Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / addressbook / libebook / e-vcard.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* e-vcard.c
3  *
4  * Copyright (C) 2003 Ximian, Inc.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of version 2 of the GNU Lesser General Public
8  * License as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  * Author: Chris Toshok (toshok@ximian.com)
21  */
22
23 /* This file implements the decoding of the v-card format
24  * http://www.imc.org/pdi/vcard-21.txt
25  */
26
27 #include <glib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include "e-vcard.h"
32
33 #define d(x)
34
35 #define CRLF "\r\n"
36
37 /** Encoding used in v-card 
38  *  Note: v-card spec defines additional 7BIT 8BIT and X- encoding
39  */
40 typedef enum {
41         EVC_ENCODING_RAW,    /* no encoding */
42         EVC_ENCODING_BASE64, /* base64 */
43         EVC_ENCODING_QP      /* quoted-printable */
44 } EVCardEncoding;
45
46 struct _EVCardPrivate {
47         GList *attributes;
48 };
49
50 struct _EVCardAttribute {
51         char  *group;
52         char  *name;
53         GList *params; /* EVCardParam */
54         GList *values;
55         GList *decoded_values;
56         EVCardEncoding encoding;
57         gboolean encoding_set;
58 };
59
60 struct _EVCardAttributeParam {
61         char     *name;
62         GList    *values;  /* GList of char*'s*/
63 };
64
65 static GObjectClass *parent_class;
66
67 static void   _evc_base64_init(void);
68 static size_t _evc_base64_encode_step(unsigned char *in, size_t len, gboolean break_lines, unsigned char *out, int *state, int *save);
69 static size_t _evc_base64_decode_step(unsigned char *in, size_t len, unsigned char *out, int *state, unsigned int *save);
70 size_t _evc_base64_decode_simple (char *data, size_t len);
71 char  *_evc_base64_encode_simple (const char *data, size_t len);
72
73 static void
74 e_vcard_dispose (GObject *object)
75 {
76         EVCard *evc = E_VCARD (object);
77
78         if (evc->priv) {
79
80                 g_list_foreach (evc->priv->attributes, (GFunc)e_vcard_attribute_free, NULL);
81                 g_list_free (evc->priv->attributes);
82
83                 g_free (evc->priv);
84                 evc->priv = NULL;
85         }
86
87         if (G_OBJECT_CLASS (parent_class)->dispose)
88                 G_OBJECT_CLASS (parent_class)->dispose (object);
89 }
90
91 static void
92 e_vcard_class_init (EVCardClass *klass)
93 {
94         GObjectClass *object_class;
95
96         object_class = G_OBJECT_CLASS(klass);
97
98         parent_class = g_type_class_ref (G_TYPE_OBJECT);
99
100         object_class->dispose = e_vcard_dispose;
101
102         _evc_base64_init();
103 }
104
105 static void
106 e_vcard_init (EVCard *evc)
107 {
108         evc->priv = g_new0 (EVCardPrivate, 1);
109 }
110
111 GType
112 e_vcard_get_type (void)
113 {
114         static GType vcard_type = 0;
115
116         if (!vcard_type) {
117                 static const GTypeInfo vcard_info =  {
118                         sizeof (EVCardClass),
119                         NULL,           /* base_init */
120                         NULL,           /* base_finalize */
121                         (GClassInitFunc) e_vcard_class_init,
122                         NULL,           /* class_finalize */
123                         NULL,           /* class_data */
124                         sizeof (EVCard),
125                         0,             /* n_preallocs */
126                         (GInstanceInitFunc) e_vcard_init,
127                 };
128
129                 vcard_type = g_type_register_static (G_TYPE_OBJECT, "EVCard", &vcard_info, 0);
130         }
131
132         return vcard_type;
133 }
134
135
136
137 /*  Skip newline characters and return the next character.
138  *  This function takes care of folding lines, skipping 
139  *  newline characters if found, taking care of equal characters
140  *  and other strange things.
141  */
142 static char*
143 skip_newline (char *str, gboolean quoted_printable)
144 {
145         char *p; 
146         char *next;
147         char *next2;
148         p = str;
149
150         /* -- swallow equal signs at end of line for quoted printable */
151         /* note: a quoted_printable linefolding is an equal sign followed by
152            one or more newline characters and optional a whitespace */
153         if (quoted_printable && *p == '=' ) {
154                 next = g_utf8_next_char (p);
155                 if (*next == '\r' || *next == '\n') {
156                         p = g_utf8_next_char (next); /* swallow equal and newline */
157
158                         if ((*p == '\r' || *p == '\n') && *p != *next ) {
159                                 p = g_utf8_next_char (p); /* swallow second newline */
160
161                                 if (*p == ' ' || *p == '\t') {
162                                         p = g_utf8_next_char (p); /* swallow whitespace */
163                                 }
164                         }
165
166                 }
167
168         /* -- swallow newline and (if present) following whitespaces */
169         } else if (*p == '\r' || *p == '\n') {
170
171                 next = g_utf8_next_char (p);
172                 if ((*next == '\n' || *next == '\r') && *p != *next) {
173
174                         next2 = g_utf8_next_char (next);
175                         if (*next2 == ' ' || *next2 == '\t') {
176                                 p = g_utf8_next_char (next2); /* we found a line folding */
177                         }
178
179                 } else if (*next == ' ' || *next == '\t') {
180                         p = g_utf8_next_char (next);  /* we found a line folding */
181                 }
182         }
183
184         return p;
185 }
186
187
188 /* skip forward until we hit the CRLF, or \0 */
189 static void
190 skip_to_next_line (char **p)
191 {
192         char *lp;
193         lp = *p;
194
195         while (*lp != '\n' && *lp != '\r' && *lp != '\0')
196                 lp = g_utf8_next_char (lp);
197
198         /* -- skip over the endline */
199         while( *lp == '\r' || *lp == '\n' ) {
200                 lp = g_utf8_next_char (lp);
201         }
202
203         *p = lp;
204 }
205
206 /* skip forward until we hit a character in @s, CRLF, or \0.  leave *p
207    pointing at the character that causes us to stop */
208 static void
209 skip_until (char **p, char *s)
210 {
211         char *lp;
212
213         lp = *p;
214
215         while (*lp != '\r' && *lp != '\0') {
216                 gboolean s_matches = FALSE;
217                 char *ls;
218                 for (ls = s; *ls; ls = g_utf8_next_char (ls)) {
219                         if (g_utf8_get_char (ls) == g_utf8_get_char (lp)) {
220                                 s_matches = TRUE;
221                                 break;
222                         }
223                 }
224
225                 if (s_matches)
226                         break;
227                 lp = g_utf8_next_char (lp);
228         }
229
230         *p = lp;
231 }
232
233 static void
234 read_attribute_value (EVCardAttribute *attr, char **p, gboolean quoted_printable)
235 {
236         char *lp = *p;
237         GString *str;
238
239         /* read in the value */
240         str = g_string_new ("");
241         for( lp =  skip_newline( *p, quoted_printable );
242              *lp != '\n' && *lp != '\r' && *lp != '\0'; 
243              lp = skip_newline( lp, quoted_printable ) ) {
244
245                 if (*lp == '=' && quoted_printable) {
246                         char a, b;
247                         if ((a = *(++lp)) == '\0') break;
248                         if ((b = *(++lp)) == '\0') break;
249                         if (isxdigit(a) && isxdigit (b)) {
250                                 char c;
251
252                                 a = tolower (a);
253                                 b = tolower (b);
254
255                                 c = (((a>='a'?a-'a'+10:a-'0')&0x0f) << 4)
256                                         | ((b>='a'?b-'a'+10:b-'0')&0x0f);
257                                 
258                                 g_string_append_c (str, c); /* add decoded byte (this is not a unicode yet) */
259                         }
260                         else 
261                                 {
262                                         g_string_append_c (str, a);
263                                         g_string_append_c (str, b);
264                                 }
265                         
266                         lp++;
267
268                 } else if (*lp == '\\') {
269                         /* convert back to the non-escaped version of
270                            the characters */
271                         lp = g_utf8_next_char(lp);
272                         if (*lp == '\0') {
273                                 g_string_append_c (str, '\\');
274                                 break;
275                         }
276
277                         /* beware, there might be a line break due to folding,
278                          * need next real character
279                          */
280                         lp = skip_newline (lp, quoted_printable);
281
282                         switch (*lp) {
283                         case 'n': g_string_append_c (str, '\n'); break;
284                         case 'N': g_string_append_c (str, '\n'); break;
285                         case 'r': g_string_append_c (str, '\r'); break;
286                         case 'R': g_string_append_c (str, '\r'); break;
287                         case ';': g_string_append_c (str, ';'); break;
288                         case ',': g_string_append_c (str, ','); break;
289                         case '\\': g_string_append_c (str, '\\'); break;
290                         default:
291                                 g_warning ("invalid escape, passing it through");
292                                 g_string_append_c (str, '\\');
293                                 g_string_append_unichar (str, g_utf8_get_char(lp));
294                                 break;
295                         }
296                         lp = g_utf8_next_char(lp);
297                 }
298                 else if ((*lp == ';') ||
299                          (*lp == ',' && !strcmp (attr->name, "CATEGORIES"))) {
300                         e_vcard_attribute_add_value (attr, str->str);
301                         g_string_assign (str, "");
302                         lp = g_utf8_next_char(lp);
303                 }
304                 else {
305                         g_string_append_unichar (str, g_utf8_get_char (lp));
306                         lp = g_utf8_next_char(lp);
307                 }
308         }
309         if (str) {
310                 e_vcard_attribute_add_value (attr, str->str);
311                 g_string_free (str, TRUE);
312         }
313
314         skip_to_next_line( &lp );
315
316         *p = lp;
317 }
318
319 static void
320 read_attribute_params (EVCardAttribute *attr, char **p, gboolean *quoted_printable)
321 {
322         char *lp;
323         GString *str;
324         EVCardAttributeParam *param = NULL;
325         gboolean in_quote = FALSE;
326
327         str = g_string_new ("");
328         for( lp =  skip_newline( *p, *quoted_printable );
329              *lp != '\n' && *lp != '\r' && *lp != '\0'; 
330              lp = skip_newline( lp, *quoted_printable ) ) {
331
332                 if (*lp == '"') {
333                         in_quote = !in_quote;
334                         lp = g_utf8_next_char (lp);
335                 }
336                 else if (in_quote || g_unichar_isalnum (g_utf8_get_char (lp)) || *lp == '-' || *lp == '_') {
337                         g_string_append_unichar (str, g_utf8_get_char (lp));
338                         lp = g_utf8_next_char (lp);
339                 }
340                 /* accumulate until we hit the '=' or ';'.  If we hit
341                  * a '=' the string contains the parameter name.  if
342                  * we hit a ';' the string contains the parameter
343                  * value and the name is either ENCODING (if value ==
344                  * QUOTED-PRINTABLE) or TYPE (in any other case.)
345                  */
346                 else if (*lp == '=') {
347                         if (str->len > 0) {
348                                 param = e_vcard_attribute_param_new (str->str);
349                                 g_string_assign (str, "");
350                                 lp = g_utf8_next_char (lp);
351                         }
352                         else {
353                                 skip_until (&lp, ":;");
354                                 if (*lp == ';') {
355                                         lp = g_utf8_next_char (lp);
356
357                                 } else if (*lp == ':') {
358                                         /* do nothing */
359
360                                 } else {                                
361                                         skip_to_next_line( &lp );
362                                         break;
363                                 }
364                         }
365                 }
366                 else if (*lp == ';' || *lp == ':' || *lp == ',') {
367                         gboolean colon = (*lp == ':');
368                         gboolean comma = (*lp == ',');
369
370                         if (param) {
371                                 if (str->len > 0) {
372                                         e_vcard_attribute_param_add_value (param, str->str);
373                                         g_string_assign (str, "");
374                                         if (!colon)
375                                                 lp = g_utf8_next_char (lp);
376                                 }
377                                 else {
378                                         /* we've got a parameter of the form:
379                                          * PARAM=(.*,)?[:;]
380                                          * so what we do depends on if there are already values
381                                          * for the parameter.  If there are, we just finish
382                                          * this parameter and skip past the offending character
383                                          * (unless it's the ':'). If there aren't values, we free
384                                          * the parameter then skip past the character.
385                                          */
386                                         if (!param->values) {
387                                                 e_vcard_attribute_param_free (param);
388                                                 param = NULL;
389                                                 if (!colon)
390                                                         lp = g_utf8_next_char (lp);
391                                         }
392                                 }
393
394                                 if (param
395                                     && !g_ascii_strcasecmp (param->name, "encoding")
396                                     && !g_ascii_strcasecmp (param->values->data, "quoted-printable")) {
397                                         *quoted_printable = TRUE;
398                                         e_vcard_attribute_param_free (param);
399                                         param = NULL;
400                                 }
401                         }
402                         else {
403                                 if (str->len > 0) {
404                                         char *param_name;
405                                         if (!g_ascii_strcasecmp (str->str,
406                                                                  "quoted-printable")) {
407                                                 param_name = "ENCODING";
408                                                 *quoted_printable = TRUE;
409                                         }
410                                         /* apple's broken addressbook app outputs naked BASE64
411                                            parameters, which aren't even vcard 3.0 compliant. */
412                                         else if (!g_ascii_strcasecmp (str->str,
413                                                                       "base64")) {
414                                                 param_name = "ENCODING";
415                                                 g_string_assign (str, "b");
416                                         }
417                                         else {
418                                                 param_name = "TYPE";
419                                         }
420
421                                         if (param_name) {
422                                                 param = e_vcard_attribute_param_new (param_name);
423                                                 e_vcard_attribute_param_add_value (param, str->str);
424                                         }
425                                         g_string_assign (str, "");
426                                         if (!colon)
427                                                 lp = g_utf8_next_char (lp);
428                                 }
429                                 else {
430                                         /* we've got an attribute with a truly empty
431                                            attribute parameter.  So it's of the form:
432                                            
433                                            ATTR;[PARAM=value;]*;[PARAM=value;]*:
434
435                                            (note the extra ';')
436
437                                            the only thing to do here is, well.. nothing.
438                                            we skip over the character if it's not a colon,
439                                            and the rest is handled for us: We'll either
440                                            continue through the loop again if we hit a ';',
441                                            or we'll break out correct below if it was a ':' */
442                                         if (!colon)
443                                                 lp = g_utf8_next_char (lp);
444                                 }
445                         }
446                         if (param && !comma) {
447                                 e_vcard_attribute_add_param (attr, param);
448                                 param = NULL;
449                         }
450                         if (colon)
451                                 break;
452                 }
453                 else {
454                         g_warning ("invalid character found in parameter spec");
455                         g_string_assign (str, "");
456                         /*                      skip_until (&lp, ":;"); */
457                         
458                         skip_to_next_line( &lp );
459                 }
460         }
461
462         if (str)
463                 g_string_free (str, TRUE);
464
465         *p = lp;
466 }
467
468 /* reads an entire attribute from the input buffer, leaving p pointing
469    at the start of the next line (past the \r\n) */
470 static EVCardAttribute*
471 read_attribute (char **p)
472 {
473         char *attr_group = NULL;
474         char *attr_name = NULL;
475         EVCardAttribute *attr = NULL;
476         GString *str;
477         char *lp;
478         gboolean is_qp = FALSE;
479
480         /* first read in the group/name */
481         str = g_string_new ("");
482         for( lp =  skip_newline( *p, is_qp );
483              *lp != '\n' && *lp != '\r' && *lp != '\0'; 
484              lp = skip_newline( lp, is_qp ) ) {
485
486                 if (*lp == ':' || *lp == ';') {
487                         if (str->len != 0) {
488                                 /* we've got a name, break out to the value/attribute parsing */
489                                 attr_name = g_string_free (str, FALSE);
490                                 break;
491                         }
492                         else {
493                                 /* a line of the form:
494                                  * (group.)?[:;]
495                                  *
496                                  * since we don't have an attribute
497                                  * name, skip to the end of the line
498                                  * and try again.
499                                  */
500                                 g_string_free (str, TRUE);
501                                 *p = lp;
502                                 skip_to_next_line(p);
503                                 goto lose;
504                         }
505                 }
506                 else if (*lp == '.') {
507                         if (attr_group) {
508                                 g_warning ("extra `.' in attribute specification.  ignoring extra group `%s'",
509                                            str->str);
510                                 g_string_free (str, TRUE);
511                                 str = g_string_new ("");
512                         }
513                         if (str->len != 0) {
514                                 attr_group = g_string_free (str, FALSE);
515                                 str = g_string_new ("");
516                         }
517                 }
518                 else if (g_unichar_isalnum (g_utf8_get_char (lp)) || *lp == '-' || *lp == '_') {
519                         g_string_append_unichar (str, g_utf8_get_char (lp));
520                 }
521                 else {
522                         g_warning ("invalid character found in attribute group/name");
523                         g_string_free (str, TRUE);
524                         *p = lp;
525                         skip_to_next_line(p);
526                         goto lose;
527                 }
528
529                 lp = g_utf8_next_char(lp);
530         }
531
532         if (!attr_name) {
533                 skip_to_next_line (p);
534                 goto lose;
535         }
536
537         attr = e_vcard_attribute_new (attr_group, attr_name);
538         g_free (attr_group);
539         g_free (attr_name);
540
541         if (*lp == ';') {
542                 /* skip past the ';' */
543                 lp = g_utf8_next_char(lp);
544                 read_attribute_params (attr, &lp, &is_qp);
545                 if (is_qp)
546                         attr->encoding = EVC_ENCODING_RAW;
547         }
548         if (*lp == ':') {
549                 /* skip past the ':' */
550                 lp = g_utf8_next_char(lp);
551                 read_attribute_value (attr, &lp, is_qp);
552         }
553
554         *p = lp;
555
556         if (!attr->values)
557                 goto lose;
558
559         return attr;
560  lose:
561         if (attr)
562                 e_vcard_attribute_free (attr);
563         return NULL;
564 }
565
566 /* Stolen from glib/glib/gconvert.c */
567 static gchar *
568 make_valid_utf8 (const gchar *name)
569 {
570         GString *string;
571         const gchar *remainder, *invalid;
572         gint remaining_bytes, valid_bytes;
573   
574         string = NULL;
575         remainder = name;
576         remaining_bytes = strlen (name);
577   
578         while (remaining_bytes != 0) {
579                 if (g_utf8_validate (remainder, remaining_bytes, &invalid)) 
580                         break;
581               valid_bytes = invalid - remainder;
582     
583                 if (string == NULL) 
584                         string = g_string_sized_new (remaining_bytes);
585
586                 g_string_append_len (string, remainder, valid_bytes);
587                 /* append U+FFFD REPLACEMENT CHARACTER */
588                 g_string_append (string, "\357\277\275");
589       
590                 remaining_bytes -= valid_bytes + 1;
591                 remainder = invalid + 1;
592         }
593   
594         if (string == NULL)
595                 return g_strdup (name);
596   
597         g_string_append (string, remainder);
598
599         g_assert (g_utf8_validate (string->str, -1, NULL));
600   
601         return g_string_free (string, FALSE);
602 }
603
604 /* we try to be as forgiving as we possibly can here - this isn't a
605  * validator.  Almost nothing is considered a fatal error.  We always
606  * try to return *something*.
607  */
608 static void
609 parse (EVCard *evc, const char *str)
610 {
611         char *buf ;
612         char *p;
613         EVCardAttribute *attr;
614         
615         buf = make_valid_utf8 (str);
616
617         //buf = fold_lines (buf);
618
619         d(printf ("BEFORE FOLDING:\n"));
620         d(printf (str));
621         d(printf ("\n\nAFTER FOLDING:\n"));
622         d(printf (buf));
623
624         p = buf;
625
626         attr = read_attribute (&p);
627         if (!attr || attr->group || g_ascii_strcasecmp (attr->name, "begin")) {
628                 g_warning ("vcard began without a BEGIN:VCARD\n");
629         }
630         if (attr && !g_ascii_strcasecmp (attr->name, "begin"))
631                 e_vcard_attribute_free (attr);
632         else if (attr)
633                 e_vcard_add_attribute (evc, attr);
634
635         while (*p) {
636                 EVCardAttribute *next_attr = read_attribute (&p);
637
638                 if (next_attr) {
639                         if (g_ascii_strcasecmp (next_attr->name, "end"))
640                                 e_vcard_add_attribute (evc, next_attr);
641                         attr = next_attr;
642                 }
643         }
644
645         if (!attr || attr->group || g_ascii_strcasecmp (attr->name, "end")) {
646                 g_warning ("vcard ended without END:VCARD\n");
647         }
648
649         if (attr && !g_ascii_strcasecmp (attr->name, "end"))
650                 e_vcard_attribute_free (attr);
651
652         g_free (buf);
653
654         evc->priv->attributes = g_list_reverse (evc->priv->attributes);
655 }
656
657 /**
658  * e_vcard_escape_string:
659  * @s: the string to escape
660  *
661  * Escapes a string according to RFC2426, section 5.
662  *
663  * Return value: A newly allocated, escaped string.
664  **/
665 char*
666 e_vcard_escape_string (const char *s)
667 {
668         GString *str;
669         const char *p;
670
671         str = g_string_new ("");
672
673         /* Escape a string as described in RFC2426, section 5 */
674         for (p = s; p && *p; p++) {
675                 switch (*p) {
676                 case '\n':
677                         g_string_append (str, "\\n");
678                         break;
679                 case '\r':
680                         if (*(p+1) == '\n')
681                                 p++;
682                         g_string_append (str, "\\n");
683                         break;
684                 case ';':
685                         g_string_append (str, "\\;");
686                         break;
687                 case ',':
688                         g_string_append (str, "\\,");
689                         break;
690                 case '\\':
691                         g_string_append (str, "\\\\");
692                         break;
693                 default:
694                         g_string_append_c (str, *p);
695                         break;
696                 }
697         }
698
699         return g_string_free (str, FALSE);
700 }
701
702 /**
703  * e_vcard_unescape_string:
704  * @s: the string to unescape
705  *
706  * Unescapes a string according to RFC2426, section 5.
707  *
708  * Return value: A newly allocated, unescaped string.
709  **/
710 char*
711 e_vcard_unescape_string (const char *s)
712 {
713         GString *str;
714         const char *p;
715
716         g_return_val_if_fail (s != NULL, NULL);
717
718         str = g_string_new ("");
719
720         /* Unescape a string as described in RFC2426, section 5 */
721         for (p = s; *p; p++) {
722                 if (*p == '\\') {
723                         p++;
724                         if (*p == '\0') {
725                                 g_string_append_c (str, '\\');
726                                 break;
727                         }
728                         switch (*p) {
729                         case 'n':  g_string_append_c (str, '\n'); break;
730                         case 'r':  g_string_append_c (str, '\r'); break;
731                         case ';':  g_string_append_c (str, ';'); break;
732                         case ',':  g_string_append_c (str, ','); break;
733                         case '\\': g_string_append_c (str, '\\'); break;
734                         default:
735                                 g_warning ("invalid escape, passing it through");
736                                 g_string_append_c (str, '\\');
737                                 g_string_append_unichar (str, g_utf8_get_char(p));
738                                 break;
739                         }
740                 }
741         }
742
743         return g_string_free (str, FALSE);
744 }
745
746 void
747 e_vcard_construct (EVCard *evc, const char *str)
748 {
749         g_return_if_fail (E_IS_VCARD (evc));
750         g_return_if_fail (str != NULL);
751
752         if (*str)
753                 parse (evc, str);
754 }
755
756 /**
757  * e_vcard_new:
758  * 
759  * Creates a new, blank #EVCard.
760  *
761  * Return value: A new, blank #EVCard.
762  **/
763 EVCard *
764 e_vcard_new (void)
765 {
766         return e_vcard_new_from_string ("");
767 }
768
769 /**
770  * e_vcard_new_from_string:
771  * @str: a string representation of the vcard to create
772  *
773  * Creates a new #EVCard from the passed-in string
774  * representation.
775  *
776  * Return value: A new #EVCard.
777  **/
778 EVCard *
779 e_vcard_new_from_string (const char *str)
780 {
781         EVCard *evc;
782
783         g_return_val_if_fail (str != NULL, NULL);
784
785         evc = g_object_new (E_TYPE_VCARD, NULL);
786
787         e_vcard_construct (evc, str);
788
789         return evc;
790 }
791
792 static char*
793 e_vcard_to_string_vcard_21  (EVCard *evc)
794 {
795         g_warning ("need to implement e_vcard_to_string_vcard_21");
796         return g_strdup ("");
797 }
798
799 static char*
800 e_vcard_to_string_vcard_30 (EVCard *evc)
801 {
802         GList *l;
803         GList *v;
804
805         GString *str = g_string_new ("");
806
807         g_string_append (str, "BEGIN:VCARD" CRLF);
808
809         /* we hardcode the version (since we're outputting to a
810            specific version) and ignore any version attributes the
811            vcard might contain */
812         g_string_append (str, "VERSION:3.0" CRLF);
813
814         for (l = evc->priv->attributes; l; l = l->next) {
815                 GList *list;
816                 EVCardAttribute *attr = l->data;
817                 GString *attr_str;
818                 glong len;
819
820                 if (!g_ascii_strcasecmp (attr->name, "VERSION"))
821                         continue;
822
823                 attr_str = g_string_new ("");
824
825                 /* From rfc2425, 5.8.2
826                  *
827                  * contentline  = [group "."] name *(";" param) ":" value CRLF
828                  */
829
830                 if (attr->group) {
831                         g_string_append (attr_str, attr->group);
832                         g_string_append_c (attr_str, '.');
833                 }
834                 g_string_append (attr_str, attr->name);
835
836                 /* handle the parameters */
837                 for (list = attr->params; list; list = list->next) {
838                         EVCardAttributeParam *param = list->data;
839                         /* 5.8.2:
840                          * param        = param-name "=" param-value *("," param-value)
841                          */
842                         g_string_append_c (attr_str, ';');
843                         g_string_append (attr_str, param->name);
844                         if (param->values) {
845                                 g_string_append_c (attr_str, '=');
846                                 for (v = param->values; v; v = v->next) {
847                                         char *value = v->data;
848                                         char *pval = value;
849                                         gboolean quotes = FALSE;
850                                         while (*pval) {
851                                                 if (!g_unichar_isalnum (g_utf8_get_char (pval))) {
852                                                         quotes = TRUE;
853                                                         break;
854                                                 }
855                                                 pval = g_utf8_next_char (pval);
856                                         }
857                                         if (quotes)
858                                                 g_string_append_c (attr_str, '"');
859                                         g_string_append (attr_str, value);
860                                         if (quotes)
861                                                 g_string_append_c (attr_str, '"');
862                                         if (v->next)
863                                                 g_string_append_c (attr_str, ',');
864                                 }
865                         }
866                 }
867
868                 g_string_append_c (attr_str, ':');
869
870                 for (v = attr->values; v; v = v->next) {
871                         char *value = v->data;
872                         char *escaped_value = NULL;
873
874                         escaped_value = e_vcard_escape_string (value);
875
876                         g_string_append (attr_str, escaped_value);
877                         if (v->next) {
878                                 /* XXX toshok - i hate you, rfc 2426.
879                                    why doesn't CATEGORIES use a ; like
880                                    a normal list attribute? */
881                                 if (!strcmp (attr->name, "CATEGORIES"))
882                                         g_string_append_c (attr_str, ',');
883                                 else
884                                         g_string_append_c (attr_str, ';');
885                         }
886
887                         g_free (escaped_value);
888                 }
889
890                 /* 5.8.2:
891                  * When generating a content line, lines longer than 75
892                  * characters SHOULD be folded
893                  */
894                 len = g_utf8_strlen (attr_str->str, -1);
895                 if (len > 75) {
896                         GString *fold_str = g_string_sized_new (attr_str->len + len/74*3);
897                         gchar *pos1 = attr_str->str;
898                         gchar *pos2 = pos1;
899                         pos2 = g_utf8_offset_to_pointer (pos2, 75);
900
901                         do {
902                                 g_string_append_len (fold_str, pos1, pos2 - pos1);
903                                 g_string_append (fold_str, CRLF " ");
904                                 pos1 = pos2;
905                                 pos2 = g_utf8_offset_to_pointer (pos2, 74);
906                         } while (pos2 < attr_str->str + attr_str->len);
907                         g_string_append (fold_str, pos1);
908                         g_string_free (attr_str, TRUE);
909                         attr_str = fold_str;
910                 }
911                 g_string_append (attr_str, CRLF);
912
913                 g_string_append (str, attr_str->str);
914                 g_string_free (attr_str, TRUE);
915         }
916
917         g_string_append (str, "END:VCARD");
918
919         return g_string_free (str, FALSE);
920 }
921
922 /**
923  * e_vcard_to_string:
924  * @evc: the #EVCard to export
925  * @format: the format to export to
926  *
927  * Exports @evc to a string representation, specified
928  * by the @format argument.
929  *
930  * Return value: A newly allocated string representing the vcard.
931  **/
932 char*
933 e_vcard_to_string (EVCard *evc, EVCardFormat format)
934 {
935         g_return_val_if_fail (E_IS_VCARD (evc), NULL);
936
937         switch (format) {
938         case EVC_FORMAT_VCARD_21:
939                 return e_vcard_to_string_vcard_21 (evc);
940         case EVC_FORMAT_VCARD_30:
941                 return e_vcard_to_string_vcard_30 (evc);
942         default:
943                 g_warning ("invalid format specifier passed to e_vcard_to_string");
944                 return g_strdup ("");
945         }
946 }
947
948 /**
949  * e_vcard_dump_structure:
950  * @evc: the #EVCard to dump
951  *
952  * Prints a dump of @evc's structure to stdout. Used for
953  * debugging.
954  **/
955 void
956 e_vcard_dump_structure (EVCard *evc)
957 {
958         GList *a;
959         GList *v;
960         int i;
961
962         g_return_if_fail (E_IS_VCARD (evc));
963
964         printf ("vCard\n");
965         for (a = evc->priv->attributes; a; a = a->next) {
966                 GList *p;
967                 EVCardAttribute *attr = a->data;
968                 printf ("+-- %s\n", attr->name);
969                 if (attr->params) {
970                         printf ("    +- params=\n");
971
972                         for (p = attr->params, i = 0; p; p = p->next, i++) {
973                                 EVCardAttributeParam *param = p->data;
974                                 printf ("    |   [%d] = %s", i,param->name);
975                                 printf ("(");
976                                 for (v = param->values; v; v = v->next) {
977                                         char *value = e_vcard_escape_string ((char*)v->data);
978                                         printf ("%s", value);
979                                         if (v->next)
980                                                 printf (",");
981                                         g_free (value);
982                                 }
983
984                                 printf (")\n");
985                         }
986                 }
987                 printf ("    +- values=\n");
988                 for (v = attr->values, i = 0; v; v = v->next, i++) {
989                         printf ("        [%d] = `%s'\n", i, (char*)v->data);
990                 }
991         }
992 }
993
994 /**
995  * e_vcard_attribute_new:
996  * @attr_group: a group name
997  * @attr_name: an attribute name
998  *
999  * Creates a new #EVCardAttribute with the specified group and
1000  * attribute names.
1001  *
1002  * Return value: A new #EVCardAttribute.
1003  **/
1004 EVCardAttribute*
1005 e_vcard_attribute_new (const char *attr_group, const char *attr_name)
1006 {
1007         EVCardAttribute *attr;
1008
1009         attr = g_slice_new0 (EVCardAttribute);
1010
1011         attr->group = g_strdup (attr_group);
1012         attr->name = g_strdup (attr_name);
1013
1014         return attr;
1015 }
1016
1017 /**
1018  * e_vcard_attribute_free:
1019  * @attr: attribute to free
1020  *
1021  * Frees an attribute, its values and its parameters.
1022  **/
1023 void
1024 e_vcard_attribute_free (EVCardAttribute *attr)
1025 {
1026         g_return_if_fail (attr != NULL);
1027
1028         g_free (attr->group);
1029         g_free (attr->name);
1030
1031         e_vcard_attribute_remove_values (attr);
1032
1033         e_vcard_attribute_remove_params (attr);
1034
1035         g_slice_free (EVCardAttribute, attr);
1036 }
1037
1038 /**
1039  * e_vcard_attribute_copy:
1040  * @attr: attribute to copy
1041  *
1042  * Makes a copy of @attr.
1043  *
1044  * Return value: A new #EVCardAttribute identical to @attr.
1045  **/
1046 EVCardAttribute*
1047 e_vcard_attribute_copy (EVCardAttribute *attr)
1048 {
1049         EVCardAttribute *a;
1050         GList *p;
1051
1052         g_return_val_if_fail (attr != NULL, NULL);
1053
1054         a = e_vcard_attribute_new (attr->group, attr->name);
1055
1056         for (p = attr->values; p; p = p->next)
1057                 e_vcard_attribute_add_value (a, p->data);
1058
1059         for (p = attr->params; p; p = p->next)
1060                 e_vcard_attribute_add_param (a, e_vcard_attribute_param_copy (p->data));
1061
1062         return a;
1063 }
1064
1065 /**
1066  * e_vcard_remove_attributes:
1067  * @evc: vcard object
1068  * @attr_group: group name of attributes to be removed
1069  * @attr_name: name of the arributes to be removed
1070  *
1071  * Removes all the attributes with group name and attribute name equal to 
1072  * passed in values. If @attr_group is %NULL or an empty string,
1073  * it removes all the attributes with passed in name irrespective of
1074  * their group names.
1075  **/
1076 void
1077 e_vcard_remove_attributes (EVCard *evc, const char *attr_group, const char *attr_name)
1078 {
1079         GList *attr;
1080
1081         g_return_if_fail (E_IS_VCARD (evc));
1082         g_return_if_fail (attr_name != NULL);
1083
1084         attr = evc->priv->attributes;
1085         while (attr) {
1086                 GList *next_attr;
1087                 EVCardAttribute *a = attr->data;
1088
1089                 next_attr = attr->next;
1090
1091                 if (((!attr_group || *attr_group == '\0') ||
1092                      (attr_group && !g_ascii_strcasecmp (attr_group, a->group))) &&
1093                     ((!attr_name && !a->name) || !g_ascii_strcasecmp (attr_name, a->name))) {
1094
1095                         /* matches, remove/delete the attribute */
1096                         evc->priv->attributes = g_list_delete_link (evc->priv->attributes, attr);
1097
1098                         e_vcard_attribute_free (a);
1099                 }
1100
1101                 attr = next_attr;
1102         }
1103 }
1104
1105 /**
1106  * e_vcard_remove_attribute:
1107  * @evc: an #EVCard
1108  * @attr: an #EVCardAttribute to remove
1109  *
1110  * Removes @attr from @evc and frees it.
1111  **/
1112 void
1113 e_vcard_remove_attribute (EVCard *evc, EVCardAttribute *attr)
1114 {
1115         g_return_if_fail (E_IS_VCARD (evc));
1116         g_return_if_fail (attr != NULL);
1117
1118         evc->priv->attributes = g_list_remove (evc->priv->attributes, attr);
1119         e_vcard_attribute_free (attr);
1120 }
1121
1122 /**
1123  * e_vcard_add_attribute:
1124  * @evc: an #EVCard
1125  * @attr: an #EVCardAttribute to add
1126  *
1127  * Adds @attr to @evc.
1128  **/
1129 void
1130 e_vcard_add_attribute (EVCard *evc, EVCardAttribute *attr)
1131 {
1132         g_return_if_fail (E_IS_VCARD (evc));
1133         g_return_if_fail (attr != NULL);
1134
1135         evc->priv->attributes = g_list_prepend (evc->priv->attributes, attr);
1136 }
1137
1138 /**
1139  * e_vcard_add_attribute_with_value:
1140  * @evcard: an #EVCard
1141  * @attr: an #EVCardAttribute to add
1142  * @value: a value to assign to the attribute
1143  *
1144  * Adds @attr to @evcard, setting it to @value.
1145  **/
1146 void
1147 e_vcard_add_attribute_with_value (EVCard *evcard,
1148                                   EVCardAttribute *attr, const char *value)
1149 {
1150         g_return_if_fail (E_IS_VCARD (evcard));
1151         g_return_if_fail (attr != NULL);
1152
1153         e_vcard_attribute_add_value (attr, value);
1154
1155         e_vcard_add_attribute (evcard, attr);
1156 }
1157
1158 /**
1159  * e_vcard_add_attribute_with_values:
1160  * @evcard: an @EVCard
1161  * @attr: an #EVCardAttribute to add
1162  * @...: a %NULL-terminated list of values to assign to the attribute
1163  *
1164  * Adds @attr to @evcard, assigning the list of values to it.
1165  **/
1166 void
1167 e_vcard_add_attribute_with_values (EVCard *evcard, EVCardAttribute *attr, ...)
1168 {
1169         va_list ap;
1170         char *v;
1171
1172         g_return_if_fail (E_IS_VCARD (evcard));
1173         g_return_if_fail (attr != NULL);
1174
1175         va_start (ap, attr);
1176
1177         while ((v = va_arg (ap, char*))) {
1178                 e_vcard_attribute_add_value (attr, v);
1179         }
1180
1181         va_end (ap);
1182
1183         e_vcard_add_attribute (evcard, attr);
1184 }
1185
1186 /**
1187  * e_vcard_attribute_add_value:
1188  * @attr: an #EVCardAttribute
1189  * @value: a string value
1190  *
1191  * Adds @value to @attr's list of values.
1192  **/
1193 void
1194 e_vcard_attribute_add_value (EVCardAttribute *attr, const char *value)
1195 {
1196         g_return_if_fail (attr != NULL);
1197
1198         attr->values = g_list_append (attr->values, g_strdup (value));
1199 }
1200
1201 /**
1202  * e_vcard_attribute_add_value_decoded:
1203  * @attr: an #EVCardAttribute
1204  * @value: an encoded value
1205  * @len: the length of the encoded value, in bytes
1206  *
1207  * Decodes @value according to the encoding used for @attr, and
1208  * adds it to @attr's list of values.
1209  **/
1210 void
1211 e_vcard_attribute_add_value_decoded (EVCardAttribute *attr, const char *value, int len)
1212 {
1213         g_return_if_fail (attr != NULL);
1214
1215         switch (attr->encoding) {
1216         case EVC_ENCODING_RAW:
1217                 g_warning ("can't add_value_decoded with an attribute using RAW encoding.  you must set the ENCODING parameter first");
1218                 break;
1219         case EVC_ENCODING_BASE64: {
1220                 char *b64_data = _evc_base64_encode_simple (value, len);
1221                 GString *decoded = g_string_new_len (value, len);
1222
1223                 /* make sure the decoded list is up to date */
1224                 e_vcard_attribute_get_values_decoded (attr);
1225
1226                 d(printf ("base64 encoded value: %s\n", b64_data));
1227                 d(printf ("original length: %d\n", len));
1228
1229                 attr->values = g_list_append (attr->values, b64_data);
1230                 attr->decoded_values = g_list_append (attr->decoded_values, decoded);
1231                 break;
1232         }
1233         case EVC_ENCODING_QP:
1234                 g_warning ("need to implement quoted printable decoding");
1235                 break;
1236         }
1237 }
1238
1239 /**
1240  * e_vcard_attribute_add_values:
1241  * @attr: an #EVCardAttribute
1242  * @Varargs: a %NULL-terminated list of strings
1243  *
1244  * Adds a list of values to @attr.
1245  **/
1246 void
1247 e_vcard_attribute_add_values (EVCardAttribute *attr,
1248                               ...)
1249 {
1250         va_list ap;
1251         char *v;
1252
1253         g_return_if_fail (attr != NULL);
1254
1255         va_start (ap, attr);
1256
1257         while ((v = va_arg (ap, char*))) {
1258                 e_vcard_attribute_add_value (attr, v);
1259         }
1260
1261         va_end (ap);
1262 }
1263
1264 static void
1265 free_gstring (GString *str)
1266 {
1267         g_string_free (str, TRUE);
1268 }
1269
1270 /**
1271  * e_vcard_attribute_remove_values:
1272  * @attr: an #EVCardAttribute
1273  *
1274  * Removes all values from @attr.
1275  **/
1276 void
1277 e_vcard_attribute_remove_values (EVCardAttribute *attr)
1278 {
1279         g_return_if_fail (attr != NULL);
1280
1281         g_list_foreach (attr->values, (GFunc)g_free, NULL);
1282         g_list_free (attr->values);
1283         attr->values = NULL;
1284
1285         g_list_foreach (attr->decoded_values, (GFunc)free_gstring, NULL);
1286         g_list_free (attr->decoded_values);
1287         attr->decoded_values = NULL;
1288 }
1289
1290 /**
1291  * e_vcard_attribute_remove_value:
1292  * @attr: an #EVCardAttribute
1293  * @s: an value to remove
1294  *
1295  * Removes from the value list in @attr the value @s.
1296  **/
1297 void
1298 e_vcard_attribute_remove_value (EVCardAttribute *attr, const char *s)
1299 {
1300         GList *l;
1301
1302         g_return_if_fail (attr != NULL);
1303         g_return_if_fail (s != NULL);
1304
1305         l = g_list_find_custom (attr->values, s, (GCompareFunc)strcmp);
1306         if (l == NULL) {
1307                 return;
1308         }
1309         
1310         attr->values = g_list_delete_link (attr->values, l);
1311 }
1312
1313 /**
1314  * e_vcard_attribute_remove_param:
1315  * @attr: an #EVCardAttribute
1316  * @param_name: a parameter name
1317  *
1318  * Removes the parameter @param_name from the attribute @attr.
1319  *
1320  * Since 1.11.3.
1321  */
1322 void
1323 e_vcard_attribute_remove_param (EVCardAttribute *attr, const char *param_name)
1324 {
1325         GList *l;
1326         EVCardAttributeParam *param;
1327
1328         g_return_if_fail (attr != NULL);
1329         g_return_if_fail (param_name != NULL);
1330         
1331         for (l = attr->params; l; l = l->next) {
1332                 param = l->data;
1333                 if (g_ascii_strcasecmp (e_vcard_attribute_param_get_name (param),
1334                                         param_name) == 0) {
1335                         attr->params = g_list_delete_link (attr->params, l);
1336                         e_vcard_attribute_param_free(param);
1337                         break;
1338                 }
1339         }
1340 }
1341
1342 /**
1343  * e_vcard_attribute_remove_params:
1344  * @attr: an #EVCardAttribute
1345  *
1346  * Removes all parameters from @attr.
1347  **/
1348 void
1349 e_vcard_attribute_remove_params (EVCardAttribute *attr)
1350 {
1351         g_return_if_fail (attr != NULL);
1352
1353         g_list_foreach (attr->params, (GFunc)e_vcard_attribute_param_free, NULL);
1354         g_list_free (attr->params);
1355         attr->params = NULL;
1356
1357         /* also remove the cached encoding on this attribute */
1358         attr->encoding_set = FALSE;
1359         attr->encoding = EVC_ENCODING_RAW;
1360 }
1361
1362 /**
1363  * e_vcard_attribute_param_new:
1364  * @name: the name of the new parameter
1365  *
1366  * Creates a new parameter named @name.
1367  *
1368  * Return value: A new #EVCardAttributeParam.
1369  **/
1370 EVCardAttributeParam*
1371 e_vcard_attribute_param_new (const char *name)
1372 {
1373         EVCardAttributeParam *param = g_slice_new (EVCardAttributeParam);
1374         param->values = NULL;
1375         param->name = g_strdup (name);
1376
1377         return param;
1378 }
1379
1380 /**
1381  * e_vcard_attribute_param_free:
1382  * @param: an #EVCardAttributeParam
1383  *
1384  * Frees @param and its values.
1385  **/
1386 void
1387 e_vcard_attribute_param_free (EVCardAttributeParam *param)
1388 {
1389         g_return_if_fail (param != NULL);
1390
1391         g_free (param->name);
1392
1393         e_vcard_attribute_param_remove_values (param);
1394
1395         g_slice_free (EVCardAttributeParam, param);
1396 }
1397
1398 /**
1399  * e_vcard_attribute_param_copy:
1400  * @param: an #EVCardAttributeParam
1401  *
1402  * Makes a copy of @param.
1403  *
1404  * Return value: a new #EVCardAttributeParam identical to @param.
1405  **/
1406 EVCardAttributeParam*
1407 e_vcard_attribute_param_copy (EVCardAttributeParam *param)
1408 {
1409         EVCardAttributeParam *p;
1410         GList *l;
1411
1412         g_return_val_if_fail (param != NULL, NULL);
1413
1414         p = e_vcard_attribute_param_new (e_vcard_attribute_param_get_name (param));
1415
1416         for (l = param->values; l; l = l->next) {
1417                 e_vcard_attribute_param_add_value (p, l->data);
1418         }
1419
1420         return p;
1421 }
1422
1423 /**
1424  * e_vcard_attribute_add_param:
1425  * @attr: an #EVCardAttribute
1426  * @param: an #EVCardAttributeParam to add
1427  *
1428  * Adds @param to @attr's list of parameters.
1429  * It tests for duplicities, only new parameters are added,
1430  * when a new parameter already exists in attr, then those
1431  * values are merged, also without creating duplicities.
1432  * When we will not add whole param, then it's freed here.
1433  **/
1434 void
1435 e_vcard_attribute_add_param (EVCardAttribute *attr,
1436                              EVCardAttributeParam *param)
1437 {
1438         gboolean contains;
1439         GList *params, *p;
1440         const char *par_name;
1441
1442         g_return_if_fail (attr != NULL);
1443         g_return_if_fail (param != NULL);
1444
1445         contains = FALSE;
1446         params = attr->params;
1447         par_name = param->name;
1448  
1449         for (p = params; p; p = p->next) {
1450                 EVCardAttributeParam *param2 = p->data;
1451                 if (g_ascii_strcasecmp (param2->name, par_name) == 0) {
1452                         /* param2 has same name as our new param;
1453                            better merge them than have more parameters
1454                            with same name within one attribute.
1455                         */
1456                         GList *vals,*v;
1457
1458                         vals = param->values;
1459
1460                         for (v = vals; v; v = v->next) {
1461                                 const char *my_value;
1462                                 GList *vals2,*v2;
1463
1464                                 my_value = (const char *)v->data;
1465                                 vals2 = param2->values;
1466
1467                                 for (v2 = vals2; v2; v2 = v2->next) {
1468                                         if (g_ascii_strcasecmp ((const char *)v2->data, my_value) == 0) {
1469                                                 break;
1470                                         }
1471                                 }
1472
1473                                 if (!v2) {
1474                                         /* we did loop through all values and none of them was my_value */
1475                                         e_vcard_attribute_param_add_value (param2, my_value);
1476                                 }
1477                         }
1478
1479                         contains = TRUE;
1480                         break;
1481                 }
1482         }
1483         
1484         if (!contains) {
1485                 attr->params = g_list_prepend (attr->params, param);
1486         }
1487
1488         /* we handle our special encoding stuff here */
1489
1490         if (!g_ascii_strcasecmp (param->name, EVC_ENCODING)) {
1491                 if (attr->encoding_set) {
1492                         g_warning ("ENCODING specified twice");
1493                         if (contains) {
1494                                 e_vcard_attribute_param_free (param);
1495                         }
1496                         return;
1497                 }
1498
1499                 if (param->values && param->values->data) {
1500                         if (!g_ascii_strcasecmp ((char*)param->values->data, "b") ||
1501                             !g_ascii_strcasecmp ((char*)param->values->data, "BASE64"))
1502                                 attr->encoding = EVC_ENCODING_BASE64;
1503                         else if (!g_ascii_strcasecmp ((char*)param->values->data, EVC_QUOTEDPRINTABLE))
1504                                 attr->encoding = EVC_ENCODING_QP;
1505                         else {
1506                                 g_warning ("Unknown value `%s' for ENCODING parameter.  values will be treated as raw",
1507                                            (char*)param->values->data);
1508                         }
1509
1510                         attr->encoding_set = TRUE;
1511                 }
1512                 else {
1513                         g_warning ("ENCODING parameter added with no value");
1514                 }
1515         }
1516
1517         if (contains) {
1518                 e_vcard_attribute_param_free (param);
1519         }
1520 }
1521
1522 /**
1523  * e_vcard_attribute_param_add_value:
1524  * @param: an #EVCardAttributeParam
1525  * @value: a string value to add
1526  *
1527  * Adds @value to @param's list of values.
1528  **/
1529 void
1530 e_vcard_attribute_param_add_value (EVCardAttributeParam *param,
1531                                    const char *value)
1532 {
1533         g_return_if_fail (param != NULL);
1534
1535         param->values = g_list_append (param->values, g_strdup (value));
1536 }
1537
1538 /**
1539  * e_vcard_attribute_param_add_values:
1540  * @param: an #EVCardAttributeParam
1541  * @Varargs: a %NULL-terminated list of strings
1542  *
1543  * Adds a list of values to @param.
1544  **/
1545 void
1546 e_vcard_attribute_param_add_values (EVCardAttributeParam *param,
1547                                     ...)
1548 {
1549         va_list ap;
1550         char *v;
1551
1552         g_return_if_fail (param != NULL);
1553
1554         va_start (ap, param);
1555
1556         while ((v = va_arg (ap, char*))) {
1557                 e_vcard_attribute_param_add_value (param, v);
1558         }
1559
1560         va_end (ap);
1561 }
1562
1563 /**
1564  * e_vcard_attribute_add_param_with_value:
1565  * @attr: an #EVCardAttribute
1566  * @param: an #EVCardAttributeParam
1567  * @value: a string value
1568  *
1569  * Adds @value to @param, then adds @param to @attr.
1570  **/
1571 void
1572 e_vcard_attribute_add_param_with_value (EVCardAttribute *attr,
1573                                         EVCardAttributeParam *param, const char *value)
1574 {
1575         g_return_if_fail (attr != NULL);
1576         g_return_if_fail (param != NULL);
1577
1578         e_vcard_attribute_param_add_value (param, value);
1579
1580         e_vcard_attribute_add_param (attr, param);
1581 }
1582
1583 /**
1584  * e_vcard_attribute_add_param_with_values:
1585  * @attr: an #EVCardAttribute
1586  * @param: an #EVCardAttributeParam
1587  * @Varargs: a %NULL-terminated list of strings
1588  *
1589  * Adds the list of values to @param, then adds @param
1590  * to @attr.
1591  **/
1592 void
1593 e_vcard_attribute_add_param_with_values (EVCardAttribute *attr,
1594                                          EVCardAttributeParam *param, ...)
1595 {
1596         va_list ap;
1597         char *v;
1598
1599         g_return_if_fail (attr != NULL);
1600         g_return_if_fail (param != NULL);
1601
1602         va_start (ap, param);
1603
1604         while ((v = va_arg (ap, char*))) {
1605                 e_vcard_attribute_param_add_value (param, v);
1606         }
1607
1608         va_end (ap);
1609
1610         e_vcard_attribute_add_param (attr, param);
1611 }
1612
1613 /**
1614  * e_vcard_attribute_param_remove_values:
1615  * @param: an #EVCardAttributeParam
1616  *
1617  * Removes and frees all values from @param.
1618  **/
1619 void
1620 e_vcard_attribute_param_remove_values (EVCardAttributeParam *param)
1621 {
1622         g_return_if_fail (param != NULL);
1623
1624         g_list_foreach (param->values, (GFunc)g_free, NULL);
1625         g_list_free (param->values);
1626         param->values = NULL;
1627 }
1628
1629 /**
1630  * e_vcard_attribute_remove_param_value:
1631  * @attr: an #EVCardAttribute
1632  * @param_name: a parameter name
1633  * @s: a value
1634  *
1635  * Removes the value @s from the parameter @param_name on the attribute @attr.
1636  **/
1637 void
1638 e_vcard_attribute_remove_param_value (EVCardAttribute *attr, const char *param_name, const char *s)
1639 {
1640         GList *l, *params;
1641         EVCardAttributeParam *param;
1642
1643         g_return_if_fail (attr != NULL);
1644         g_return_if_fail (param_name != NULL);
1645         g_return_if_fail (s != NULL);
1646
1647         params = e_vcard_attribute_get_params (attr);
1648
1649         for (l = params; l; l = l->next) {
1650                 param = l->data;
1651                 if (g_ascii_strcasecmp (e_vcard_attribute_param_get_name (param), param_name) == 0) {
1652                         l = g_list_find_custom (param->values, s, (GCompareFunc)strcmp);
1653                         if (l == NULL) {
1654                                 return;
1655                         }
1656                         
1657                         param->values = g_list_delete_link (param->values, l);
1658                         if (param->values == NULL) {
1659                                 e_vcard_attribute_param_free (param);
1660                                 attr->params = g_list_remove (attr->params, param);
1661                         }
1662                         break;
1663                 }
1664         }
1665         return;
1666 }
1667
1668 /**
1669  * e_vcard_get_attributes:
1670  * @evcard: an #EVCard
1671  *
1672  * Gets the list of attributes from @evcard. The list and its
1673  * contents are owned by @evcard, and must not be freed.
1674  *
1675  * Return value: A list of attributes of type #EVCardAttribute.
1676  **/
1677 GList*
1678 e_vcard_get_attributes (EVCard *evcard)
1679 {
1680         g_return_val_if_fail (E_IS_VCARD (evcard), NULL);
1681
1682         return evcard->priv->attributes;
1683 }
1684
1685 /**
1686  * e_vcard_get_attribute:
1687  * @evc: an #EVCard
1688  * @name: the name of the attribute to get
1689  *
1690  * Get the attribute @name from @evc.  The #EVCardAttribute is owned by
1691  * @evcard and should not be freed. If the attribute does not exist, #NULL is
1692  * returned.
1693  *
1694  * Return value: An #EVCardAttribute if found, or #NULL.
1695  **/
1696 EVCardAttribute *
1697 e_vcard_get_attribute (EVCard     *evc,
1698                        const char *name)
1699 {
1700         GList *attrs, *l;
1701
1702         g_return_val_if_fail (E_IS_VCARD (evc), NULL);
1703         g_return_val_if_fail (name != NULL, NULL);
1704
1705         attrs = e_vcard_get_attributes (evc);
1706         for (l = attrs; l; l = l->next) {
1707                 EVCardAttribute *attr;
1708                 
1709                 attr = (EVCardAttribute *) l->data;
1710                 if (strcmp (attr->name, name) == 0)
1711                         return attr;
1712         }
1713
1714         return NULL;
1715 }
1716 /**
1717  * e_vcard_attribute_get_group:
1718  * @attr: an #EVCardAttribute
1719  *
1720  * Gets the group name of @attr.
1721  *
1722  * Return value: The attribute's group name.
1723  **/
1724 const char*
1725 e_vcard_attribute_get_group (EVCardAttribute *attr)
1726 {
1727         g_return_val_if_fail (attr != NULL, NULL);
1728
1729         return attr->group;
1730 }
1731
1732 /**
1733  * e_vcard_attribute_get_name:
1734  * @attr: an #EVCardAttribute
1735  *
1736  * Gets the name of @attr.
1737  *
1738  * Return value: The attribute's name.
1739  **/
1740 const char*
1741 e_vcard_attribute_get_name (EVCardAttribute *attr)
1742 {
1743         g_return_val_if_fail (attr != NULL, NULL);
1744
1745         return attr->name;
1746 }
1747
1748 /**
1749  * e_vcard_attribute_get_values:
1750  * @attr: an #EVCardAttribute
1751  *
1752  * Gets the list of values from @attr. The list and its
1753  * contents are owned by @attr, and must not be freed.
1754  * 
1755  * Return value: A list of string values.
1756  **/
1757 GList*
1758 e_vcard_attribute_get_values (EVCardAttribute *attr)
1759 {
1760         g_return_val_if_fail (attr != NULL, NULL);
1761
1762         return attr->values;
1763 }
1764
1765 /**
1766  * e_vcard_attribute_get_values_decoded:
1767  * @attr: an #EVCardAttribute
1768  *
1769  * Gets the list of values from @attr, decoding them if
1770  * necessary. The list and its contents are owned by @attr,
1771  * and must not be freed.
1772  *
1773  * Return value: A list of values of type #GString.
1774  **/
1775 GList*
1776 e_vcard_attribute_get_values_decoded (EVCardAttribute *attr)
1777 {
1778         g_return_val_if_fail (attr != NULL, NULL);
1779
1780         if (!attr->decoded_values) {
1781                 GList *l;
1782                 switch (attr->encoding) {
1783                 case EVC_ENCODING_RAW:
1784                         for (l = attr->values; l; l = l->next)
1785                                 attr->decoded_values = g_list_prepend (attr->decoded_values, g_string_new ((char*)l->data));
1786                         attr->decoded_values = g_list_reverse (attr->decoded_values);
1787                         break;
1788                 case EVC_ENCODING_BASE64:
1789                         for (l = attr->values; l; l = l->next) {
1790                                 char *decoded = g_strdup ((char*)l->data);
1791                                 int len = _evc_base64_decode_simple (decoded, strlen (decoded));
1792                                 attr->decoded_values = g_list_prepend (attr->decoded_values, g_string_new_len (decoded, len));
1793                                 g_free (decoded);
1794                         }
1795                         attr->decoded_values = g_list_reverse (attr->decoded_values);
1796                         break;
1797                 case EVC_ENCODING_QP:
1798                         g_warning ("need to implement quoted printable decoding");
1799                         break;
1800                 }
1801         }
1802
1803         return attr->decoded_values;
1804 }
1805
1806 /**
1807  * e_vcard_attribute_is_single_valued:
1808  * @attr: an #EVCardAttribute
1809  *
1810  * Checks if @attr has a single value.
1811  *
1812  * Return value: %TRUE if the attribute has exactly one value, %FALSE otherwise.
1813  **/
1814 gboolean
1815 e_vcard_attribute_is_single_valued (EVCardAttribute *attr)
1816 {
1817         g_return_val_if_fail (attr != NULL, FALSE);
1818
1819         if (attr->values == NULL
1820             || attr->values->next != NULL)
1821                 return FALSE;
1822
1823         return TRUE;
1824 }
1825
1826 /**
1827  * e_vcard_attribute_get_value:
1828  * @attr: an #EVCardAttribute
1829  *
1830  * Gets the value of a single-valued #EVCardAttribute, @attr.
1831  *
1832  * Return value: A newly allocated string representing the value.
1833  **/
1834 char*
1835 e_vcard_attribute_get_value (EVCardAttribute *attr)
1836 {
1837         GList *values;
1838
1839         g_return_val_if_fail (attr != NULL, NULL);
1840
1841         values = e_vcard_attribute_get_values (attr);
1842
1843         if (!e_vcard_attribute_is_single_valued (attr))
1844                 g_warning ("e_vcard_attribute_get_value called on multivalued attribute");
1845
1846         return values ? g_strdup ((char*)values->data) : NULL;
1847 }
1848
1849 /**
1850  * e_vcard_attribute_get_value_decoded:
1851  * @attr: an #EVCardAttribute
1852  *
1853  * Gets the value of a single-valued #EVCardAttribute, @attr, decoding
1854  * it if necessary.
1855  *
1856  * Note: this function seems currently to be unused. Could be removed.
1857  *
1858  * Return value: A newly allocated #GString representing the value.
1859  **/
1860 GString*
1861 e_vcard_attribute_get_value_decoded (EVCardAttribute *attr)
1862 {
1863         GList *values;
1864         GString *str = NULL;
1865
1866         g_return_val_if_fail (attr != NULL, NULL);
1867
1868         values = e_vcard_attribute_get_values_decoded (attr);
1869
1870         if (!e_vcard_attribute_is_single_valued (attr))
1871                 g_warning ("e_vcard_attribute_get_value_decoded called on multivalued attribute");
1872
1873         if (values)
1874                 str = values->data;
1875
1876         return str ? g_string_new_len (str->str, str->len) : NULL;
1877 }
1878
1879 /**
1880  * e_vcard_attribute_has_type:
1881  * @attr: an #EVCardAttribute
1882  * @typestr: a string representing the type
1883  *
1884  * Checks if @attr has an #EVCardAttributeParam of the specified type.
1885  *
1886  * Return value: %TRUE if such a parameter exists, %FALSE otherwise.
1887  **/
1888 gboolean
1889 e_vcard_attribute_has_type (EVCardAttribute *attr, const char *typestr)
1890 {
1891         GList *params;
1892         GList *p;
1893
1894         g_return_val_if_fail (attr != NULL, FALSE);
1895         g_return_val_if_fail (typestr != NULL, FALSE);
1896
1897         params = e_vcard_attribute_get_params (attr);
1898
1899         for (p = params; p; p = p->next) {
1900                 EVCardAttributeParam *param = p->data;
1901
1902                 if (!g_ascii_strcasecmp (e_vcard_attribute_param_get_name (param), EVC_TYPE)) {
1903                         GList *values = e_vcard_attribute_param_get_values (param);
1904                         GList *v;
1905
1906                         for (v = values; v; v = v->next) {
1907                                 if (!g_ascii_strcasecmp ((char*)v->data, typestr))
1908                                         return TRUE;
1909                         }
1910                 }
1911         }
1912
1913         return FALSE;
1914 }
1915
1916 /**
1917  * e_vcard_attribute_get_params:
1918  * @attr: an #EVCardAttribute
1919  * 
1920  * Gets the list of parameters from @attr. The list and its
1921  * contents are owned by @attr, and must not be freed.
1922  *
1923  * Return value: A list of elements of type #EVCardAttributeParam.
1924  **/
1925 GList*
1926 e_vcard_attribute_get_params (EVCardAttribute *attr)
1927 {
1928         g_return_val_if_fail (attr != NULL, NULL);
1929
1930         return attr->params;
1931 }
1932
1933 /**
1934  * e_vcard_attribute_get_param:
1935  * @attr: an #EVCardAttribute
1936  * @name: a parameter name
1937  * 
1938  * Gets the list of values for the paramater @name from @attr. The list and its
1939  * contents are owned by @attr, and must not be freed.
1940  *
1941  * Return value: A list of string elements representing the parameter's values.
1942  **/
1943 GList *
1944 e_vcard_attribute_get_param (EVCardAttribute *attr, const char *name)
1945 {
1946         GList *params, *p;
1947         
1948         g_return_val_if_fail (attr != NULL, NULL);
1949         g_return_val_if_fail (name != NULL, NULL);
1950         
1951         params = e_vcard_attribute_get_params (attr);
1952
1953         for (p = params; p; p = p->next) {
1954                 EVCardAttributeParam *param = p->data;
1955                 if (g_ascii_strcasecmp (e_vcard_attribute_param_get_name (param), name) == 0) {
1956                         return e_vcard_attribute_param_get_values (param);
1957                 }
1958         }
1959
1960         return NULL;
1961 }
1962
1963 /**
1964  * e_vcard_attribute_param_get_name:
1965  * @param: an #EVCardAttributeParam
1966  *
1967  * Gets the name of @param.
1968  *
1969  * Return value: The name of the parameter.
1970  **/
1971 const char*
1972 e_vcard_attribute_param_get_name (EVCardAttributeParam *param)
1973 {
1974         g_return_val_if_fail (param != NULL, NULL);
1975
1976         return param->name;
1977 }
1978
1979 /**
1980  * e_vcard_attribute_param_get_values:
1981  * @param: an #EVCardAttributeParam
1982  * 
1983  * Gets the list of values from @param. The list and its
1984  * contents are owned by @param, and must not be freed.
1985  *
1986  * Return value: A list of string elements representing the parameter's values.
1987  **/
1988 GList*
1989 e_vcard_attribute_param_get_values (EVCardAttributeParam *param)
1990 {
1991         g_return_val_if_fail (param != NULL, NULL);
1992
1993         return param->values;
1994 }
1995
1996 \f
1997
1998 /* encoding/decoding stuff ripped from camel-mime-utils.c */
1999
2000 static char *_evc_base64_alphabet =
2001 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2002
2003 static unsigned char _evc_base64_rank[256];
2004
2005 static void
2006 _evc_base64_init(void)
2007 {
2008         int i;
2009
2010         memset(_evc_base64_rank, 0xff, sizeof(_evc_base64_rank));
2011         for (i=0;i<64;i++) {
2012                 _evc_base64_rank[(unsigned int)_evc_base64_alphabet[i]] = i;
2013         }
2014         _evc_base64_rank['='] = 0;
2015 }
2016
2017 /* call this when finished encoding everything, to
2018    flush off the last little bit */
2019 static size_t
2020 _evc_base64_encode_close(unsigned char *in, size_t inlen, gboolean break_lines, unsigned char *out, int *state, int *save)
2021 {
2022         int c1, c2;
2023         unsigned char *outptr = out;
2024
2025         if (inlen>0)
2026                 outptr += _evc_base64_encode_step(in, inlen, break_lines, outptr, state, save);
2027
2028         c1 = ((unsigned char *)save)[1];
2029         c2 = ((unsigned char *)save)[2];
2030         
2031         d(printf("mode = %d\nc1 = %c\nc2 = %c\n",
2032                  (int)((char *)save)[0],
2033                  (int)((char *)save)[1],
2034                  (int)((char *)save)[2]));
2035
2036         switch (((char *)save)[0]) {
2037         case 2:
2038                 outptr[2] = _evc_base64_alphabet[ ( (c2 &0x0f) << 2 ) ];
2039                 g_assert(outptr[2] != 0);
2040                 goto skip;
2041         case 1:
2042                 outptr[2] = '=';
2043         skip:
2044                 outptr[0] = _evc_base64_alphabet[ c1 >> 2 ];
2045                 outptr[1] = _evc_base64_alphabet[ c2 >> 4 | ( (c1&0x3) << 4 )];
2046                 outptr[3] = '=';
2047                 outptr += 4;
2048                 break;
2049         }
2050         if (break_lines)
2051                 *outptr++ = '\n';
2052
2053         *save = 0;
2054         *state = 0;
2055
2056         return outptr-out;
2057 }
2058
2059 /*
2060   performs an 'encode step', only encodes blocks of 3 characters to the
2061   output at a time, saves left-over state in state and save (initialise to
2062   0 on first invocation).
2063 */
2064 static size_t
2065 _evc_base64_encode_step(unsigned char *in, size_t len, gboolean break_lines, unsigned char *out, int *state, int *save)
2066 {
2067         register unsigned char *inptr, *outptr;
2068
2069         if (len<=0)
2070                 return 0;
2071
2072         inptr = in;
2073         outptr = out;
2074
2075         d(printf("we have %d chars, and %d saved chars\n", len, ((char *)save)[0]));
2076
2077         if (len + ((char *)save)[0] > 2) {
2078                 unsigned char *inend = in+len-2;
2079                 register int c1, c2, c3;
2080                 register int already;
2081
2082                 already = *state;
2083
2084                 switch (((char *)save)[0]) {
2085                 case 1: c1 = ((unsigned char *)save)[1]; goto skip1;
2086                 case 2: c1 = ((unsigned char *)save)[1];
2087                         c2 = ((unsigned char *)save)[2]; goto skip2;
2088                 }
2089                 
2090                 /* yes, we jump into the loop, no i'm not going to change it, it's beautiful! */
2091                 while (inptr < inend) {
2092                         c1 = *inptr++;
2093                 skip1:
2094                         c2 = *inptr++;
2095                 skip2:
2096                         c3 = *inptr++;
2097                         *outptr++ = _evc_base64_alphabet[ c1 >> 2 ];
2098                         *outptr++ = _evc_base64_alphabet[ c2 >> 4 | ( (c1&0x3) << 4 ) ];
2099                         *outptr++ = _evc_base64_alphabet[ ( (c2 &0x0f) << 2 ) | (c3 >> 6) ];
2100                         *outptr++ = _evc_base64_alphabet[ c3 & 0x3f ];
2101                         /* this is a bit ugly ... */
2102                         if (break_lines && (++already)>=19) {
2103                                 *outptr++='\n';
2104                                 already = 0;
2105                         }
2106                 }
2107
2108                 ((char *)save)[0] = 0;
2109                 len = 2-(inptr-inend);
2110                 *state = already;
2111         }
2112
2113         d(printf("state = %d, len = %d\n",
2114                  (int)((char *)save)[0],
2115                  len));
2116
2117         if (len>0) {
2118                 register char *saveout;
2119
2120                 /* points to the slot for the next char to save */
2121                 saveout = & (((char *)save)[1]) + ((char *)save)[0];
2122
2123                 /* len can only be 0 1 or 2 */
2124                 switch(len) {
2125                 case 2: *saveout++ = *inptr++;
2126                 case 1: *saveout++ = *inptr++;
2127                 }
2128                 ((char *)save)[0]+=len;
2129         }
2130
2131         d(printf("mode = %d\nc1 = %c\nc2 = %c\n",
2132                  (int)((char *)save)[0],
2133                  (int)((char *)save)[1],
2134                  (int)((char *)save)[2]));
2135
2136         return outptr-out;
2137 }
2138
2139
2140 /**
2141  * base64_decode_step: decode a chunk of base64 encoded data
2142  * @in: input stream
2143  * @len: max length of data to decode
2144  * @out: output stream
2145  * @state: holds the number of bits that are stored in @save
2146  * @save: leftover bits that have not yet been decoded
2147  *
2148  * Decodes a chunk of base64 encoded data
2149  **/
2150 static size_t
2151 _evc_base64_decode_step(unsigned char *in, size_t len, unsigned char *out, int *state, unsigned int *save)
2152 {
2153         register unsigned char *inptr, *outptr;
2154         unsigned char *inend, c;
2155         register unsigned int v;
2156         int i;
2157
2158         inend = in+len;
2159         outptr = out;
2160
2161         /* convert 4 base64 bytes to 3 normal bytes */
2162         v=*save;
2163         i=*state;
2164         inptr = in;
2165         while (inptr<inend) {
2166                 c = _evc_base64_rank[*inptr++];
2167                 if (c != 0xff) {
2168                         v = (v<<6) | c;
2169                         i++;
2170                         if (i==4) {
2171                                 *outptr++ = v>>16;
2172                                 *outptr++ = v>>8;
2173                                 *outptr++ = v;
2174                                 i=0;
2175                         }
2176                 }
2177         }
2178
2179         *save = v;
2180         *state = i;
2181
2182         /* quick scan back for '=' on the end somewhere */
2183         /* fortunately we can drop 1 output char for each trailing = (upto 2) */
2184         i=2;
2185         while (inptr>in && i) {
2186                 inptr--;
2187                 if (_evc_base64_rank[*inptr] != 0xff) {
2188                         if (*inptr == '=' && outptr>out)
2189                                 outptr--;
2190                         i--;
2191                 }
2192         }
2193
2194         /* if i!= 0 then there is a truncation error! */
2195         return outptr-out;
2196 }
2197
2198 char *
2199 _evc_base64_encode_simple (const char *data, size_t len)
2200 {
2201         unsigned char *out;
2202         int state = 0, outlen;
2203         int save = 0;
2204
2205         g_return_val_if_fail (data != NULL, NULL);
2206
2207         out = g_malloc (len * 4 / 3 + 5);
2208         outlen = _evc_base64_encode_close ((unsigned char *)data, len, FALSE,
2209                                       out, &state, &save);
2210         out[outlen] = '\0';
2211         return (char *)out;
2212 }
2213
2214 size_t
2215 _evc_base64_decode_simple (char *data, size_t len)
2216 {
2217         int state = 0;
2218         unsigned int save = 0;
2219
2220         g_return_val_if_fail (data != NULL, 0);
2221
2222         return _evc_base64_decode_step ((unsigned char *)data, len,
2223                                         (unsigned char *)data, &state, &save);
2224 }