home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / xwphescr.zip / XWPH0208.ZIP / src / helpers / vcard.c < prev    next >
C/C++ Source or Header  |  2002-07-28  |  26KB  |  882 lines

  1.  
  2. /*
  3.  *@@sourcefile vcard.c:
  4.  *
  5.  *      Function prefixes:
  6.  *      --  vcf*   replacement profile (INI) functions
  7.  *
  8.  *      Note: Version numbering in this file relates to XWorkplace version
  9.  *            numbering.
  10.  *
  11.  *@@header "helpers\vcard.h"
  12.  *@@added V0.9.16 (2002-02-02) [umoeller]
  13.  */
  14.  
  15. /*
  16.  *      Copyright (C) 2002 Ulrich Möller.
  17.  *      This file is part of the "XWorkplace helpers" source package.
  18.  *      This is free software; you can redistribute it and/or modify
  19.  *      it under the terms of the GNU General Public License as published
  20.  *      by the Free Software Foundation, in version 2 as it comes in the
  21.  *      "COPYING" file of the XWorkplace main distribution.
  22.  *      This program is distributed in the hope that it will be useful,
  23.  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  24.  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  25.  *      GNU General Public License for more details.
  26.  */
  27.  
  28. #define OS2EMX_PLAIN_CHAR
  29.     // this is needed for "os2emx.h"; if this is defined,
  30.     // emx will define PSZ as _signed_ char, otherwise
  31.     // as unsigned char
  32.  
  33. #define INCL_DOSNLS
  34. #define INCL_DOSERRORS
  35. #define INCL_WINCOUNTRY
  36. #include <os2.h>
  37.  
  38. #include <stdlib.h>
  39. #include <stdio.h>
  40. #include <string.h>
  41.  
  42. #include "setup.h"                      // code generation and debugging options
  43.  
  44. #include "helpers\dosh.h"
  45. #include "helpers\linklist.h"
  46. #include "helpers\nls.h"
  47. #include "helpers\standards.h"
  48. #include "helpers\stringh.h"
  49. #include "helpers\xstring.h"
  50.  
  51. #define INCLUDE_VCARD_PRIVATE
  52. #define INCLUDE_VCARD_ALL
  53. #include "helpers\vcard.h"
  54.  
  55. #pragma hdrstop
  56.  
  57. /*
  58.  *@@category: Helpers\vCard parser
  59.  *      See vcard.c.
  60.  */
  61.  
  62. /* ******************************************************************
  63.  *
  64.  *   Private declarations
  65.  *
  66.  ********************************************************************/
  67.  
  68. static VOID FreeList(PLINKLIST *ppll);
  69.  
  70. /* ******************************************************************
  71.  *
  72.  *   vCard parser
  73.  *
  74.  ********************************************************************/
  75.  
  76. /*
  77.  *@@ Translate:
  78.  *
  79.  */
  80.  
  81. static VOID Translate(PXSTRING pstr,
  82.                       ULONG cpCurrent)
  83. {
  84.     ULONG ul;
  85.  
  86.     // there may be MIME-encoded strings in here
  87.     xstrDecode2(pstr, '=');
  88.  
  89.     for (ul = 0;
  90.          ul < pstr->ulLength;
  91.          ul++)
  92.     {
  93.         PSZ pc;
  94.  
  95.         if (*(pc = &pstr->psz[ul]) > 127)
  96.             *pc = WinCpTranslateChar(0,
  97.                                      1004,
  98.                                      *pc,
  99.                                      cpCurrent);
  100.     }
  101. }
  102.  
  103. /*
  104.  *@@ DecodeStringList:
  105.  *
  106.  *@@added V0.9.16 (2002-02-02) [umoeller]
  107.  */
  108.  
  109. static APIRET DecodeStringList(PCSZ pStart,
  110.                                PCSZ pEnd,
  111.                                PXSTRING *ppaStrings,
  112.                                PULONG pcStrings,
  113.                                PXSTRING *ppstrLast,        // out: last string stored
  114.                                ULONG cpCurrent)            // in: current codepage
  115. {
  116.     if (!pStart || !pEnd)
  117.         return ERROR_BAD_FORMAT;
  118.  
  119.     while (pStart)
  120.     {
  121.         PCSZ pNext;
  122.  
  123.         // we can have several parameters:
  124.         // PHOTO;VALUE=URL;TYPE=GIF:http://www.abc.com/dir_photos/my_photo.gif
  125.         // so find end of this param
  126.         PCSZ pEndOfParam;
  127.         if (pNext = strchr(pStart + 1, ';'))
  128.             pEndOfParam = pNext;
  129.         else
  130.             pEndOfParam = pEnd;
  131.  
  132.         (*pcStrings)++;
  133.  
  134.         // append a new XSTRING to the array
  135.         if (*ppaStrings = (PXSTRING)realloc(*ppaStrings,      // NULL on first call
  136.                                             *pcStrings * sizeof(XSTRING)))
  137.         {
  138.             PXSTRING paStrings = *ppaStrings;
  139.             PXSTRING pstrParamThis = &paStrings[(*pcStrings) - 1];
  140.             ULONG cb;
  141.  
  142.             xstrInit(pstrParamThis, 0);
  143.  
  144.             if (cb = pEndOfParam - pStart - 1)
  145.             {
  146.                 if (    (cb > 6)
  147.                      && (!memcmp(pStart + 1, "TYPE=", 5))
  148.                    )
  149.                     xstrcpy(pstrParamThis,
  150.                             pStart + 6,
  151.                             // up to colon
  152.                             cb - 5);
  153.                 else
  154.                     xstrcpy(pstrParamThis,
  155.                             pStart + 1,
  156.                             // up to colon
  157.                             cb);
  158.  
  159.                 Translate(pstrParamThis,
  160.                           cpCurrent);
  161.             }
  162.  
  163.             if (ppstrLast)
  164.                 // caller wants last string used:
  165.                 *ppstrLast = pstrParamThis;
  166.         }
  167.         else
  168.             return ERROR_NOT_ENOUGH_MEMORY;
  169.  
  170.         pStart = pNext;
  171.     }
  172.  
  173.     return NO_ERROR;
  174. }
  175.  
  176. /*
  177.  *@@ Tokenize:
  178.  *
  179.  *      A property is the definition of an individual attribute describing
  180.  *      the vCard. A property takes the following form:
  181.  +
  182.  +          PropertyName [';' PropertyParameters] ':'  PropertyValue
  183.  +
  184.  *      as shown in the following example:
  185.  +
  186.  +          TEL;HOME:+1-919-555-1234
  187.  +
  188.  *      A property takes the form of one or more lines of text. The
  189.  *      specification of property names and property parameters is
  190.  *      case insensitive.
  191.  *
  192.  *      The property name can be one of a set of pre-defined strings.
  193.  *      The property name, along with an optional grouping label,
  194.  *      must appear as the first characters on a line.
  195.  *      In the previous example, "TEL" is the name of the Telephone
  196.  *      Number property.
  197.  *
  198.  *      Property values are specified as strings. In the previous
  199.  *      example, "+1-919-555-1234" is the formatted value for the
  200.  *      Telephone Number property.
  201.  *
  202.  *      A property value can be further qualified with a property
  203.  *      parameter expression. Property parameter expressions are
  204.  *      delimited from the property name with a semicolon.
  205.  *      A semicolon in a property parameter value must be escaped
  206.  *      with a backslash character. The property parameter expressions
  207.  *      are specified as either a name=value or a value string. The
  208.  *      value string can be specified alone in those cases where the
  209.  *      value is unambiguous. For example a complete property parameter
  210.  *      specification might be:
  211.  +
  212.  +      NOTE;ENCODING=QUOTED-PRINTABLE:Don't remember to order Girl=
  213.  +          Scout cookies from Stacey today!
  214.  +
  215.  *      A valid short version of the same property parameter
  216.  *      specification might be:
  217.  +
  218.  +      NOTE;QUOTED-PRINTABLE:Don t remember to order Girl=
  219.  +          Scout cookies from Stacey today!
  220.  *
  221.  *      Continuation across several lines is possible by starting
  222.  *      continuation lines with spaces. During parsing, any sequence
  223.  *      of CRLF followed immediately by spaces is considered a
  224.  *      continuation and will be removed in the returned value.
  225.  *
  226.  *      Standard properties:
  227.  *
  228.  *      --  FN: formatted name (what is displayed as the name).
  229.  *
  230.  *      --  N: structured name (family name;
  231.  *                              given name;
  232.  *                              addtl. names;
  233.  *                              name prefix;
  234.  *                              name suffix)
  235.  *
  236.  *          e.g.    N:Public;John;Quinlan;Mr.;Esq.
  237.  *                  N:Veni, Vidi, Vici;The Restaurant.
  238.  *
  239.  *      --  PHOTO: photo of vCard's owner
  240.  *
  241.  +              PHOTO;VALUE=URL:file:///jqpublic.gif
  242.  +
  243.  +              PHOTO;ENCODING=BASE64;TYPE=GIF:
  244.  +                  R0lGODdhfgA4AOYAAAAAAK+vr62trVIxa6WlpZ+fnzEpCEpzlAha/0Kc74+PjyGM
  245.  +                  SuecKRhrtX9/fzExORBSjCEYCGtra2NjYyF7nDGE50JrhAg51qWtOTl7vee1MWu1
  246.  +                  50o5e3PO/3sxcwAx/4R7GBgQOcDAwFoAQt61hJyMGHuUSpRKIf8A/wAY54yMjHtz
  247.  *
  248.  *      --  BDAY: birthday
  249.  +
  250.  +              BDAY:19950415
  251.  +
  252.  +              BDAY:1995-04-15
  253.  *
  254.  *      --  ADR: delivery address (compound: Post Office Address;
  255.  *                                           Extended Address;
  256.  *                                           Street;
  257.  *                                           Locality;
  258.  *                                           Region;
  259.  *                                           Postal Code;
  260.  *                                           Country)
  261.  +
  262.  +              ADR;DOM;HOME:P.O. Box 101;Suite 101;123 Main Street;Any Town;CA;91921-1234;
  263.  *
  264.  *      --  LABEL: delivery label (formatted)
  265.  *
  266.  *      --  TEL: telephone
  267.  *
  268.  *      --  EMAIL
  269.  *
  270.  *      --  MAILER: email software used by individual
  271.  *
  272.  *      --  TZ: timezone
  273.  *
  274.  *      --  GEO: geographic position
  275.  *
  276.  *      --  TITLE: job title etc.
  277.  *
  278.  *      --  ROLE: business role
  279.  *
  280.  *      --  LOGO: company logo or something
  281.  *
  282.  *      --  ORG: organization name
  283.  *
  284.  *      --  NOTE: a comment
  285.  *
  286.  *      --  REV: when vCard was last modified
  287.  *
  288.  *      --  SOUND: sound data
  289.  *
  290.  *      --  URL: where to find up-to-date information
  291.  *
  292.  *      --  UID: unique vCard identifier
  293.  *
  294.  *      --  VERSION: vCard version info (2.1)
  295.  *
  296.  *      --  KEY: public key
  297.  *
  298.  *      --  X-*: extension
  299.  */
  300.  
  301. static APIRET Tokenize(ULONG ulLevel,
  302.                        PSZ *ppszInput,
  303.                        PLINKLIST pllParent,
  304.                        ULONG cpCurrent)
  305. {
  306.     PSZ         pLineThis = *ppszInput;
  307.     ULONG       cbPropertyName;
  308.     APIRET      arc = NO_ERROR;
  309.     ULONG       ul = 0;
  310.     PXSTRING    pstrPrevValue = NULL;
  311.  
  312.     PVCFPROPERTY pPrevProp = NULL;
  313.  
  314.     if (    (!ppszInput)
  315.          || (!(*ppszInput))
  316.          || (!pllParent)
  317.        )
  318.         return (ERROR_INVALID_PARAMETER);
  319.  
  320.     while (!arc)
  321.     {
  322.         PSZ     pNextEOL = strhFindEOL(pLineThis, NULL);    // never NULL
  323.  
  324.         if (*pLineThis == ' ')
  325.         {
  326.             // continuation from previous line:
  327.             // append to previous value string, if we had one
  328.             if (!pstrPrevValue)
  329.             {
  330.                 arc = ERROR_BAD_FORMAT;
  331.                 break;
  332.             }
  333.             else
  334.             {
  335.                 // skip the spaces
  336.                 PSZ p = pLineThis + 1;
  337.                 while (*p == ' ')
  338.                     p++;
  339.                 if (*p != '\n')
  340.                     // line not empty:
  341.                     xstrcat(pstrPrevValue,
  342.                             p - 1,      // add one space always!
  343.                             pNextEOL - p + 1);
  344.             }
  345.         }
  346.         else
  347.         {
  348.             PSZ pNextColon;
  349.             if (!(pNextColon = strchr(pLineThis, ':')))
  350.             {
  351.                 arc = ERROR_BAD_FORMAT;
  352.                 break;
  353.             }
  354.  
  355.             if (    (pNextColon < pNextEOL)
  356.                  && (*pLineThis != '\n')       // not empty line
  357.                )
  358.             {
  359.                 // ADR;DOM;HOME:P.O. Box 101;Suite 101;123 Main Street;Any Town;CA;91921-1234;
  360.                 // colon before EOL: then we have at least a value
  361.                 PSZ     pNextSemicolon;
  362.                 ULONG   cbPropertyNameThis,
  363.                         cbLineThis = pNextEOL - pLineThis;
  364.                 PVCFPROPERTY pProp;
  365.  
  366.                 *pNextColon = '\0';
  367.                 nlsUpper(pLineThis);
  368.  
  369.                 if (pNextSemicolon = strchr(pLineThis, ';'))
  370.                     // we have a parameter:
  371.                     cbPropertyNameThis = pNextSemicolon - pLineThis;
  372.                 else
  373.                     cbPropertyNameThis = pNextColon - pLineThis;
  374.  
  375.                 // special properties:
  376.                 if (!strcmp(pLineThis, "BEGIN"))
  377.                 {
  378.                     // begin of vCard object:
  379.                     // this is either the root object or a nested one;
  380.                     // in any case, recurse!
  381.                     if (    (*pNextEOL)
  382.                          && (pPrevProp)
  383.                        )
  384.                     {
  385.                         PSZ pszSubInput = pNextEOL + 1;
  386.                         pPrevProp->pllSubList = lstCreate(FALSE);
  387.                         if (!(arc = Tokenize(ulLevel + 1,
  388.                                              &pszSubInput,
  389.                                              pPrevProp->pllSubList,
  390.                                              cpCurrent)))
  391.                         {
  392.                             // continue after this chunk
  393.                             // (pszSubinput points to after end:vcard now)
  394.                             pNextEOL = pszSubInput;
  395.                         }
  396.                     }
  397.                     else
  398.                         arc = ERROR_BAD_FORMAT;
  399.  
  400.                     if (arc)
  401.                         break;
  402.  
  403.                 }
  404.                 else if (!strcmp(pLineThis, "END"))
  405.                 {
  406.                     // end of this vCard:
  407.                     // store address of end:vcard for parent call
  408.                     *ppszInput = pNextEOL;
  409.                     break;
  410.                 }
  411.                 // any other property:
  412.                 else if (pProp = NEW(VCFPROPERTY))
  413.                 {
  414.                     CHAR cSaved2;
  415.  
  416.                     ZERO(pProp);
  417.  
  418.                     // 1) store property name
  419.                     xstrInit(&pProp->strProperty, 0);
  420.                     xstrcpy(&pProp->strProperty,
  421.                             pLineThis,
  422.                             cbPropertyNameThis);
  423.  
  424.                     // 2) store parameters
  425.                     DecodeStringList(pNextSemicolon,
  426.                                      pNextColon,
  427.                                      &pProp->pastrParameters,
  428.                                      &pProp->cParameters,
  429.                                      NULL,
  430.                                      cpCurrent);
  431.  
  432.                     // 3) store values
  433.                     cSaved2 = *pNextEOL;
  434.                     *pNextEOL = '\0';
  435.                     DecodeStringList(pNextColon,
  436.                                      pNextEOL,
  437.                                      &pProp->pastrValues,
  438.                                      &pProp->cValues,
  439.                                      &pstrPrevValue,        // for line continuations
  440.                                      cpCurrent);
  441.                     *pNextEOL = cSaved2;
  442.  
  443.                     // add the property to the parent's list
  444.                     lstAppendItem(pllParent,
  445.                                   pProp);
  446.  
  447.                     // store the prop for next loop in case
  448.                     // we need to recurse for nested vCards
  449.                     pPrevProp = pProp;
  450.                 }
  451.                 else
  452.                     arc = ERROR_NOT_ENOUGH_MEMORY;
  453.  
  454.                 *pNextColon = ':';
  455.             }
  456.         }
  457.  
  458.         if (!*pNextEOL)
  459.             // no more lines:
  460.             break;
  461.  
  462.         pLineThis = pNextEOL + 1;
  463.     }
  464.  
  465.     _Pmpf((__FUNCTION__ ": returning %d", arc));
  466.  
  467.     return arc;
  468. }
  469.  
  470. /*
  471.  *@@ FindValues:
  472.  *
  473.  */
  474.  
  475. static PVCFPROPERTY FindValues(PLINKLIST pll,
  476.                                PCSZ pcszProperty,
  477.                                PCSZ pcszParameter)
  478. {
  479.     PLISTNODE   pNode;
  480.  
  481.     for (pNode = lstQueryFirstNode(pll);
  482.          pNode;
  483.          pNode = pNode->pNext)
  484.     {
  485.         PVCFPROPERTY pProp = (PVCFPROPERTY)pNode->pItemData;
  486.  
  487.         if (!strcmp(pProp->strProperty.psz, pcszProperty))
  488.         {
  489.             if (!pcszParameter)     // or parameter matches @@todo
  490.             {
  491.                 return pProp;
  492.             }
  493.         }
  494.     }
  495.  
  496.     return NULL;
  497. }
  498.  
  499. /*
  500.  *@@ CopyStrings:
  501.  *
  502.  */
  503.  
  504. static VOID CopyStrings(PVCFPROPERTY pProp,
  505.                         PCSZ *papcszValues,
  506.                         ULONG cValues)
  507. {
  508.     ULONG ul;
  509.  
  510.     memset(papcszValues, 0, sizeof(PSZ) * cValues);
  511.  
  512.     if (pProp)
  513.     {
  514.         if (cValues > pProp->cValues)
  515.             cValues = pProp->cValues;
  516.  
  517.         for (ul = 0;
  518.              ul < cValues;
  519.              ul++)
  520.         {
  521.             papcszValues[ul] = pProp->pastrValues[ul].psz;
  522.         }
  523.     }
  524. }
  525.  
  526. /*
  527.  *@@ GetFlagStrings:
  528.  *
  529.  *      My application to the "obfuscated C contest".
  530.  */
  531.  
  532. static ULONG GetFlagStrings(PXSTRING pastrParameters,
  533.                             ULONG cParameters,
  534.                             const PCSZ **apcsz,
  535.                             const ULONG *afl,
  536.                             ULONG cStrings,
  537.                             ULONG flDefault)
  538. {
  539.     ULONG ul, ul2;
  540.     ULONG fl = 0;
  541.     if (!cParameters)
  542.         fl = flDefault;
  543.     else for (ul = 0;
  544.               ul < cParameters;
  545.               ul++)
  546.     {
  547.         PCSZ pcszThis = pastrParameters[ul].psz;
  548.         for (ul2 = 0;
  549.              ul2 < cStrings;
  550.              ul2++)
  551.         {
  552.             if (!strcmp(pcszThis, *apcsz[ul2]))
  553.                 fl |= afl[ul2];
  554.         }
  555.     }
  556.  
  557.     return fl;
  558. }
  559.  
  560. static const PCSZ *apcszAddress[] =
  561.     {
  562.         &VCF_TYPE_ADR_DOM,
  563.         &VCF_TYPE_ADR_INTL,
  564.         &VCF_TYPE_ADR_POSTAL,
  565.         &VCF_TYPE_ADR_PARCEL,
  566.         &VCF_TYPE_ADR_HOME,
  567.         &VCF_TYPE_ADR_WORK
  568.     };
  569.  
  570. static const ULONG aflAddress[] =
  571.     {
  572.         VCF_ADDRFL_DOM,
  573.         VCF_ADDRFL_INTL,
  574.         VCF_ADDRFL_POSTAL,
  575.         VCF_ADDRFL_PARCEL,
  576.         VCF_ADDRFL_HOME,
  577.         VCF_ADDRFL_WORK
  578.     };
  579.  
  580. /*
  581.  *@@ AppendAddress:
  582.  *
  583.  */
  584.  
  585. static VOID AppendAddress(PVCARD pvc,
  586.                           PVCFPROPERTY pProp)
  587. {
  588.     if (pvc->paDeliveryAddresses = (PVCADDRESS)realloc(
  589.                                 pvc->paDeliveryAddresses,
  590.                                 (pvc->cDeliveryAddresses + 1) * sizeof(VCADDRESS)))
  591.     {
  592.         PVCADDRESS pThis = &pvc->paDeliveryAddresses[(pvc->cDeliveryAddresses)++];
  593.  
  594.         CopyStrings(pProp,
  595.                     pThis->apcszAddress,
  596.                     7);
  597.         pThis->fl = GetFlagStrings(pProp->pastrParameters,
  598.                                    pProp->cParameters,
  599.                                    apcszAddress,
  600.                                    aflAddress,
  601.                                    ARRAYITEMCOUNT(apcszAddress),
  602.                                    VCF_ADDRFL_INTL | VCF_ADDRFL_WORK
  603.                                         | VCF_ADDRFL_POSTAL | VCF_ADDRFL_PARCEL);
  604.     }
  605. }
  606.  
  607. /*
  608.  *@@ AppendLabel:
  609.  *
  610.  */
  611.  
  612. static VOID AppendLabel(PVCARD pvc,
  613.                         PVCFPROPERTY pProp)
  614. {
  615.     if (pvc->paLabels = (PVCLABEL)realloc(
  616.                                 pvc->paLabels,
  617.                                 (pvc->cLabels + 1) * sizeof(VCLABEL)))
  618.     {
  619.         PVCLABEL pThis = &pvc->paLabels[(pvc->cLabels)++];
  620.  
  621.         CopyStrings(pProp,
  622.                     &pThis->pcszLabel,
  623.                     1);
  624.         pThis->fl = GetFlagStrings(pProp->pastrParameters,
  625.                                    pProp->cParameters,
  626.                                    apcszAddress,
  627.                                    aflAddress,
  628.                                    ARRAYITEMCOUNT(apcszAddress),
  629.                                    VCF_ADDRFL_INTL | VCF_ADDRFL_WORK
  630.                                         | VCF_ADDRFL_POSTAL | VCF_ADDRFL_PARCEL);
  631.     }
  632. }
  633.  
  634. static const PCSZ *apcszPhone[] =
  635.     {
  636.         &VCF_TYPE_TEL_PREF,
  637.         &VCF_TYPE_TEL_WORK,
  638.         &VCF_TYPE_TEL_HOME,
  639.         &VCF_TYPE_TEL_VOICE,
  640.         &VCF_TYPE_TEL_FAX,
  641.         &VCF_TYPE_TEL_MSG,
  642.         &VCF_TYPE_TEL_CELL,
  643.         &VCF_TYPE_TEL_PAGER,
  644.         &VCF_TYPE_TEL_BBS,
  645.         &VCF_TYPE_TEL_MODEM,
  646.         &VCF_TYPE_TEL_CAR,
  647.         &VCF_TYPE_TEL_ISDN,
  648.         &VCF_TYPE_TEL_VIDEO
  649.     };
  650.  
  651. static const ULONG aflPhone[] =
  652.     {
  653.         VCF_PHONEFL_PREF,
  654.         VCF_PHONEFL_WORK,
  655.         VCF_PHONEFL_HOME,
  656.         VCF_PHONEFL_VOICE,
  657.         VCF_PHONEFL_FAX,
  658.         VCF_PHONEFL_MSG,
  659.         VCF_PHONEFL_CELL,
  660.         VCF_PHONEFL_PAGER,
  661.         VCF_PHONEFL_BBS,
  662.         VCF_PHONEFL_MODEM,
  663.         VCF_PHONEFL_CAR,
  664.         VCF_PHONEFL_ISDN,
  665.         VCF_PHONEFL_VIDEO
  666.     };
  667.  
  668. /*
  669.  *@@ AppendTel:
  670.  *
  671.  */
  672.  
  673. static VOID AppendTel(PVCARD pvc,
  674.                       PVCFPROPERTY pProp)
  675. {
  676.     if (pvc->paPhones = (PVCPHONE)realloc(pvc->paPhones,
  677.                                           (pvc->cPhones + 1) * sizeof(VCPHONE)))
  678.     {
  679.         ULONG ul;
  680.         PVCPHONE pThis = &pvc->paPhones[(pvc->cPhones)++];
  681.  
  682.         CopyStrings(pProp,
  683.                     &pThis->pcszNumber,
  684.                     1);
  685.  
  686.         pThis->fl = GetFlagStrings(pProp->pastrParameters,
  687.                                    pProp->cParameters,
  688.                                    apcszPhone,
  689.                                    aflPhone,
  690.                                    ARRAYITEMCOUNT(apcszPhone),
  691.                                    VCF_PHONEFL_VOICE);
  692.     }
  693. }
  694.  
  695. /*
  696.  *@@ vcfRead:
  697.  *
  698.  */
  699.  
  700. APIRET vcfRead(PCSZ pcszFilename,
  701.                PVCARD *ppvCard)         // out: vCard handle
  702. {
  703.     APIRET  arc;
  704.     PSZ     pszData = NULL;
  705.     ULONG   cbRead;
  706.     if (!(arc = doshLoadTextFile(pcszFilename,
  707.                                  &pszData,
  708.                                  &cbRead)))
  709.     {
  710.         XSTRING str;
  711.         PSZ p;
  712.  
  713.         COUNTRYCODE cc = {0};
  714.         COUNTRYINFO ci = {0};
  715.         ULONG cb;
  716.  
  717.         DosQueryCtryInfo(sizeof(ci),
  718.                          &cc,
  719.                          &ci,
  720.                          &cb);
  721.  
  722.         xstrInitSet2(&str, pszData, cbRead - 1);
  723.         xstrConvertLineFormat(&str, CRLF2LF);
  724.  
  725.         if (    (p = strhistr(str.psz, "BEGIN:VCARD"))
  726.              && (p = strhFindEOL(p, NULL))
  727.            )
  728.         {
  729.             PLINKLIST pll = lstCreate(FALSE);
  730.             if (!(arc = Tokenize(0,
  731.                                  &p,
  732.                                  pll,
  733.                                  ci.codepage)))
  734.             {
  735.                 PVCARD pvc;
  736.                 if (!(pvc = NEW(VCARD)))
  737.                     arc = ERROR_NOT_ENOUGH_MEMORY;
  738.                 else
  739.                 {
  740.                     PVCFPROPERTY pProp;
  741.                     PLISTNODE pNode;
  742.  
  743.                     ZERO(pvc);
  744.  
  745.  
  746.                     pvc->pll = pll;
  747.  
  748.                     // now go set up the data fields
  749.                     if (pProp = FindValues(pll,
  750.                                            VCFPROP_FN,
  751.                                            NULL))
  752.                         CopyStrings(pProp,
  753.                                     &pvc->pcszFormattedName,
  754.                                     1);
  755.  
  756.                     if (pProp = FindValues(pll,
  757.                                            VCFPROP_N,
  758.                                            NULL))
  759.                         CopyStrings(pProp,
  760.                                     pvc->apcszName,
  761.                                     5);
  762.  
  763.                     if (pProp = FindValues(pll,
  764.                                            VCFPROP_EMAIL,
  765.                                            NULL))
  766.                         CopyStrings(pProp,
  767.                                     &pvc->pcszEmail,
  768.                                     1);
  769.  
  770.                     if (pProp = FindValues(pll,
  771.                                            VCFPROP_TITLE,
  772.                                            NULL))
  773.                         CopyStrings(pProp,
  774.                                     &pvc->pcszJobTitle,
  775.                                     1);
  776.  
  777.                     for (pNode = lstQueryFirstNode(pll);
  778.                          pNode;
  779.                          pNode = pNode->pNext)
  780.                     {
  781.                         pProp = (PVCFPROPERTY)pNode->pItemData;
  782.  
  783.                         if (!strcmp(pProp->strProperty.psz, VCFPROP_ADR))
  784.                             AppendAddress(pvc,
  785.                                           pProp);
  786.                         else if (!strcmp(pProp->strProperty.psz, VCFPROP_LABEL))
  787.                             AppendLabel(pvc,
  788.                                         pProp);
  789.                         else if (!strcmp(pProp->strProperty.psz, VCFPROP_TEL))
  790.                             AppendTel(pvc,
  791.                                       pProp);
  792.                     }
  793.  
  794.                     *ppvCard = pvc;
  795.                 }
  796.             }
  797.  
  798.             if (arc)
  799.                 FreeList(&pll);
  800.         }
  801.         else
  802.             arc = ERROR_BAD_FORMAT;
  803.  
  804.         xstrClear(&str);
  805.     }
  806.  
  807.     _Pmpf((__FUNCTION__ ": returning %d", arc));
  808.  
  809.     return arc;
  810. }
  811.  
  812. /*
  813.  *@@ FreeList:
  814.  *
  815.  */
  816.  
  817. static VOID FreeList(PLINKLIST *ppll)
  818. {
  819.     PLISTNODE pNode = lstQueryFirstNode(*ppll);
  820.     while (pNode)
  821.     {
  822.         PVCFPROPERTY pProp = (PVCFPROPERTY)pNode->pItemData;
  823.         ULONG ul;
  824.  
  825.         xstrClear(&pProp->strProperty);
  826.  
  827.         if (pProp->pllSubList)
  828.             FreeList(&pProp->pllSubList);
  829.  
  830.         if (pProp->pastrParameters)
  831.         {
  832.             for (ul = 0;
  833.                  ul < pProp->cParameters;
  834.                  ul++)
  835.                 xstrClear(&pProp->pastrParameters[ul]);
  836.  
  837.             free(pProp->pastrParameters);
  838.         }
  839.  
  840.         if (pProp->pastrValues)
  841.         {
  842.             for (ul = 0;
  843.                  ul < pProp->cValues;
  844.                  ul++)
  845.                 xstrClear(&pProp->pastrValues[ul]);
  846.  
  847.             free(pProp->pastrValues);
  848.         }
  849.  
  850.         pNode = pNode->pNext;
  851.     }
  852.  
  853.     lstFree(ppll);
  854. }
  855.  
  856. /*
  857.  *@@ vcfFree:
  858.  *
  859.  */
  860.  
  861. APIRET vcfFree(PVCARD *ppvCard)
  862. {
  863.     PVCARD pvc;
  864.     if (    (!ppvCard)
  865.          || (!(pvc = *ppvCard))
  866.        )
  867.         return ERROR_INVALID_PARAMETER;
  868.     else
  869.     {
  870.         FREE(pvc->paDeliveryAddresses);
  871.  
  872.         FreeList(&pvc->pll);
  873.  
  874.         free(pvc);
  875.         *ppvCard = NULL;
  876.     }
  877.  
  878.     return NO_ERROR;
  879. }
  880.  
  881.  
  882.