source: branches/branch-1-0/src/helpers/vcard.c@ 302

Last change on this file since 302 was 226, checked in by umoeller, 23 years ago

Map file parser.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 25.2 KB
Line 
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
68STATIC VOID FreeList(PLINKLIST *ppll);
69
70/* ******************************************************************
71 *
72 * vCard parser
73 *
74 ********************************************************************/
75
76/*
77 *@@ Translate:
78 *
79 */
80
81STATIC 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
109STATIC 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
301STATIC 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 return arc;
466}
467
468/*
469 *@@ FindValues:
470 *
471 */
472
473STATIC PVCFPROPERTY FindValues(PLINKLIST pll,
474 PCSZ pcszProperty,
475 PCSZ pcszParameter)
476{
477 PLISTNODE pNode;
478
479 for (pNode = lstQueryFirstNode(pll);
480 pNode;
481 pNode = pNode->pNext)
482 {
483 PVCFPROPERTY pProp = (PVCFPROPERTY)pNode->pItemData;
484
485 if (!strcmp(pProp->strProperty.psz, pcszProperty))
486 {
487 if (!pcszParameter) // or parameter matches @@todo
488 {
489 return pProp;
490 }
491 }
492 }
493
494 return NULL;
495}
496
497/*
498 *@@ CopyStrings:
499 *
500 */
501
502STATIC VOID CopyStrings(PVCFPROPERTY pProp,
503 PCSZ *papcszValues,
504 ULONG cValues)
505{
506 ULONG ul;
507
508 memset(papcszValues, 0, sizeof(PSZ) * cValues);
509
510 if (pProp)
511 {
512 if (cValues > pProp->cValues)
513 cValues = pProp->cValues;
514
515 for (ul = 0;
516 ul < cValues;
517 ul++)
518 {
519 papcszValues[ul] = pProp->pastrValues[ul].psz;
520 }
521 }
522}
523
524/*
525 *@@ GetFlagStrings:
526 *
527 * My application to the "obfuscated C contest".
528 */
529
530STATIC ULONG GetFlagStrings(PXSTRING pastrParameters,
531 ULONG cParameters,
532 const PCSZ **apcsz,
533 const ULONG *afl,
534 ULONG cStrings,
535 ULONG flDefault)
536{
537 ULONG ul, ul2;
538 ULONG fl = 0;
539 if (!cParameters)
540 fl = flDefault;
541 else for (ul = 0;
542 ul < cParameters;
543 ul++)
544 {
545 PCSZ pcszThis = pastrParameters[ul].psz;
546 for (ul2 = 0;
547 ul2 < cStrings;
548 ul2++)
549 {
550 if (!strcmp(pcszThis, *apcsz[ul2]))
551 fl |= afl[ul2];
552 }
553 }
554
555 return fl;
556}
557
558STATIC const PCSZ *apcszAddress[] =
559 {
560 &VCF_TYPE_ADR_DOM,
561 &VCF_TYPE_ADR_INTL,
562 &VCF_TYPE_ADR_POSTAL,
563 &VCF_TYPE_ADR_PARCEL,
564 &VCF_TYPE_ADR_HOME,
565 &VCF_TYPE_ADR_WORK
566 };
567
568STATIC const ULONG aflAddress[] =
569 {
570 VCF_ADDRFL_DOM,
571 VCF_ADDRFL_INTL,
572 VCF_ADDRFL_POSTAL,
573 VCF_ADDRFL_PARCEL,
574 VCF_ADDRFL_HOME,
575 VCF_ADDRFL_WORK
576 };
577
578/*
579 *@@ AppendAddress:
580 *
581 */
582
583STATIC VOID AppendAddress(PVCARD pvc,
584 PVCFPROPERTY pProp)
585{
586 if (pvc->paDeliveryAddresses = (PVCADDRESS)realloc(
587 pvc->paDeliveryAddresses,
588 (pvc->cDeliveryAddresses + 1) * sizeof(VCADDRESS)))
589 {
590 PVCADDRESS pThis = &pvc->paDeliveryAddresses[(pvc->cDeliveryAddresses)++];
591
592 CopyStrings(pProp,
593 pThis->apcszAddress,
594 7);
595 pThis->fl = GetFlagStrings(pProp->pastrParameters,
596 pProp->cParameters,
597 apcszAddress,
598 aflAddress,
599 ARRAYITEMCOUNT(apcszAddress),
600 VCF_ADDRFL_INTL | VCF_ADDRFL_WORK
601 | VCF_ADDRFL_POSTAL | VCF_ADDRFL_PARCEL);
602 }
603}
604
605/*
606 *@@ AppendLabel:
607 *
608 */
609
610STATIC VOID AppendLabel(PVCARD pvc,
611 PVCFPROPERTY pProp)
612{
613 if (pvc->paLabels = (PVCLABEL)realloc(
614 pvc->paLabels,
615 (pvc->cLabels + 1) * sizeof(VCLABEL)))
616 {
617 PVCLABEL pThis = &pvc->paLabels[(pvc->cLabels)++];
618
619 CopyStrings(pProp,
620 &pThis->pcszLabel,
621 1);
622 pThis->fl = GetFlagStrings(pProp->pastrParameters,
623 pProp->cParameters,
624 apcszAddress,
625 aflAddress,
626 ARRAYITEMCOUNT(apcszAddress),
627 VCF_ADDRFL_INTL | VCF_ADDRFL_WORK
628 | VCF_ADDRFL_POSTAL | VCF_ADDRFL_PARCEL);
629 }
630}
631
632STATIC const PCSZ *apcszPhone[] =
633 {
634 &VCF_TYPE_TEL_PREF,
635 &VCF_TYPE_TEL_WORK,
636 &VCF_TYPE_TEL_HOME,
637 &VCF_TYPE_TEL_VOICE,
638 &VCF_TYPE_TEL_FAX,
639 &VCF_TYPE_TEL_MSG,
640 &VCF_TYPE_TEL_CELL,
641 &VCF_TYPE_TEL_PAGER,
642 &VCF_TYPE_TEL_BBS,
643 &VCF_TYPE_TEL_MODEM,
644 &VCF_TYPE_TEL_CAR,
645 &VCF_TYPE_TEL_ISDN,
646 &VCF_TYPE_TEL_VIDEO
647 };
648
649STATIC const ULONG aflPhone[] =
650 {
651 VCF_PHONEFL_PREF,
652 VCF_PHONEFL_WORK,
653 VCF_PHONEFL_HOME,
654 VCF_PHONEFL_VOICE,
655 VCF_PHONEFL_FAX,
656 VCF_PHONEFL_MSG,
657 VCF_PHONEFL_CELL,
658 VCF_PHONEFL_PAGER,
659 VCF_PHONEFL_BBS,
660 VCF_PHONEFL_MODEM,
661 VCF_PHONEFL_CAR,
662 VCF_PHONEFL_ISDN,
663 VCF_PHONEFL_VIDEO
664 };
665
666/*
667 *@@ AppendTel:
668 *
669 */
670
671STATIC VOID AppendTel(PVCARD pvc,
672 PVCFPROPERTY pProp)
673{
674 if (pvc->paPhones = (PVCPHONE)realloc(pvc->paPhones,
675 (pvc->cPhones + 1) * sizeof(VCPHONE)))
676 {
677 ULONG ul;
678 PVCPHONE pThis = &pvc->paPhones[(pvc->cPhones)++];
679
680 CopyStrings(pProp,
681 &pThis->pcszNumber,
682 1);
683
684 pThis->fl = GetFlagStrings(pProp->pastrParameters,
685 pProp->cParameters,
686 apcszPhone,
687 aflPhone,
688 ARRAYITEMCOUNT(apcszPhone),
689 VCF_PHONEFL_VOICE);
690 }
691}
692
693/*
694 *@@ vcfRead:
695 *
696 */
697
698APIRET vcfRead(PCSZ pcszFilename,
699 PVCARD *ppvCard) // out: vCard handle
700{
701 APIRET arc;
702 PSZ pszData = NULL;
703 ULONG cbRead;
704 if (!(arc = doshLoadTextFile(pcszFilename,
705 &pszData,
706 &cbRead)))
707 {
708 XSTRING str;
709 PSZ p;
710
711 COUNTRYCODE cc = {0};
712 COUNTRYINFO ci = {0};
713 ULONG cb;
714
715 DosQueryCtryInfo(sizeof(ci),
716 &cc,
717 &ci,
718 &cb);
719
720 xstrInitSet2(&str, pszData, cbRead - 1);
721 xstrConvertLineFormat(&str, CRLF2LF);
722
723 if ( (p = strhistr(str.psz, "BEGIN:VCARD"))
724 && (p = strhFindEOL(p, NULL))
725 )
726 {
727 PLINKLIST pll = lstCreate(FALSE);
728 if (!(arc = Tokenize(0,
729 &p,
730 pll,
731 ci.codepage)))
732 {
733 PVCARD pvc;
734 if (!(pvc = NEW(VCARD)))
735 arc = ERROR_NOT_ENOUGH_MEMORY;
736 else
737 {
738 PVCFPROPERTY pProp;
739 PLISTNODE pNode;
740
741 ZERO(pvc);
742
743
744 pvc->pll = pll;
745
746 // now go set up the data fields
747 if (pProp = FindValues(pll,
748 VCFPROP_FN,
749 NULL))
750 CopyStrings(pProp,
751 &pvc->pcszFormattedName,
752 1);
753
754 if (pProp = FindValues(pll,
755 VCFPROP_N,
756 NULL))
757 CopyStrings(pProp,
758 pvc->apcszName,
759 5);
760
761 if (pProp = FindValues(pll,
762 VCFPROP_EMAIL,
763 NULL))
764 CopyStrings(pProp,
765 &pvc->pcszEmail,
766 1);
767
768 if (pProp = FindValues(pll,
769 VCFPROP_TITLE,
770 NULL))
771 CopyStrings(pProp,
772 &pvc->pcszJobTitle,
773 1);
774
775 for (pNode = lstQueryFirstNode(pll);
776 pNode;
777 pNode = pNode->pNext)
778 {
779 pProp = (PVCFPROPERTY)pNode->pItemData;
780
781 if (!strcmp(pProp->strProperty.psz, VCFPROP_ADR))
782 AppendAddress(pvc,
783 pProp);
784 else if (!strcmp(pProp->strProperty.psz, VCFPROP_LABEL))
785 AppendLabel(pvc,
786 pProp);
787 else if (!strcmp(pProp->strProperty.psz, VCFPROP_TEL))
788 AppendTel(pvc,
789 pProp);
790 }
791
792 *ppvCard = pvc;
793 }
794 }
795
796 if (arc)
797 FreeList(&pll);
798 }
799 else
800 arc = ERROR_BAD_FORMAT;
801
802 xstrClear(&str);
803 }
804
805 return arc;
806}
807
808/*
809 *@@ FreeList:
810 *
811 */
812
813STATIC VOID FreeList(PLINKLIST *ppll)
814{
815 PLISTNODE pNode = lstQueryFirstNode(*ppll);
816 while (pNode)
817 {
818 PVCFPROPERTY pProp = (PVCFPROPERTY)pNode->pItemData;
819 ULONG ul;
820
821 xstrClear(&pProp->strProperty);
822
823 if (pProp->pllSubList)
824 FreeList(&pProp->pllSubList);
825
826 if (pProp->pastrParameters)
827 {
828 for (ul = 0;
829 ul < pProp->cParameters;
830 ul++)
831 xstrClear(&pProp->pastrParameters[ul]);
832
833 free(pProp->pastrParameters);
834 }
835
836 if (pProp->pastrValues)
837 {
838 for (ul = 0;
839 ul < pProp->cValues;
840 ul++)
841 xstrClear(&pProp->pastrValues[ul]);
842
843 free(pProp->pastrValues);
844 }
845
846 pNode = pNode->pNext;
847 }
848
849 lstFree(ppll);
850}
851
852/*
853 *@@ vcfFree:
854 *
855 */
856
857APIRET vcfFree(PVCARD *ppvCard)
858{
859 PVCARD pvc;
860 if ( (!ppvCard)
861 || (!(pvc = *ppvCard))
862 )
863 return ERROR_INVALID_PARAMETER;
864 else
865 {
866 FREE(pvc->paDeliveryAddresses);
867
868 FreeList(&pvc->pll);
869
870 free(pvc);
871 *ppvCard = NULL;
872 }
873
874 return NO_ERROR;
875}
876
877
Note: See TracBrowser for help on using the repository browser.