source: trunk/src/helpers/vcard.c@ 140

Last change on this file since 140 was 139, checked in by umoeller, 24 years ago

Sources as of V0.9.16.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 25.1 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
68VOID FreeList(PLINKLIST *ppll);
69
70/* ******************************************************************
71 *
72 * vCard parser
73 *
74 ********************************************************************/
75
76/*
77 *@@ Translate:
78 *
79 */
80
81VOID 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
109APIRET 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
301APIRET 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 pNextColon - pLineThis);
369
370 if (pNextSemicolon = strchr(pLineThis, ';'))
371 // we have a parameter:
372 cbPropertyNameThis = pNextSemicolon - pLineThis;
373 else
374 cbPropertyNameThis = pNextColon - pLineThis;
375
376 // special properties:
377 if (!strcmp(pLineThis, "BEGIN"))
378 {
379 // begin of vCard object:
380 // this is either the root object or a nested one;
381 // in any case, recurse!
382 if ( (*pNextEOL)
383 && (pPrevProp)
384 )
385 {
386 PSZ pszSubInput = pNextEOL + 1;
387 pPrevProp->pllSubList = lstCreate(FALSE);
388 if (!(arc = Tokenize(ulLevel + 1,
389 &pszSubInput,
390 pPrevProp->pllSubList,
391 cpCurrent)))
392 {
393 // continue after this chunk
394 // (pszSubinput points to after end:vcard now)
395 pNextEOL = pszSubInput;
396 }
397 }
398 else
399 arc = ERROR_BAD_FORMAT;
400
401 if (arc)
402 break;
403
404 }
405 else if (!strcmp(pLineThis, "END"))
406 {
407 // end of this vCard:
408 // store address of end:vcard for parent call
409 *ppszInput = pNextEOL;
410 break;
411 }
412 // any other property:
413 else if (pProp = NEW(VCFPROPERTY))
414 {
415 CHAR cSaved2;
416
417 ZERO(pProp);
418
419 // 1) store property name
420 xstrInit(&pProp->strProperty, 0);
421 xstrcpy(&pProp->strProperty,
422 pLineThis,
423 cbPropertyNameThis);
424
425 // 2) store parameters
426 DecodeStringList(pNextSemicolon,
427 pNextColon,
428 &pProp->pastrParameters,
429 &pProp->cParameters,
430 NULL,
431 cpCurrent);
432
433 // 3) store values
434 cSaved2 = *pNextEOL;
435 *pNextEOL = '\0';
436 DecodeStringList(pNextColon,
437 pNextEOL,
438 &pProp->pastrValues,
439 &pProp->cValues,
440 &pstrPrevValue, // for line continuations
441 cpCurrent);
442 *pNextEOL = cSaved2;
443
444 // add the property to the parent's list
445 lstAppendItem(pllParent,
446 pProp);
447
448 // store the prop for next loop in case
449 // we need to recurse for nested vCards
450 pPrevProp = pProp;
451 }
452 else
453 arc = ERROR_NOT_ENOUGH_MEMORY;
454
455 *pNextColon = ':';
456 }
457 }
458
459 if (!*pNextEOL)
460 // no more lines:
461 break;
462
463 pLineThis = pNextEOL + 1;
464 }
465
466 _Pmpf((__FUNCTION__ ": returning %d", arc));
467
468 return (arc);
469}
470
471/*
472 *@@ FindValues:
473 *
474 */
475
476PVCFPROPERTY FindValues(PLINKLIST pll,
477 PCSZ pcszProperty,
478 PCSZ pcszParameter)
479{
480 PLISTNODE pNode;
481
482 for (pNode = lstQueryFirstNode(pll);
483 pNode;
484 pNode = pNode->pNext)
485 {
486 PVCFPROPERTY pProp = (PVCFPROPERTY)pNode->pItemData;
487
488 if (!strcmp(pProp->strProperty.psz, pcszProperty))
489 {
490 if (!pcszParameter) // or parameter matches @@todo
491 {
492 return pProp;
493 }
494 }
495 }
496
497 return NULL;
498}
499
500/*
501 *@@ CopyStrings:
502 *
503 */
504
505VOID CopyStrings(PVCFPROPERTY pProp,
506 PCSZ *papcszValues,
507 ULONG cValues)
508{
509 ULONG ul;
510
511 memset(papcszValues, 0, sizeof(PSZ) * cValues);
512
513 if (pProp)
514 {
515 if (cValues > pProp->cValues)
516 cValues = pProp->cValues;
517
518 for (ul = 0;
519 ul < cValues;
520 ul++)
521 {
522 papcszValues[ul] = pProp->pastrValues[ul].psz;
523 }
524 }
525}
526
527/*
528 *@@ GetFlagStrings:
529 *
530 * My application to the "obfuscated C contest".
531 */
532
533ULONG GetFlagStrings(PXSTRING pastrParameters,
534 ULONG cParameters,
535 const PCSZ **apcsz,
536 const ULONG *afl,
537 ULONG cStrings,
538 ULONG flDefault)
539{
540 ULONG ul, ul2;
541 ULONG fl = 0;
542 if (!cParameters)
543 fl = flDefault;
544 else for (ul = 0;
545 ul < cParameters;
546 ul++)
547 {
548 PCSZ pcszThis = pastrParameters[ul].psz;
549 for (ul2 = 0;
550 ul2 < cStrings;
551 ul2++)
552 {
553 if (!strcmp(pcszThis, *apcsz[ul2]))
554 fl |= afl[ul2];
555 }
556 }
557
558 return fl;
559}
560
561static const PCSZ *apcszAddress[] =
562 {
563 &VCF_TYPE_ADR_DOM,
564 &VCF_TYPE_ADR_INTL,
565 &VCF_TYPE_ADR_POSTAL,
566 &VCF_TYPE_ADR_PARCEL,
567 &VCF_TYPE_ADR_HOME,
568 &VCF_TYPE_ADR_WORK
569 };
570
571static const ULONG aflAddress[] =
572 {
573 VCF_ADDRFL_DOM,
574 VCF_ADDRFL_INTL,
575 VCF_ADDRFL_POSTAL,
576 VCF_ADDRFL_PARCEL,
577 VCF_ADDRFL_HOME,
578 VCF_ADDRFL_WORK
579 };
580
581/*
582 *@@ AppendAddress:
583 *
584 */
585
586VOID AppendAddress(PVCARD pvc,
587 PVCFPROPERTY pProp)
588{
589 if (pvc->paDeliveryAddresses = (PVCADDRESS)realloc(
590 pvc->paDeliveryAddresses,
591 (pvc->cDeliveryAddresses + 1) * sizeof(VCADDRESS)))
592 {
593 PVCADDRESS pThis = &pvc->paDeliveryAddresses[(pvc->cDeliveryAddresses)++];
594
595 CopyStrings(pProp,
596 pThis->apcszAddress,
597 7);
598 pThis->fl = GetFlagStrings(pProp->pastrParameters,
599 pProp->cParameters,
600 apcszAddress,
601 aflAddress,
602 ARRAYITEMCOUNT(apcszAddress),
603 VCF_ADDRFL_INTL | VCF_ADDRFL_WORK
604 | VCF_ADDRFL_POSTAL | VCF_ADDRFL_PARCEL);
605 }
606}
607
608/*
609 *@@ AppendLabel:
610 *
611 */
612
613VOID AppendLabel(PVCARD pvc,
614 PVCFPROPERTY pProp)
615{
616 if (pvc->paLabels = (PVCLABEL)realloc(
617 pvc->paLabels,
618 (pvc->cLabels + 1) * sizeof(VCLABEL)))
619 {
620 PVCLABEL pThis = &pvc->paLabels[(pvc->cLabels)++];
621
622 CopyStrings(pProp,
623 &pThis->pcszLabel,
624 1);
625 pThis->fl = GetFlagStrings(pProp->pastrParameters,
626 pProp->cParameters,
627 apcszAddress,
628 aflAddress,
629 ARRAYITEMCOUNT(apcszAddress),
630 VCF_ADDRFL_INTL | VCF_ADDRFL_WORK
631 | VCF_ADDRFL_POSTAL | VCF_ADDRFL_PARCEL);
632 }
633}
634
635static const PCSZ *apcszPhone[] =
636 {
637 &VCF_TYPE_TEL_PREF,
638 &VCF_TYPE_TEL_WORK,
639 &VCF_TYPE_TEL_HOME,
640 &VCF_TYPE_TEL_VOICE,
641 &VCF_TYPE_TEL_FAX,
642 &VCF_TYPE_TEL_MSG,
643 &VCF_TYPE_TEL_CELL,
644 &VCF_TYPE_TEL_PAGER,
645 &VCF_TYPE_TEL_BBS,
646 &VCF_TYPE_TEL_MODEM,
647 &VCF_TYPE_TEL_CAR,
648 &VCF_TYPE_TEL_ISDN,
649 &VCF_TYPE_TEL_VIDEO
650 };
651
652static const ULONG aflPhone[] =
653 {
654 VCF_PHONEFL_PREF,
655 VCF_PHONEFL_WORK,
656 VCF_PHONEFL_HOME,
657 VCF_PHONEFL_VOICE,
658 VCF_PHONEFL_FAX,
659 VCF_PHONEFL_MSG,
660 VCF_PHONEFL_CELL,
661 VCF_PHONEFL_PAGER,
662 VCF_PHONEFL_BBS,
663 VCF_PHONEFL_MODEM,
664 VCF_PHONEFL_CAR,
665 VCF_PHONEFL_ISDN,
666 VCF_PHONEFL_VIDEO
667 };
668
669/*
670 *@@ AppendTel:
671 *
672 */
673
674VOID AppendTel(PVCARD pvc,
675 PVCFPROPERTY pProp)
676{
677 if (pvc->paPhones = (PVCPHONE)realloc(pvc->paPhones,
678 (pvc->cPhones + 1) * sizeof(VCPHONE)))
679 {
680 ULONG ul;
681 PVCPHONE pThis = &pvc->paPhones[(pvc->cPhones)++];
682
683 CopyStrings(pProp,
684 &pThis->pcszNumber,
685 1);
686
687 pThis->fl = GetFlagStrings(pProp->pastrParameters,
688 pProp->cParameters,
689 apcszPhone,
690 aflPhone,
691 ARRAYITEMCOUNT(apcszPhone),
692 VCF_PHONEFL_VOICE);
693 }
694}
695
696/*
697 *@@ vcfRead:
698 *
699 */
700
701APIRET vcfRead(PCSZ pcszFilename,
702 PVCARD *ppvCard) // out: vCard handle
703{
704 APIRET arc;
705 PSZ pszData = NULL;
706 ULONG cbRead;
707 if (!(arc = doshLoadTextFile(pcszFilename,
708 &pszData,
709 &cbRead)))
710 {
711 XSTRING str;
712 PSZ p;
713
714 COUNTRYCODE cc = {0};
715 COUNTRYINFO ci = {0};
716 ULONG cb;
717
718 DosQueryCtryInfo(sizeof(ci),
719 &cc,
720 &ci,
721 &cb);
722
723 xstrInitSet2(&str, pszData, cbRead - 1);
724 xstrConvertLineFormat(&str, CRLF2LF);
725
726 if ( (p = strhistr(str.psz, "BEGIN:VCARD"))
727 && (p = strhFindEOL(p, NULL))
728 )
729 {
730 PLINKLIST pll = lstCreate(FALSE);
731 if (!(arc = Tokenize(0,
732 &p,
733 pll,
734 ci.codepage)))
735 {
736 PVCARD pvc;
737 if (!(pvc = NEW(VCARD)))
738 arc = ERROR_NOT_ENOUGH_MEMORY;
739 else
740 {
741 PVCFPROPERTY pProp;
742 PLISTNODE pNode;
743
744 ZERO(pvc);
745
746
747 pvc->pll = pll;
748
749 // now go set up the data fields
750 if (pProp = FindValues(pll,
751 VCFPROP_FN,
752 NULL))
753 CopyStrings(pProp,
754 &pvc->pcszFormattedName,
755 1);
756
757 if (pProp = FindValues(pll,
758 VCFPROP_N,
759 NULL))
760 CopyStrings(pProp,
761 pvc->apcszName,
762 5);
763
764 if (pProp = FindValues(pll,
765 VCFPROP_EMAIL,
766 NULL))
767 CopyStrings(pProp,
768 &pvc->pcszEmail,
769 1);
770
771 if (pProp = FindValues(pll,
772 VCFPROP_TITLE,
773 NULL))
774 CopyStrings(pProp,
775 &pvc->pcszJobTitle,
776 1);
777
778 for (pNode = lstQueryFirstNode(pll);
779 pNode;
780 pNode = pNode->pNext)
781 {
782 pProp = (PVCFPROPERTY)pNode->pItemData;
783
784 if (!strcmp(pProp->strProperty.psz, VCFPROP_ADR))
785 AppendAddress(pvc,
786 pProp);
787 else if (!strcmp(pProp->strProperty.psz, VCFPROP_LABEL))
788 AppendLabel(pvc,
789 pProp);
790 else if (!strcmp(pProp->strProperty.psz, VCFPROP_TEL))
791 AppendTel(pvc,
792 pProp);
793 }
794
795 *ppvCard = pvc;
796 }
797 }
798
799 if (arc)
800 FreeList(&pll);
801 }
802 else
803 arc = ERROR_BAD_FORMAT;
804
805 xstrClear(&str);
806 }
807
808 _Pmpf((__FUNCTION__ ": returning %d", arc));
809
810 return (arc);
811}
812
813/*
814 *@@ FreeList:
815 *
816 */
817
818VOID FreeList(PLINKLIST *ppll)
819{
820 PLISTNODE pNode = lstQueryFirstNode(*ppll);
821 while (pNode)
822 {
823 PVCFPROPERTY pProp = (PVCFPROPERTY)pNode->pItemData;
824 ULONG ul;
825
826 xstrClear(&pProp->strProperty);
827
828 if (pProp->pllSubList)
829 FreeList(&pProp->pllSubList);
830
831 if (pProp->pastrParameters)
832 {
833 for (ul = 0;
834 ul < pProp->cParameters;
835 ul++)
836 xstrClear(&pProp->pastrParameters[ul]);
837
838 free(pProp->pastrParameters);
839 }
840
841 if (pProp->pastrValues)
842 {
843 for (ul = 0;
844 ul < pProp->cValues;
845 ul++)
846 xstrClear(&pProp->pastrValues[ul]);
847
848 free(pProp->pastrValues);
849 }
850
851 pNode = pNode->pNext;
852 }
853
854 lstFree(ppll);
855}
856
857/*
858 *@@ vcfFree:
859 *
860 */
861
862APIRET vcfFree(PVCARD *ppvCard)
863{
864 PVCARD pvc;
865 if ( (!ppvCard)
866 || (!(pvc = *ppvCard))
867 )
868 return ERROR_INVALID_PARAMETER;
869 else
870 {
871 FREE(pvc->paDeliveryAddresses);
872
873 FreeList(&pvc->pll);
874
875 free(pvc);
876 *ppvCard = NULL;
877 }
878
879 return NO_ERROR;
880}
881
882
Note: See TracBrowser for help on using the repository browser.