1 /*
2  *  libvc - vCard library
3  *  Copyright (C) 2003  Andrew Hsu
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2.1 of the License, or (at your option) any later
9  *  version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free
18  *  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
19  *  MA  02111-1307  USA
20  *
21  *  $Id: vc.c,v 1.5 2003/06/14 00:03:39 ahsu Rel $
22  */
23 
24 
25 #include "vc.h"
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdio.h>
29 
30 #define BUF_LEN 80
31 
32 /*** STRUCTS ***/
33 
34 struct vc_component_tag
35 {
36   char *group;
37   char *name;
38   vc_component_param *param;
39   char *value;
40   vc_component *next;
41 };
42 
43 struct vc_component_param_tag
44 {
45   char *name;
46   char *value;
47   vc_component_param *next;
48 };
49 
50 /*** FUNCTION DEFINITIONS ***/
51 
52 /***************************************************************************
53     Returns a new vc_component with everything set to NULL.  The
54     user of the new vc_component will be responsible for freeing
55     it in the future with a call to vc_delete or vc_delete_deep.
56  */
57 
58 vc_component *
vc_new()59 vc_new ()
60 {
61   vc_component *new_vc = NULL;
62 
63   new_vc = (vc_component *) malloc (sizeof (vc_component));
64 
65   if (NULL == new_vc)
66     {
67       fprintf (stderr, "unable to malloc a new vc_component\n");
68       exit (1);
69     }
70   else
71     {
72       new_vc->group = NULL;
73       new_vc->name = NULL;
74       new_vc->param = NULL;
75       new_vc->value = NULL;
76       new_vc->next = NULL;
77     }
78 
79   return new_vc;
80 }
81 
82 /***************************************************************************
83     Sets the group of a vc_component by making a copy of the
84     given group.  Does nothing if the given vc_component is NULL.
85     Returns the given vc_component.
86  */
87 
88 vc_component *
vc_set_group(vc_component * vc,const char * group)89 vc_set_group (vc_component * vc, const char *group)
90 {
91   if (NULL != vc)
92     {
93       free (vc->group);
94       vc->group = strdup (group);
95     }
96 
97   return vc;
98 }
99 
100 /***************************************************************************
101     Sets the name of a vc_component by making a copy of the given
102     name.  Does nothing if the given vc_component is NULL.
103     Returns the given vc_component.
104  */
105 
106 vc_component *
vc_set_name(vc_component * vc,char * name)107 vc_set_name (vc_component * vc, char *name)
108 {
109   if (NULL != vc)
110     {
111       free (vc->name);
112       vc->name = strdup (name);
113     }
114 
115   return vc;
116 }
117 
118 /***************************************************************************
119     Appends to the linked-list of parameters in the given
120     vc_component.  Does nothing if the given vc_component is
121     NULL.  Returns the given vc_component.
122  */
123 
124 vc_component *
vc_add_param(vc_component * vc,vc_component_param * vc_param)125 vc_add_param (vc_component * vc, vc_component_param * vc_param)
126 {
127   if (NULL != vc)
128     {
129       vc_component_param *p = NULL;
130       p = vc->param;
131 
132       if (NULL == p)
133         {
134           vc->param = vc_param;
135         }
136       else
137         {
138           while (NULL != p->next)
139             {
140               p = p->next;
141             }
142 
143           p->next = vc_param;
144         }
145     }
146 
147   return vc;
148 }
149 
150 /***************************************************************************
151     Sets the value of a vc_component by making a copy of the
152     given value.  Does nothing if the given vc_component is NULL.
153     Returns the given vc_component.
154  */
155 
156 vc_component *
vc_set_value(vc_component * vc,const char * value)157 vc_set_value (vc_component * vc, const char *value)
158 {
159   if (NULL != vc)
160     {
161       free (vc->value);
162       vc->value = strdup (value);
163     }
164 
165   return vc;
166 }
167 
168 /***************************************************************************
169     Traverses to the end of the list of head and then appends tail
170     as the next node.  If head is null, does nothing.  Returns head.
171  */
172 
173 vc_component *
vc_link(vc_component * head,vc_component * tail)174 vc_link (vc_component * head, vc_component * tail)
175 {
176   if (NULL != head)
177     {
178       vc_component *vc = NULL;
179       vc = head;
180 
181       while (NULL != vc->next)
182         {
183           vc = vc->next;
184         }
185 
186       vc->next = tail;
187     }
188 
189   return head;
190 }
191 
192 /***************************************************************************
193     This is a convenience function for appending a new vc_component
194     to the end of the list pointed to by the given vc_component.
195     Returns a pointer to the newly created vc_component if
196     successful, NULL otherwise.
197  */
198 
199 vc_component *
vc_append_with_name(vc_component * vc,char * name)200 vc_append_with_name (vc_component * vc, char *name)
201 {
202   vc_component *new_vc = NULL;
203   if (NULL != vc)
204     {
205       new_vc = vc_new ();
206       vc_set_name (new_vc, name);
207       vc_link (vc, new_vc);
208     }
209 
210   return new_vc;
211 }
212 
213 /***************************************************************************
214     Checks the parameters of the given vc_component to see if
215     there exists a parameter name `TYPE' with a value of `pref'.
216     Returns a value of 1 if found, else 0.
217  */
218 
219 int
vc_is_preferred(vc_component * vc)220 vc_is_preferred (vc_component * vc)
221 {
222   int ret_val = 0;
223 
224   if (NULL != vc)
225     {
226       vc_component_param *vc_param = NULL;
227       char *value = NULL;
228       int done = 0;
229 
230       for (vc_param = vc_param_get_by_name (vc->param, "TYPE");
231            (NULL != vc_param) && (!done);
232            vc_param = vc_param_get_next_by_name (vc_param, "TYPE"))
233         {
234           value = vc_param_get_value (vc_param);
235 
236           if (NULL != value)
237             {
238               if (0 == strcasecmp (value, "pref"))
239                 {
240                   ret_val = 1;
241                   done = 1;
242                 }
243             }
244         }
245     }
246 
247   return ret_val;
248 }
249 
250 /***************************************************************************
251     Returns the pointer to the name of the preferred telephone
252     number of the given vc.  This is done by checking for `TYPE'
253     parameters with a value of `pref'.  If no such parameter is
254     found, then the first vc_component with the name `TEL' will be
255     returned.  Returns NULL if none found.  Users of this function
256     must not modify the contents to which the returned pointer
257     points to.
258 
259     TODO: Fix the duplicate code with vc_get_preferred_email.
260  */
261 
262 char *
vc_get_preferred_tel(vc_component * v)263 vc_get_preferred_tel (vc_component * v)
264 {
265   char *tel = NULL;
266   int done = 0;
267   vc_component *vc = NULL;
268 
269   vc = vc_get_next_by_name (v, VC_TELEPHONE);
270   tel = vc_get_value (vc);
271 
272   if (!vc_is_preferred (vc))
273     {
274       while ((NULL != vc) && (!done))
275         {
276           vc = vc_get_next_by_name (vc, VC_TELEPHONE);
277           if (vc_is_preferred (vc))
278             {
279               tel = vc_get_value (vc);
280               done = 1;
281             }
282         }
283     }
284 
285   return tel;
286 }
287 
288 /***************************************************************************
289     Returns the pointer to the name of the preferred email number
290     of the given vc.  This is done by checking for `TYPE'
291     parameters with a value of `pref'.  If no such parameter is
292     found, then the first vc_component with the name `EMAIL'
293     will be returned.  Returns NULL if none found.  Users of this
294     function must not modify the contents to which the returned
295     pointer points to.
296 
297     FIXME: lots of duplicate code with vc_get_preferred_tel
298  */
299 
300 char *
vc_get_preferred_email(vc_component * v)301 vc_get_preferred_email (vc_component * v)
302 {
303   char *email = NULL;
304   int done = 0;
305   vc_component *vc = NULL;
306 
307   vc = vc_get_next_by_name (v, VC_EMAIL);
308   email = vc_get_value (vc);
309 
310   if (!vc_is_preferred (vc))
311     {
312       while ((NULL != vc) && (!done))
313         {
314           vc = vc_get_next_by_name (vc, VC_EMAIL);
315           if (vc_is_preferred (vc))
316             {
317               email = vc_get_value (vc);
318               done = 1;
319             }
320         }
321     }
322 
323   return email;
324 }
325 
326 /***************************************************************************
327     Returns the pointer to the group of the given vc_component.
328     Users of this function must not modify the contents to which
329     the pointer points to (use vc_set_group function for modifying
330     the group).  Returns NULL if no group found.
331  */
332 
333 char *
vc_get_group(const vc_component * vc)334 vc_get_group (const vc_component * vc)
335 {
336   char *ret_val = NULL;
337   if (NULL != vc)
338     {
339       ret_val = vc->group;
340     }
341 
342   return ret_val;
343 }
344 
345 /***************************************************************************
346     Returns the pointer to the name of the given vc_component.
347     Users of this function must not modify the contents to which
348     the pointer points to (use vc_set_name function for modifying
349     the name).  Returns NULL if no name found.
350  */
351 
352 char *
vc_get_name(const vc_component * vc)353 vc_get_name (const vc_component * vc)
354 {
355   char *ret_val = NULL;
356   if (NULL != vc)
357     {
358       ret_val = vc->name;
359     }
360 
361   return ret_val;
362 }
363 
364 /***************************************************************************
365     Returns the pointer to the first parameter of the given
366     vc_component.  Users of this function may use the modify
367     functions for vc_component_param to change the contents of
368     the returned parameter.  Returns NULL if no parameter found.
369  */
370 
371 vc_component_param *
vc_get_param(const vc_component * vc)372 vc_get_param (const vc_component * vc)
373 {
374   vc_component_param *ret_val = NULL;
375   if (NULL != vc)
376     {
377       ret_val = vc->param;
378     }
379 
380   return ret_val;
381 }
382 
383 /***************************************************************************
384     Returns the pointer to the value of the given vc_component.
385     Users of this function must not modify the contents to which
386     the pointer points to (use vc_set_value function for modifying
387     the value).  Returns NULL if no value found.
388  */
389 
390 char *
vc_get_value(const vc_component * vc)391 vc_get_value (const vc_component * vc)
392 {
393   char *ret_val = NULL;
394   if (NULL != vc)
395     {
396       ret_val = vc->value;
397     }
398 
399   return ret_val;
400 }
401 
402 /***************************************************************************
403     Returns a new vc_component_param with everything set to NULL.
404     The user of the new vc_component_param will be responsible
405     for freeing it in the future with a call to vc_param_delete or
406     vc_param_delete_deep.
407  */
408 
409 vc_component_param *
vc_param_new()410 vc_param_new ()
411 {
412   vc_component_param *new_vc_param = NULL;
413 
414   new_vc_param = (vc_component_param *) malloc (sizeof (vc_component_param));
415 
416   if (NULL == new_vc_param)
417     {
418       fprintf (stderr, "unable to malloc a new vc_component_param\n");
419       exit (1);
420     }
421   else
422     {
423       new_vc_param->name = NULL;
424       new_vc_param->value = NULL;
425       new_vc_param->next = NULL;
426     }
427 
428   return new_vc_param;
429 }
430 
431 /***************************************************************************
432     Sets the name of a vc_component_param by making a copy of
433     the given name.  Does nothing if the given vc_component_param
434     is NULL.  Returns the given vc_component_param.
435  */
436 
437 vc_component_param *
vc_param_set_name(vc_component_param * vc_param,const char * name)438 vc_param_set_name (vc_component_param * vc_param, const char *name)
439 {
440   if (NULL != vc_param)
441     {
442       free (vc_param->name);
443       vc_param->name = strdup (name);
444     }
445 
446   return vc_param;
447 }
448 
449 /***************************************************************************
450     Sets the value of a vc_component_param by making a copy of
451     the given value.  Does nothing if the given vc_component_param
452     is NULL.  Returns the given vc_component_param.
453  */
454 
455 vc_component_param *
vc_param_set_value(vc_component_param * vc_param,const char * value)456 vc_param_set_value (vc_component_param * vc_param, const char *value)
457 {
458   if (NULL != vc_param)
459     {
460       free (vc_param->value);
461       vc_param->value = strdup (value);
462     }
463 
464   return vc_param;
465 }
466 
467 /***************************************************************************
468     Traverses to the end of the list of head and then appends tail
469     as the next node.  If head is null, does nothing.  Returns head.
470  */
471 
472 vc_component_param *
vc_param_link(vc_component_param * head,vc_component_param * tail)473 vc_param_link (vc_component_param * head, vc_component_param * tail)
474 {
475   if (NULL != head)
476     {
477       vc_component_param *vc_param = NULL;
478       vc_param = head;
479 
480       while (NULL != vc_param->next)
481         {
482           vc_param = vc_param->next;
483         }
484 
485       vc_param->next = tail;
486     }
487 
488   return head;
489 }
490 
491 /***************************************************************************
492     Returns the pointer to the name of the given vc_component_param.
493     Users of this function must not modify the contents to which
494     the pointer points to (use vc_param_set_name function for
495     modifying the name).  Returns NULL if no name found.
496  */
497 
498 char *
vc_param_get_name(const vc_component_param * vc_param)499 vc_param_get_name (const vc_component_param * vc_param)
500 {
501   char *ret_val = NULL;
502   if (NULL != vc_param)
503     {
504       ret_val = vc_param->name;
505     }
506 
507   return ret_val;
508 }
509 
510 /***************************************************************************
511     Returns the pointer to the value of the given vc_component_param.
512     Users of this function must not modify the contents to which
513     the pointer points to (use vc_param_set_value function for
514     modifying the value).  Returns NULL if no name found.
515  */
516 
517 char *
vc_param_get_value(const vc_component_param * vc_param)518 vc_param_get_value (const vc_component_param * vc_param)
519 {
520   char *ret_val = NULL;
521   if (NULL != vc_param)
522     {
523       ret_val = vc_param->value;
524     }
525 
526   return ret_val;
527 }
528 
529 /***************************************************************************
530     Returns the next vc_component linked to the given one.
531     Returns NULL if none left.
532  */
533 
534 vc_component *
vc_get_next(const vc_component * vc)535 vc_get_next (const vc_component * vc)
536 {
537   vc_component *ret_val = NULL;
538 
539   if (NULL != vc)
540     {
541       ret_val = vc->next;
542     }
543 
544   return ret_val;
545 }
546 
547 /***************************************************************************
548     Searches for a vc_component that matches the given name,
549     starting with the one after the given vc_component.  Returns
550     NULL if none is found.
551  */
552 
553 vc_component *
vc_get_next_by_name(vc_component * vc,const char * name)554 vc_get_next_by_name (vc_component * vc, const char *name)
555 {
556   vc_component *result_vc = NULL;
557   vc_component *tmp_vc = NULL;
558   int done = 0;
559 
560   if ((NULL != name) && (NULL != vc))
561     {
562       tmp_vc = vc->next;
563       while ((0 == done) && (NULL != tmp_vc))
564         {
565           if (NULL != tmp_vc->name)
566             {
567               if (0 == strcasecmp (name, tmp_vc->name))
568                 {
569                   result_vc = tmp_vc;
570                   done = 1;
571                 }
572             }
573           tmp_vc = tmp_vc->next;
574         }
575     }
576 
577   return result_vc;
578 }
579 
580 /***************************************************************************
581     Returns the next vc_component_param linked to the given one.
582     Returns NULL if none left.
583  */
584 
585 vc_component_param *
vc_param_get_next(const vc_component_param * vc_param)586 vc_param_get_next (const vc_component_param * vc_param)
587 {
588   vc_component_param *ret_val = NULL;
589 
590   if (NULL != vc_param)
591     {
592       ret_val = vc_param->next;
593     }
594 
595   return ret_val;
596 }
597 
598 /***************************************************************************
599     Searches for a vc_component_param that matches the given
600     name, starting with the given vc_component_param.  Returns
601     NULL if none is found.
602 
603     FIXME: lots of code duplicated from vc_param_get_next_by_name
604  */
605 
606 vc_component_param *
vc_param_get_by_name(vc_component_param * vc_param,const char * name)607 vc_param_get_by_name (vc_component_param * vc_param, const char *name)
608 {
609   vc_component_param *result_vc_param = NULL;
610   vc_component_param *tmp_vc_param = NULL;
611   int done = 0;
612 
613   if ((NULL != name) && (NULL != vc_param))
614     {
615       tmp_vc_param = vc_param;
616       while ((0 == done) && (NULL != tmp_vc_param))
617         {
618           if (NULL != tmp_vc_param->name)
619             {
620               if (0 == strcasecmp (name, tmp_vc_param->name))
621                 {
622                   result_vc_param = tmp_vc_param;
623                   done = 1;
624                 }
625             }
626           tmp_vc_param = tmp_vc_param->next;
627         }
628     }
629 
630   return result_vc_param;
631 }
632 
633 /***************************************************************************
634     Searches for a vc_component_param that matches the given
635     name, starting with the one after the given vc_component_param.
636     Returns NULL if none is found.
637 
638     FIXME: lots of code duplicated from vc_param_get_by_name
639  */
640 
641 vc_component_param *
vc_param_get_next_by_name(vc_component_param * vc_param,const char * name)642 vc_param_get_next_by_name (vc_component_param * vc_param, const char *name)
643 {
644   vc_component_param *result_vc_param = NULL;
645   vc_component_param *tmp_vc_param = NULL;
646   int done = 0;
647 
648   if ((NULL != name) && (NULL != vc_param))
649     {
650       tmp_vc_param = vc_param->next;
651       while ((0 == done) && (NULL != tmp_vc_param))
652         {
653           if (NULL != tmp_vc_param->name)
654             {
655               if (0 == strcasecmp (name, tmp_vc_param->name))
656                 {
657                   result_vc_param = tmp_vc_param;
658                   done = 1;
659                 }
660             }
661           tmp_vc_param = tmp_vc_param->next;
662         }
663     }
664 
665   return result_vc_param;
666 }
667 
668 /***************************************************************************
669     Performs a "shallow" delete of the given vc_component.  This
670     means that only the given vc_component will be freed.  As a
671     side-effect, a "deep" delete of all the associated parameters
672     will be performed.  A responsible user of this function would
673     also remember to set the given vc_component pointer variable
674     to NULL when this function returns.
675  */
676 
677 void
vc_delete(vc_component * vc)678 vc_delete (vc_component * vc)
679 {
680   if (NULL != vc)
681     {
682       free (vc->group);
683       free (vc->name);
684       vc_param_delete_deep (vc->param);
685       free (vc->value);
686       free (vc);
687     }
688 }
689 
690 /***************************************************************************
691     Performs a "deep" delete of the given vc_component.  This
692     means that all the vc_components linked to the given one
693     will also be deleted.  A responsible user of this function would
694     also remember to set the given vc_component pointer variable
695     to NULL when this function returns.
696  */
697 
698 void
vc_delete_deep(vc_component * vc)699 vc_delete_deep (vc_component * vc)
700 {
701   vc_component *tmp_vc = NULL;
702   vc_component *vc_to_free = NULL;
703 
704   tmp_vc = vc;
705   while (NULL != tmp_vc)
706     {
707       vc_to_free = tmp_vc;
708       tmp_vc = tmp_vc->next;
709 
710       vc_delete (vc_to_free);
711     }
712 }
713 
714 /***************************************************************************
715     Performs a "shallow" delete of the given vc_component_param.
716     This means that only the given vc_component_param will be
717     freed.  A responsible user of this function would also remember
718     to set the given vc_component_param pointer variable to NULL
719     when this function returns.
720  */
721 
722 void
vc_param_delete(vc_component_param * vc_param)723 vc_param_delete (vc_component_param * vc_param)
724 {
725   if (NULL != vc_param)
726     {
727       free (vc_param->name);
728       free (vc_param->value);
729       free (vc_param);
730     }
731 }
732 
733 /***************************************************************************
734     Performs a "deep" delete of the given vc_component_param.
735     This means that all the vc_component_params linked to the
736     given one will also be deleted.  A responsible user of this
737     function would also remember to set the given vc_component_param
738     pointer variable to NULL when this function returns.
739  */
740 
741 void
vc_param_delete_deep(vc_component_param * vc_param)742 vc_param_delete_deep (vc_component_param * vc_param)
743 {
744   vc_component_param *tmp_vc_param = NULL;
745   vc_component_param *vc_param_to_free = NULL;
746 
747   tmp_vc_param = vc_param;
748   while (NULL != tmp_vc_param)
749     {
750       vc_param_to_free = tmp_vc_param;
751       tmp_vc_param = tmp_vc_param->next;
752 
753       vc_param_delete (vc_param_to_free);
754     }
755 }
756 
757 /***************************************************************************
758     Prints the linked-list of vc_component_param to the given
759     FILE pointer.
760  */
761 
762 void
fprintf_vc_component_param(FILE * fp,vc_component_param * vc_param)763 fprintf_vc_component_param (FILE * fp, vc_component_param * vc_param)
764 {
765   vc_component_param *tmp_vc_param = NULL;
766 
767   tmp_vc_param = vc_param;
768 
769   for (tmp_vc_param = vc_param; NULL != tmp_vc_param;
770        tmp_vc_param = vc_param_get_next (tmp_vc_param))
771     {
772       fprintf (fp, ";%s=%s", tmp_vc_param->name, tmp_vc_param->value);
773     }
774 }
775 
776 /***************************************************************************
777     Prints a single vc_component to the given FILE pointer.
778  */
779 
780 void
fprintf_vc_component(FILE * fp,vc_component * vc)781 fprintf_vc_component (FILE * fp, vc_component * vc)
782 {
783   if (NULL != vc)
784     {
785       if (NULL != vc->group)
786         {
787           fprintf (fp, "%s.", vc->group);
788         }
789 
790       /* the name is expected to exist */
791       fprintf (fp, "%s", vc->name);
792 
793       fprintf_vc_component_param (fp, vc->param);
794       fprintf (fp, ":");
795 
796       if (NULL != vc->value)
797         {
798           fprintf (fp, "%s", vc->value);
799         }
800 
801       fprintf (fp, "\n");
802     }
803 }
804 
805 /***************************************************************************
806     Prints the entire vCard to the given FILE pointer.
807  */
808 
809 void
fprintf_vcard(FILE * fp,vc_component * vcard)810 fprintf_vcard (FILE * fp, vc_component * vcard)
811 {
812   vc_component *vc = NULL;
813 
814   vc = vcard;
815   if (NULL != vc)
816     {
817       fprintf (fp, "BEGIN:VCARD\n");
818 
819       for (vc = vc->next; NULL != vc; vc = vc->next)
820         {
821           fprintf_vc_component (fp, vc);
822         }
823 
824       fprintf (fp, "END:VCARD\n");
825     }
826 }
827 
828 /***************************************************************************
829     Returns the number of vCards found in the given FILE pointer.
830  */
831 
832 int
count_vcards(FILE * fp)833 count_vcards (FILE * fp)
834 {
835   char buf[256];
836   int counter = 0;
837 
838   while (EOF != fscanf (fp, "%s\n", buf))
839     {
840       if (0 == strcasecmp (buf, "BEGIN:VCARD"))
841         counter++;
842     }
843 
844   return counter;
845 }
846 
847 /***************************************************************************
848     Returns a new string of the contents of the section of the given
849     string denoted by the part_index.
850  */
851 
852 char *
get_val_struct_part(const char * str,int part_index)853 get_val_struct_part (const char *str, int part_index)
854 {
855   char buf[BUF_LEN];
856   int i = 0;
857   int j = 0;
858   int part_counter = 0;
859   int done = 0;
860   char *result = NULL;
861 
862   if (NULL != str)
863     {
864       buf[0] = '\0';
865 
866       while ('\0' != str[i] && 1 != done)
867         {
868           if (part_index == part_counter)
869             {
870               while (str[i] != ';' && i < BUF_LEN - 1)
871                 {
872                   buf[j] = str[i];
873                   j++;
874                   i++;
875                 }
876 
877               buf[j] = '\0';
878               done = 1;
879             }
880           else
881             {
882               if (';' == str[i])
883                 {
884                   part_counter++;
885                 }
886               i++;
887             }
888         }
889 
890       if ('\0' != buf[0])
891         {
892           result = strdup (buf);
893         }
894     }
895 
896   return result;
897 }
898