1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
4 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
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.
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.
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.
20 * Author: Chris Toshok (toshok@ximian.com)
23 /* This file implements the decoding of the v-card format
24 * http://www.imc.org/pdi/vcard-21.txt
36 #define E_VCARD_GET_PRIVATE(obj) \
37 (G_TYPE_INSTANCE_GET_PRIVATE \
38 ((obj), E_TYPE_VCARD, EVCardPrivate))
40 G_DEFINE_TYPE (EVCard, e_vcard, G_TYPE_OBJECT)
42 /** Encoding used in v-card
43 * Note: v-card spec defines additional 7BIT 8BIT and X- encoding
46 EVC_ENCODING_RAW, /* no encoding */
47 EVC_ENCODING_BASE64, /* base64 */
48 EVC_ENCODING_QP /* quoted-printable */
51 struct _EVCardPrivate {
56 struct _EVCardAttribute {
59 GList *params; /* EVCardParam */
61 GList *decoded_values;
62 EVCardEncoding encoding;
63 gboolean encoding_set;
66 struct _EVCardAttributeParam {
68 GList *values; /* GList of gchar *'s */
72 vcard_finalize (GObject *object)
76 priv = E_VCARD_GET_PRIVATE (object);
78 /* Directly access priv->attributes and don't call
79 * e_vcard_ensure_attributes(), since it is pointless
80 * to start vCard parsing that late. */
82 priv->attributes, (GDestroyNotify) e_vcard_attribute_free);
86 /* Chain up to parent's finalize() method. */
87 G_OBJECT_CLASS (e_vcard_parent_class)->finalize (object);
91 e_vcard_class_init (EVCardClass *class)
93 GObjectClass *object_class;
95 g_type_class_add_private (class, sizeof (EVCardPrivate));
97 object_class = G_OBJECT_CLASS (class);
98 object_class->finalize = vcard_finalize;
102 e_vcard_init (EVCard *evc)
104 evc->priv = E_VCARD_GET_PRIVATE (evc);
107 /* Case insensitive version of strstr */
109 strstr_nocase (const gchar *haystack,
112 /* When _GNU_SOURCE is available, use the nonstandard extension of libc */
114 g_return_val_if_fail (haystack, NULL);
115 g_return_Val_if_fail (needle, NULL);
117 return strcasestr (haystack, needle)
119 /* Otherwise convert both, haystack and needle to lowercase and use good old strstr */
124 g_return_val_if_fail (haystack, NULL);
125 g_return_val_if_fail (needle, NULL);
127 l_haystack = g_ascii_strdown (haystack, -1);
128 l_needle = g_ascii_strdown (needle, -1);
129 pos = strstr (l_haystack, l_needle);
131 /* Get actual position of the needle in the haystack instead of l_haystack or
134 pos = (gchar *)(haystack + (pos - l_haystack));
143 /* Skip newline characters and return the next character.
144 * This function takes care of folding lines, skipping
145 * newline characters if found, taking care of equal characters
146 * and other strange things.
149 skip_newline (gchar *str,
150 gboolean quoted_printable)
157 /* -- swallow equal signs at end of line for quoted printable */
158 /* note: a quoted_printable linefolding is an equal sign followed by
159 * one or more newline characters and optional a whitespace */
160 if (quoted_printable && *p == '=' ) {
161 next = g_utf8_next_char (p);
162 if (*next == '\r' || *next == '\n') {
163 p = g_utf8_next_char (next); /* swallow equal and newline */
165 if ((*p == '\r' || *p == '\n') && *p != *next ) {
166 p = g_utf8_next_char (p); /* swallow second newline */
168 if (*p == ' ' || *p == '\t') {
169 p = g_utf8_next_char (p); /* swallow whitespace */
175 /* -- swallow newline and (if present) following whitespaces */
176 } else if (*p == '\r' || *p == '\n') {
178 next = g_utf8_next_char (p);
179 if ((*next == '\n' || *next == '\r') && *p != *next) {
181 next2 = g_utf8_next_char (next);
182 if (*next2 == ' ' || *next2 == '\t') {
183 p = g_utf8_next_char (next2); /* we found a line folding */
186 } else if (*next == ' ' || *next == '\t') {
187 p = g_utf8_next_char (next); /* we found a line folding */
194 /* skip forward until we hit the CRLF, or \0 */
196 skip_to_next_line (gchar **p)
201 while (*lp != '\n' && *lp != '\r' && *lp != '\0')
202 lp = g_utf8_next_char (lp);
204 /* -- skip over the endline */
205 while (*lp == '\r' || *lp == '\n') {
206 lp = g_utf8_next_char (lp);
212 /* skip forward until we hit a character in @s, CRLF, or \0. leave *p
213 * pointing at the character that causes us to stop */
215 skip_until (gchar **p,
222 while (*lp != '\r' && *lp != '\0') {
223 gboolean s_matches = FALSE;
225 for (ls = s; *ls; ls = g_utf8_next_char (ls)) {
226 if (g_utf8_get_char (ls) == g_utf8_get_char (lp)) {
234 lp = g_utf8_next_char (lp);
241 read_attribute_value (EVCardAttribute *attr,
243 gboolean quoted_printable,
244 const gchar *charset)
249 /* read in the value */
250 str = g_string_new ("");
251 for (lp = skip_newline ( *p, quoted_printable);
252 *lp != '\n' && *lp != '\r' && *lp != '\0';
253 lp = skip_newline ( lp, quoted_printable ) ) {
255 if (*lp == '=' && quoted_printable) {
257 if ((a = *(++lp)) == '\0') break;
258 if ((b = *(++lp)) == '\0') break;
259 if (isxdigit (a) && isxdigit (b)) {
265 c = (((a >= 'a' ? a - 'a' + 10 : a - '0') &0x0f) << 4)
266 | ((b >= 'a' ? b - 'a' + 10 : b - '0') &0x0f);
268 g_string_append_c (str, c); /* add decoded byte (this is not a unicode yet) */
272 g_string_append_c (str, a);
273 g_string_append_c (str, b);
278 } else if (*lp == '\\') {
279 /* convert back to the non-escaped version of
281 lp = g_utf8_next_char (lp);
283 g_string_append_c (str, '\\');
287 /* beware, there might be a line break due to folding,
288 * need next real character
290 lp = skip_newline (lp, quoted_printable);
293 case 'n': g_string_append_c (str, '\n'); break;
294 case 'N': g_string_append_c (str, '\n'); break;
295 case 'r': g_string_append_c (str, '\r'); break;
296 case 'R': g_string_append_c (str, '\r'); break;
297 case ';': g_string_append_c (str, ';'); break;
298 case ',': g_string_append_c (str, ','); break;
299 case '\\': g_string_append_c (str, '\\'); break;
301 g_warning ("invalid escape, passing it through");
302 g_string_append_c (str, '\\');
303 g_string_append_unichar (str, g_utf8_get_char (lp));
306 lp = g_utf8_next_char (lp);
308 else if ((*lp == ';') ||
309 (*lp == ',' && !g_ascii_strcasecmp (attr->name, "CATEGORIES"))) {
313 tmp = g_convert (str->str, str->len, "UTF-8", charset, NULL, NULL, NULL);
315 g_string_assign (str, tmp);
320 e_vcard_attribute_add_value (attr, str->str);
321 g_string_assign (str, "");
322 lp = g_utf8_next_char (lp);
325 g_string_append_unichar (str, g_utf8_get_char (lp));
326 lp = g_utf8_next_char (lp);
333 tmp = g_convert (str->str, str->len, "UTF-8", charset, NULL, NULL, NULL);
335 g_string_assign (str, tmp);
340 e_vcard_attribute_add_value (attr, str->str);
341 g_string_free (str, TRUE);
344 skip_to_next_line ( &lp );
350 read_attribute_params (EVCardAttribute *attr,
352 gboolean *quoted_printable,
357 EVCardAttributeParam *param = NULL;
358 gboolean in_quote = FALSE;
360 str = g_string_new ("");
361 for (lp = skip_newline ( *p, *quoted_printable);
362 *lp != '\n' && *lp != '\r' && *lp != '\0';
363 lp = skip_newline ( lp, *quoted_printable ) ) {
366 in_quote = !in_quote;
367 lp = g_utf8_next_char (lp);
369 else if (in_quote || g_unichar_isalnum (g_utf8_get_char (lp)) || *lp == '-' || *lp == '_') {
370 g_string_append_unichar (str, g_utf8_get_char (lp));
371 lp = g_utf8_next_char (lp);
373 /* accumulate until we hit the '=' or ';'. If we hit
374 * a '=' the string contains the parameter name. if
375 * we hit a ';' the string contains the parameter
376 * value and the name is either ENCODING (if value ==
377 * QUOTED-PRINTABLE) or TYPE (in any other case.)
379 else if (*lp == '=') {
381 param = e_vcard_attribute_param_new (str->str);
382 g_string_assign (str, "");
383 lp = g_utf8_next_char (lp);
386 skip_until (&lp, ":;");
388 lp = g_utf8_next_char (lp);
390 } else if (*lp == ':') {
394 skip_to_next_line ( &lp );
399 else if (*lp == ';' || *lp == ':' || *lp == ',') {
400 gboolean colon = (*lp == ':');
401 gboolean comma = (*lp == ',');
405 e_vcard_attribute_param_add_value (param, str->str);
406 g_string_assign (str, "");
408 lp = g_utf8_next_char (lp);
411 /* we've got a parameter of the form:
413 * so what we do depends on if there are already values
414 * for the parameter. If there are, we just finish
415 * this parameter and skip past the offending character
416 * (unless it's the ':'). If there aren't values, we free
417 * the parameter then skip past the character.
419 if (!param->values) {
420 e_vcard_attribute_param_free (param);
423 lp = g_utf8_next_char (lp);
428 && !g_ascii_strcasecmp (param->name, "encoding")
429 && !g_ascii_strcasecmp (param->values->data, "quoted-printable")) {
430 *quoted_printable = TRUE;
431 e_vcard_attribute_param_free (param);
434 && !g_ascii_strcasecmp (param->name, "charset")
435 && g_ascii_strcasecmp (param->values->data, "utf-8") != 0) {
437 *charset = g_strdup (param->values->data);
438 e_vcard_attribute_param_free (param);
444 const gchar *param_name;
445 if (!g_ascii_strcasecmp (str->str,
446 "quoted-printable")) {
447 param_name = "ENCODING";
448 *quoted_printable = TRUE;
450 /* apple's broken addressbook app outputs naked BASE64
451 * parameters, which aren't even vcard 3.0 compliant. */
452 else if (!g_ascii_strcasecmp (str->str,
454 param_name = "ENCODING";
455 g_string_assign (str, "b");
462 param = e_vcard_attribute_param_new (param_name);
463 e_vcard_attribute_param_add_value (param, str->str);
465 g_string_assign (str, "");
467 lp = g_utf8_next_char (lp);
470 /* we've got an attribute with a truly empty
471 * attribute parameter. So it's of the form:
473 * ATTR;[PARAM=value;]*;[PARAM=value;]*:
475 * (note the extra ';')
477 * the only thing to do here is, well.. nothing.
478 * we skip over the character if it's not a colon,
479 * and the rest is handled for us: We'll either
480 * continue through the loop again if we hit a ';',
481 * or we'll break out correct below if it was a ':' */
483 lp = g_utf8_next_char (lp);
486 if (param && !comma) {
487 e_vcard_attribute_add_param (attr, param);
494 g_warning ("invalid character found in parameter spec");
495 g_string_assign (str, "");
496 /* skip_until (&lp, ":;"); */
498 skip_to_next_line ( &lp );
503 g_string_free (str, TRUE);
508 /* reads an entire attribute from the input buffer, leaving p pointing
509 * at the start of the next line (past the \r\n) */
510 static EVCardAttribute *
511 read_attribute (gchar **p)
513 gchar *attr_group = NULL;
514 gchar *attr_name = NULL;
515 EVCardAttribute *attr = NULL;
518 gboolean is_qp = FALSE;
519 gchar *charset = NULL;
521 /* first read in the group/name */
522 str = g_string_new ("");
523 for (lp = skip_newline ( *p, is_qp);
524 *lp != '\n' && *lp != '\r' && *lp != '\0';
525 lp = skip_newline ( lp, is_qp ) ) {
527 if (*lp == ':' || *lp == ';') {
529 /* we've got a name, break out to the value/attribute parsing */
530 attr_name = g_string_free (str, FALSE);
534 /* a line of the form:
537 * since we don't have an attribute
538 * name, skip to the end of the line
541 g_string_free (str, TRUE);
543 skip_to_next_line (p);
547 else if (*lp == '.') {
550 "extra `.' in attribute specification. ignoring extra group `%s'",
552 g_string_free (str, TRUE);
553 str = g_string_new ("");
556 attr_group = g_string_free (str, FALSE);
557 str = g_string_new ("");
560 else if (g_unichar_isalnum (g_utf8_get_char (lp)) || *lp == '-' || *lp == '_') {
561 g_string_append_unichar (str, g_utf8_get_char (lp));
564 g_warning ("invalid character found in attribute group/name");
565 g_string_free (str, TRUE);
567 skip_to_next_line (p);
571 lp = g_utf8_next_char (lp);
575 skip_to_next_line (p);
579 attr = e_vcard_attribute_new (attr_group, attr_name);
584 /* skip past the ';' */
585 lp = g_utf8_next_char (lp);
586 read_attribute_params (attr, &lp, &is_qp, &charset);
588 attr->encoding = EVC_ENCODING_RAW;
591 /* skip past the ':' */
592 lp = g_utf8_next_char (lp);
593 read_attribute_value (attr, &lp, is_qp, charset);
606 e_vcard_attribute_free (attr);
610 /* Stolen from glib/glib/gconvert.c */
612 make_valid_utf8 (const gchar *name)
615 const gchar *remainder, *invalid;
616 gint remaining_bytes, valid_bytes;
620 remaining_bytes = strlen (name);
622 while (remaining_bytes != 0) {
623 if (g_utf8_validate (remainder, remaining_bytes, &invalid))
625 valid_bytes = invalid - remainder;
628 string = g_string_sized_new (remaining_bytes);
630 g_string_append_len (string, remainder, valid_bytes);
631 /* append U+FFFD REPLACEMENT CHARACTER */
632 g_string_append (string, "\357\277\275");
634 remaining_bytes -= valid_bytes + 1;
635 remainder = invalid + 1;
639 return g_strdup (name);
641 g_string_append (string, remainder);
643 g_assert (g_utf8_validate (string->str, -1, NULL));
645 return g_string_free (string, FALSE);
648 /* we try to be as forgiving as we possibly can here - this isn't a
649 * validator. Almost nothing is considered a fatal error. We always
650 * try to return *something*.
659 EVCardAttribute *attr;
661 buf = make_valid_utf8 (str);
663 d (printf ("BEFORE FOLDING:\n"));
665 d (printf ("\n\nAFTER FOLDING:\n"));
670 attr = read_attribute (&p);
671 if (!attr || attr->group || g_ascii_strcasecmp (attr->name, "begin")) {
672 g_warning ("vcard began without a BEGIN:VCARD\n");
674 if (attr && !g_ascii_strcasecmp (attr->name, "begin")) {
675 e_vcard_attribute_free (attr);
678 if (!ignore_uid || g_ascii_strcasecmp (attr->name, EVC_UID) != 0)
679 e_vcard_add_attribute (evc, attr);
682 EVCardAttribute *next_attr = read_attribute (&p);
687 if (g_ascii_strcasecmp (next_attr->name, "end") == 0)
690 if (ignore_uid && g_ascii_strcasecmp (attr->name, EVC_UID) == 0) {
691 e_vcard_attribute_free (attr);
696 e_vcard_add_attribute (evc, next_attr);
700 if (!attr || attr->group || g_ascii_strcasecmp (attr->name, "end")) {
701 g_warning ("vcard ended without END:VCARD\n");
704 if (attr && !g_ascii_strcasecmp (attr->name, "end"))
705 e_vcard_attribute_free (attr);
709 evc->priv->attributes = g_list_reverse (evc->priv->attributes);
713 e_vcard_ensure_attributes (EVCard *evc)
715 if (evc->priv->vcard) {
716 gboolean have_uid = (evc->priv->attributes != NULL);
717 gchar *vcs = evc->priv->vcard;
719 /* detach vCard to avoid loops */
720 evc->priv->vcard = NULL;
722 /* Parse the vCard */
723 parse (evc, vcs, have_uid);
727 return evc->priv->attributes;
731 e_vcard_escape_semicolons (const gchar *s)
736 str = g_string_new ("");
738 for (p = s; p && *p; p++) {
740 g_string_append (str, "\\");
742 g_string_append_c (str, *p);
745 return g_string_free (str, FALSE);
749 * e_vcard_escape_string:
750 * @s: the string to escape
752 * Escapes a string according to RFC2426, section 5.
754 * Returns: A newly allocated, escaped string.
757 e_vcard_escape_string (const gchar *s)
762 str = g_string_new ("");
764 /* Escape a string as described in RFC2426, section 5 */
765 for (p = s; p && *p; p++) {
768 g_string_append (str, "\\n");
771 if (*(p + 1) == '\n')
773 g_string_append (str, "\\n");
776 g_string_append (str, "\\;");
779 g_string_append (str, "\\,");
782 g_string_append (str, "\\\\");
785 g_string_append_c (str, *p);
790 return g_string_free (str, FALSE);
794 * e_vcard_unescape_string:
795 * @s: the string to unescape
797 * Unescapes a string according to RFC2426, section 5.
799 * Returns: A newly allocated, unescaped string.
802 e_vcard_unescape_string (const gchar *s)
807 g_return_val_if_fail (s != NULL, NULL);
809 str = g_string_new ("");
811 /* Unescape a string as described in RFC2426, section 5 */
812 for (p = s; *p; p++) {
816 g_string_append_c (str, '\\');
820 case 'n': g_string_append_c (str, '\n'); break;
821 case 'r': g_string_append_c (str, '\r'); break;
822 case ';': g_string_append_c (str, ';'); break;
823 case ',': g_string_append_c (str, ','); break;
824 case '\\': g_string_append_c (str, '\\'); break;
826 g_warning ("invalid escape, passing it through");
827 g_string_append_c (str, '\\');
828 g_string_append_c (str, *p);
832 g_string_append_c (str, *p);
836 return g_string_free (str, FALSE);
840 e_vcard_construct (EVCard *evc,
843 e_vcard_construct_with_uid (evc, str, NULL);
847 * e_vcard_construct_with_uid:
849 * FIXME: Document me!
854 e_vcard_construct_with_uid (EVCard *evc,
858 g_return_if_fail (E_IS_VCARD (evc));
859 g_return_if_fail (str != NULL);
860 g_return_if_fail (evc->priv->vcard == NULL);
861 g_return_if_fail (evc->priv->attributes == NULL);
863 /* Lazy construction */
865 evc->priv->vcard = g_strdup (str);
867 /* Add UID attribute */
869 EVCardAttribute *attr;
871 attr = e_vcard_attribute_new (NULL, EVC_UID);
872 e_vcard_attribute_add_value (attr, uid);
874 evc->priv->attributes = g_list_prepend (evc->priv->attributes, attr);
881 * Creates a new, blank #EVCard.
883 * Returns: A new, blank #EVCard.
888 return e_vcard_new_from_string ("");
892 * e_vcard_new_from_string:
893 * @str: a string representation of the vcard to create
895 * Creates a new #EVCard from the passed-in string
898 * Returns: A new #EVCard.
901 e_vcard_new_from_string (const gchar *str)
905 g_return_val_if_fail (str != NULL, NULL);
907 evc = g_object_new (E_TYPE_VCARD, NULL);
909 e_vcard_construct (evc, str);
915 e_vcard_qp_encode (const gchar *txt)
917 const gchar *p = txt;
918 GString *escaped = g_string_new ("");
922 if ((*p >= 33 && *p <= 60) || (*p >= 62 && *p <= 126)) {
924 g_string_append (escaped, "=" CRLF " ");
925 count = 1; /* 1 for space needed for folding */
928 g_string_append_c (escaped, *p++);
935 g_string_append (escaped, "=" CRLF " ");
936 count = 1; /* 1 for space needed for folding */
939 g_string_append_printf (escaped, "=%2.2X", (guchar) *p++);
943 return g_string_free (escaped, FALSE);
947 generate_dict_validator (const gchar *words)
949 GHashTable *dict = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
950 gchar **list = g_strsplit (words, ",", 0);
953 for (i = 0; list[i]; i++)
954 g_hash_table_insert (dict, list[i], NULL);
962 e_vcard_to_string_vcard_21 (EVCard *evc)
965 GString *str = g_string_new ("");
966 GHashTable *evc_prop = generate_dict_validator (E_VCARD_21_VALID_PROPERTIES);
967 GHashTable *evc_params = generate_dict_validator (E_VCARD_21_VALID_PARAMETERS);
969 g_string_append (str, "BEGIN:VCARD" CRLF);
970 g_string_append (str, "VERSION:2.1" CRLF);
972 for (l = e_vcard_ensure_attributes (evc); l; l = l->next) {
974 EVCardAttribute *attr = l->data;
976 gboolean empty, encode;
979 if (g_ascii_strcasecmp (attr->name, "VERSION") == 0)
982 upper_name = g_ascii_strup (attr->name, -1);
983 /* Checking whether current property (attribute) is valid for vCard 2.1 */
984 if (!g_hash_table_lookup_extended (evc_prop, upper_name, NULL, NULL)) {
991 empty = TRUE; /* Empty fields should be omitted -- some headsets may choke on it */
992 encode = FALSE; /* Generally only new line MUST be encoded (Quoted Printable) */
994 for (v = attr->values; v; v = v->next) {
995 gchar *value = v->data;
1002 if (strstr (value, "\n") != NULL) {
1011 attr_str = g_string_new ("");
1013 /* From vCard 2.1 spec page 27, 28
1015 * contentline = [group "."] name *(";" param) ":" value CRLF
1019 g_string_append (attr_str, attr->group);
1020 g_string_append_c (attr_str, '.');
1022 g_string_append (attr_str, attr->name);
1024 /* handle the parameters */
1025 for (list = attr->params; list; list = list->next) {
1026 EVCardAttributeParam *param = list->data;
1030 * param = param-name "=" param-value
1033 upper_name = g_ascii_strup (param->name, -1);
1034 /* Checking whether current parameter is valid for vCard 2.1 */
1035 if (!g_hash_table_lookup_extended (evc_params, upper_name, NULL, NULL)) {
1036 g_free (upper_name);
1040 g_free (upper_name);
1042 g_string_append_c (attr_str, ';');
1043 g_string_append (attr_str, param->name);
1047 for (v = param->values; v; v = v->next) {
1048 gchar *value = v->data;
1049 gchar *escaped_value = e_vcard_escape_semicolons (value);
1051 g_string_append_printf (attr_str, "=%s", escaped_value);
1054 g_string_append_printf (attr_str, ";%s", param->name);
1056 g_free (escaped_value);
1061 g_string_append (attr_str, ";ENCODING=QUOTED-PRINTABLE");
1063 g_string_append_c (attr_str, ':');
1065 for (v = attr->values; v; v = v->next) {
1066 gchar *value = v->data;
1069 gchar *escaped_value;
1071 escaped_value = e_vcard_qp_encode (value);
1072 g_string_append (attr_str, escaped_value);
1074 g_free (escaped_value);
1076 g_string_append (attr_str, value);
1079 g_string_append_c (attr_str, ';');
1082 g_string_append (attr_str, CRLF);
1084 g_string_append (str, attr_str->str);
1086 g_string_free (attr_str, TRUE);
1089 g_string_append (str, "END:VCARD");
1091 g_hash_table_destroy (evc_params);
1092 g_hash_table_destroy (evc_prop);
1094 return g_string_free (str, FALSE);
1098 e_vcard_to_string_vcard_30 (EVCard *evc)
1103 GString *str = g_string_new ("");
1105 g_string_append (str, "BEGIN:VCARD" CRLF);
1107 /* we hardcode the version (since we're outputting to a
1108 * specific version) and ignore any version attributes the
1109 * vcard might contain */
1110 g_string_append (str, "VERSION:3.0" CRLF);
1112 for (l = e_vcard_ensure_attributes (evc); l; l = l->next) {
1114 EVCardAttribute *attr = l->data;
1118 if (!g_ascii_strcasecmp (attr->name, "VERSION"))
1121 attr_str = g_string_new ("");
1123 /* From rfc2425, 5.8.2
1125 * contentline = [group "."] name *(";" param) ":" value CRLF
1129 g_string_append (attr_str, attr->group);
1130 g_string_append_c (attr_str, '.');
1132 g_string_append (attr_str, attr->name);
1134 /* handle the parameters */
1135 for (list = attr->params; list; list = list->next) {
1136 EVCardAttributeParam *param = list->data;
1138 * param = param-name "=" param-value *("," param-value)
1140 g_string_append_c (attr_str, ';');
1141 g_string_append (attr_str, param->name);
1142 if (param->values) {
1143 g_string_append_c (attr_str, '=');
1144 for (v = param->values; v; v = v->next) {
1145 gchar *value = v->data;
1146 gchar *pval = value;
1147 gboolean quotes = FALSE;
1149 if (!g_unichar_isalnum (g_utf8_get_char (pval))) {
1153 pval = g_utf8_next_char (pval);
1159 g_string_append_c (attr_str, '"');
1161 for (i = 0; value[i]; i++) {
1162 /* skip quotes in quoted string; it is not allowed */
1163 if (value[i] == '\"')
1166 g_string_append_c (attr_str, value[i]);
1169 g_string_append_c (attr_str, '"');
1171 g_string_append (attr_str, value);
1174 g_string_append_c (attr_str, ',');
1179 g_string_append_c (attr_str, ':');
1181 for (v = attr->values; v; v = v->next) {
1182 gchar *value = v->data;
1183 gchar *escaped_value = NULL;
1185 escaped_value = e_vcard_escape_string (value);
1187 g_string_append (attr_str, escaped_value);
1189 /* XXX toshok - i hate you, rfc 2426.
1190 * why doesn't CATEGORIES use a; like
1191 * a normal list attribute? */
1192 if (!g_ascii_strcasecmp (attr->name, "CATEGORIES"))
1193 g_string_append_c (attr_str, ',');
1195 g_string_append_c (attr_str, ';');
1198 g_free (escaped_value);
1202 * When generating a content line, lines longer than 75
1203 * characters SHOULD be folded
1205 len = g_utf8_strlen (attr_str->str, -1);
1207 GString *fold_str = g_string_sized_new (attr_str->len + len / 74 * 3);
1208 gchar *pos1 = attr_str->str;
1210 pos2 = g_utf8_offset_to_pointer (pos2, 75);
1214 g_string_append_len (fold_str, pos1, pos2 - pos1);
1215 g_string_append (fold_str, CRLF " ");
1219 pos2 = g_utf8_offset_to_pointer (pos2, 74);
1222 g_string_append (fold_str, pos1);
1223 g_string_free (attr_str, TRUE);
1224 attr_str = fold_str;
1226 g_string_append (attr_str, CRLF);
1228 g_string_append (str, attr_str->str);
1229 g_string_free (attr_str, TRUE);
1232 g_string_append (str, "END:VCARD");
1234 return g_string_free (str, FALSE);
1238 * e_vcard_to_string:
1239 * @evc: the #EVCard to export
1240 * @format: the format to export to
1242 * Exports @evc to a string representation, specified
1243 * by the @format argument.
1245 * Returns: A newly allocated string representing the vcard.
1248 e_vcard_to_string (EVCard *evc,
1249 EVCardFormat format)
1251 g_return_val_if_fail (E_IS_VCARD (evc), NULL);
1254 case EVC_FORMAT_VCARD_21:
1255 if (evc->priv->vcard && evc->priv->attributes == NULL &&
1256 strstr_nocase (evc->priv->vcard, CRLF "VERSION:2.1" CRLF))
1257 return g_strdup (evc->priv->vcard);
1259 return e_vcard_to_string_vcard_21 (evc);
1260 case EVC_FORMAT_VCARD_30:
1261 if (evc->priv->vcard && evc->priv->attributes == NULL &&
1262 strstr_nocase (evc->priv->vcard, CRLF "VERSION:3.0" CRLF))
1263 return g_strdup (evc->priv->vcard);
1265 return e_vcard_to_string_vcard_30 (evc);
1267 g_warning ("invalid format specifier passed to e_vcard_to_string");
1268 return g_strdup ("");
1273 * e_vcard_dump_structure:
1274 * @evc: the #EVCard to dump
1276 * Prints a dump of @evc's structure to stdout. Used for
1280 e_vcard_dump_structure (EVCard *evc)
1286 g_return_if_fail (E_IS_VCARD (evc));
1289 for (a = e_vcard_ensure_attributes (evc); a; a = a->next) {
1291 EVCardAttribute *attr = a->data;
1292 printf ("+-- %s\n", attr->name);
1294 printf (" +- params=\n");
1296 for (p = attr->params, i = 0; p; p = p->next, i++) {
1297 EVCardAttributeParam *param = p->data;
1298 printf (" | [%d] = %s", i,param->name);
1300 for (v = param->values; v; v = v->next) {
1301 gchar *value = e_vcard_escape_string ((gchar *) v->data);
1302 printf ("%s", value);
1311 printf (" +- values=\n");
1312 for (v = attr->values, i = 0; v; v = v->next, i++) {
1313 printf (" [%d] = `%s'\n", i, (gchar *) v->data);
1319 * e_vcard_attribute_new:
1320 * @attr_group: (allow-none): a group name
1321 * @attr_name: an attribute name
1323 * Creates a new #EVCardAttribute with the specified group and
1326 * Returns: A new #EVCardAttribute.
1329 e_vcard_attribute_new (const gchar *attr_group,
1330 const gchar *attr_name)
1332 EVCardAttribute *attr;
1334 attr = g_slice_new0 (EVCardAttribute);
1336 attr->group = g_strdup (attr_group);
1337 attr->name = g_strdup (attr_name);
1343 * e_vcard_attribute_free:
1344 * @attr: attribute to free
1346 * Frees an attribute, its values and its parameters.
1349 e_vcard_attribute_free (EVCardAttribute *attr)
1351 g_return_if_fail (attr != NULL);
1353 g_free (attr->group);
1354 g_free (attr->name);
1356 e_vcard_attribute_remove_values (attr);
1358 e_vcard_attribute_remove_params (attr);
1360 g_slice_free (EVCardAttribute, attr);
1364 * e_vcard_attribute_copy:
1365 * @attr: attribute to copy
1367 * Makes a copy of @attr.
1369 * Returns: A new #EVCardAttribute identical to @attr.
1372 e_vcard_attribute_copy (EVCardAttribute *attr)
1377 g_return_val_if_fail (attr != NULL, NULL);
1379 a = e_vcard_attribute_new (attr->group, attr->name);
1381 for (p = attr->values; p; p = p->next)
1382 e_vcard_attribute_add_value (a, p->data);
1384 for (p = attr->params; p; p = p->next)
1385 e_vcard_attribute_add_param (a, e_vcard_attribute_param_copy (p->data));
1391 e_vcard_attribute_get_type (void)
1393 static volatile gsize type_id__volatile = 0;
1395 if (g_once_init_enter (&type_id__volatile)) {
1398 type_id = g_boxed_type_register_static (
1400 (GBoxedCopyFunc) e_vcard_attribute_copy,
1401 (GBoxedFreeFunc) e_vcard_attribute_free);
1403 g_once_init_leave (&type_id__volatile, type_id);
1406 return type_id__volatile;
1410 * e_vcard_remove_attributes:
1411 * @evc: vcard object
1412 * @attr_group: (allow-none): group name of attributes to be removed
1413 * @attr_name: name of the arributes to be removed
1415 * Removes all the attributes with group name and attribute name equal to
1416 * passed in values. If @attr_group is %NULL or an empty string,
1417 * it removes all the attributes with passed in name irrespective of
1418 * their group names.
1421 e_vcard_remove_attributes (EVCard *evc,
1422 const gchar *attr_group,
1423 const gchar *attr_name)
1427 g_return_if_fail (E_IS_VCARD (evc));
1428 g_return_if_fail (attr_name != NULL);
1430 attr = e_vcard_ensure_attributes (evc);
1433 EVCardAttribute *a = attr->data;
1435 next_attr = attr->next;
1437 if (((!attr_group || *attr_group == '\0') ||
1438 (attr_group && !g_ascii_strcasecmp (attr_group, a->group))) &&
1439 ((!a->name) || !g_ascii_strcasecmp (attr_name, a->name))) {
1441 /* matches, remove/delete the attribute */
1442 evc->priv->attributes = g_list_delete_link (evc->priv->attributes, attr);
1444 e_vcard_attribute_free (a);
1452 * e_vcard_remove_attribute:
1454 * @attr: an #EVCardAttribute to remove
1456 * Removes @attr from @evc and frees it.
1459 e_vcard_remove_attribute (EVCard *evc,
1460 EVCardAttribute *attr)
1462 g_return_if_fail (E_IS_VCARD (evc));
1463 g_return_if_fail (attr != NULL);
1465 /* No need to call e_vcard_ensure_attributes() here. It has
1466 * already been called if this is a valid call and attr is among
1467 * our attributes. */
1468 evc->priv->attributes = g_list_remove (evc->priv->attributes, attr);
1469 e_vcard_attribute_free (attr);
1473 * e_vcard_append_attribute:
1475 * @attr: (transfer full): an #EVCardAttribute to append
1477 * Appends @attr to @evc to the end of a list of attributes.
1482 e_vcard_append_attribute (EVCard *evc,
1483 EVCardAttribute *attr)
1485 g_return_if_fail (E_IS_VCARD (evc));
1486 g_return_if_fail (attr != NULL);
1488 /* Handle UID special case:
1489 * No need to parse the vcard to append an UID attribute */
1490 if (evc->priv->vcard != NULL && g_strcmp0 (attr->name, EVC_UID) == 0) {
1491 evc->priv->attributes = g_list_append (evc->priv->attributes, attr);
1493 evc->priv->attributes = g_list_append (e_vcard_ensure_attributes (evc), attr);
1498 * e_vcard_append_attribute_with_value:
1499 * @evcard: an #EVCard
1500 * @attr: (transfer full): an #EVCardAttribute to append
1501 * @value: a value to assign to the attribute
1503 * Appends @attr to @evcard, setting it to @value.
1504 * For attribute addition is used e_vcard_append_attribute().
1509 e_vcard_append_attribute_with_value (EVCard *evcard,
1510 EVCardAttribute *attr,
1513 g_return_if_fail (E_IS_VCARD (evcard));
1514 g_return_if_fail (attr != NULL);
1516 e_vcard_attribute_add_value (attr, value);
1518 e_vcard_append_attribute (evcard, attr);
1522 * e_vcard_append_attribute_with_values:
1523 * @evcard: an @EVCard
1524 * @attr: (transfer full): an #EVCardAttribute to append
1525 * @...: a %NULL-terminated list of values to assign to the attribute
1527 * Appends @attr to @evcard, assigning the list of values to it.
1528 * For attribute addition is used e_vcard_append_attribute().
1533 e_vcard_append_attribute_with_values (EVCard *evcard,
1534 EVCardAttribute *attr,
1540 g_return_if_fail (E_IS_VCARD (evcard));
1541 g_return_if_fail (attr != NULL);
1543 va_start (ap, attr);
1545 while ((v = va_arg (ap, gchar *))) {
1546 e_vcard_attribute_add_value (attr, v);
1551 e_vcard_append_attribute (evcard, attr);
1555 * e_vcard_add_attribute:
1557 * @attr: (transfer full): an #EVCardAttribute to add
1559 * Adds @attr to @evc. It's added to the beginning of a list of attributes.
1562 e_vcard_add_attribute (EVCard *evc,
1563 EVCardAttribute *attr)
1565 g_return_if_fail (E_IS_VCARD (evc));
1566 g_return_if_fail (attr != NULL);
1568 /* Handle UID special case:
1569 * No need to parse the vcard to append an UID attribute */
1570 if (evc->priv->vcard != NULL && g_strcmp0 (attr->name, EVC_UID) == 0) {
1571 evc->priv->attributes = g_list_prepend (evc->priv->attributes, attr);
1573 evc->priv->attributes = g_list_prepend (e_vcard_ensure_attributes (evc), attr);
1578 * e_vcard_add_attribute_with_value:
1579 * @evcard: an #EVCard
1580 * @attr: (transfer full): an #EVCardAttribute to add
1581 * @value: a value to assign to the attribute
1583 * Adds @attr to @evcard, setting it to @value. For attribute addition
1584 * is used e_vcard_add_attribute().
1587 e_vcard_add_attribute_with_value (EVCard *evcard,
1588 EVCardAttribute *attr,
1591 g_return_if_fail (E_IS_VCARD (evcard));
1592 g_return_if_fail (attr != NULL);
1594 e_vcard_attribute_add_value (attr, value);
1596 e_vcard_add_attribute (evcard, attr);
1600 * e_vcard_add_attribute_with_values:
1601 * @evcard: an @EVCard
1602 * @attr: (transfer full): an #EVCardAttribute to add
1603 * @...: a %NULL-terminated list of values to assign to the attribute
1605 * Adds @attr to @evcard, assigning the list of values to it.
1606 * For attribute addition is used e_vcard_add_attribute().
1609 e_vcard_add_attribute_with_values (EVCard *evcard,
1610 EVCardAttribute *attr,
1616 g_return_if_fail (E_IS_VCARD (evcard));
1617 g_return_if_fail (attr != NULL);
1619 va_start (ap, attr);
1621 while ((v = va_arg (ap, gchar *))) {
1622 e_vcard_attribute_add_value (attr, v);
1627 e_vcard_add_attribute (evcard, attr);
1631 * e_vcard_attribute_add_value:
1632 * @attr: an #EVCardAttribute
1633 * @value: a string value
1635 * Adds @value to @attr's list of values.
1638 e_vcard_attribute_add_value (EVCardAttribute *attr,
1641 g_return_if_fail (attr != NULL);
1643 attr->values = g_list_append (attr->values, g_strdup (value));
1647 * e_vcard_attribute_add_value_decoded:
1648 * @attr: an #EVCardAttribute
1649 * @value: an encoded value
1650 * @len: the length of the encoded value, in bytes
1652 * Decodes @value according to the encoding used for @attr, and
1653 * adds it to @attr's list of values.
1656 e_vcard_attribute_add_value_decoded (EVCardAttribute *attr,
1660 g_return_if_fail (attr != NULL);
1662 switch (attr->encoding) {
1663 case EVC_ENCODING_RAW:
1664 g_warning ("can't add_value_decoded with an attribute using RAW encoding. you must set the ENCODING parameter first");
1666 case EVC_ENCODING_BASE64: {
1667 gchar *b64_data = g_base64_encode ((guchar *) value, len);
1668 GString *decoded = g_string_new_len (value, len);
1670 /* make sure the decoded list is up to date */
1671 e_vcard_attribute_get_values_decoded (attr);
1673 d (printf ("base64 encoded value: %s\n", b64_data));
1674 d (printf ("original length: %d\n", len));
1676 attr->values = g_list_append (attr->values, b64_data);
1677 attr->decoded_values = g_list_append (attr->decoded_values, decoded);
1680 case EVC_ENCODING_QP:
1681 g_warning ("need to implement quoted printable decoding");
1687 * e_vcard_attribute_add_values:
1688 * @attr: an #EVCardAttribute
1689 * @...: a %NULL-terminated list of strings
1691 * Adds a list of values to @attr.
1694 e_vcard_attribute_add_values (EVCardAttribute *attr,
1700 g_return_if_fail (attr != NULL);
1702 va_start (ap, attr);
1704 while ((v = va_arg (ap, gchar *))) {
1705 e_vcard_attribute_add_value (attr, v);
1712 free_gstring (GString *str)
1714 g_string_free (str, TRUE);
1718 * e_vcard_attribute_remove_values:
1719 * @attr: an #EVCardAttribute
1721 * Removes all values from @attr.
1724 e_vcard_attribute_remove_values (EVCardAttribute *attr)
1726 g_return_if_fail (attr != NULL);
1728 g_list_foreach (attr->values, (GFunc) g_free, NULL);
1729 g_list_free (attr->values);
1730 attr->values = NULL;
1732 g_list_foreach (attr->decoded_values, (GFunc) free_gstring, NULL);
1733 g_list_free (attr->decoded_values);
1734 attr->decoded_values = NULL;
1738 * e_vcard_attribute_remove_value:
1739 * @attr: an #EVCardAttribute
1740 * @s: an value to remove
1742 * Removes from the value list in @attr the value @s.
1745 e_vcard_attribute_remove_value (EVCardAttribute *attr,
1750 g_return_if_fail (attr != NULL);
1751 g_return_if_fail (s != NULL);
1753 l = g_list_find_custom (attr->values, s, (GCompareFunc) strcmp);
1758 attr->values = g_list_delete_link (attr->values, l);
1762 * e_vcard_attribute_remove_param:
1763 * @attr: an #EVCardAttribute
1764 * @param_name: a parameter name
1766 * Removes the parameter @param_name from the attribute @attr.
1771 e_vcard_attribute_remove_param (EVCardAttribute *attr,
1772 const gchar *param_name)
1775 EVCardAttributeParam *param;
1777 g_return_if_fail (attr != NULL);
1778 g_return_if_fail (param_name != NULL);
1780 for (l = attr->params; l; l = l->next) {
1782 if (g_ascii_strcasecmp (e_vcard_attribute_param_get_name (param),
1784 attr->params = g_list_delete_link (attr->params, l);
1785 e_vcard_attribute_param_free (param);
1792 * e_vcard_attribute_remove_params:
1793 * @attr: an #EVCardAttribute
1795 * Removes all parameters from @attr.
1798 e_vcard_attribute_remove_params (EVCardAttribute *attr)
1800 g_return_if_fail (attr != NULL);
1802 g_list_foreach (attr->params, (GFunc) e_vcard_attribute_param_free, NULL);
1803 g_list_free (attr->params);
1804 attr->params = NULL;
1806 /* also remove the cached encoding on this attribute */
1807 attr->encoding_set = FALSE;
1808 attr->encoding = EVC_ENCODING_RAW;
1812 e_vcard_attribute_param_get_type (void)
1814 static volatile gsize type_id__volatile = 0;
1816 if (g_once_init_enter (&type_id__volatile)) {
1819 type_id = g_boxed_type_register_static (
1820 "EVCardAttributeParam",
1821 (GBoxedCopyFunc) e_vcard_attribute_param_copy,
1822 (GBoxedFreeFunc) e_vcard_attribute_param_free);
1824 g_once_init_leave (&type_id__volatile, type_id);
1827 return type_id__volatile;
1831 * e_vcard_attribute_param_new:
1832 * @name: the name of the new parameter
1834 * Creates a new parameter named @name.
1836 * Returns: A new #EVCardAttributeParam.
1838 EVCardAttributeParam *
1839 e_vcard_attribute_param_new (const gchar *name)
1841 EVCardAttributeParam *param = g_slice_new (EVCardAttributeParam);
1842 param->values = NULL;
1843 param->name = g_strdup (name);
1849 * e_vcard_attribute_param_free:
1850 * @param: an #EVCardAttributeParam
1852 * Frees @param and its values.
1855 e_vcard_attribute_param_free (EVCardAttributeParam *param)
1857 g_return_if_fail (param != NULL);
1859 g_free (param->name);
1861 e_vcard_attribute_param_remove_values (param);
1863 g_slice_free (EVCardAttributeParam, param);
1867 * e_vcard_attribute_param_copy:
1868 * @param: an #EVCardAttributeParam
1870 * Makes a copy of @param.
1872 * Returns: a new #EVCardAttributeParam identical to @param.
1874 EVCardAttributeParam *
1875 e_vcard_attribute_param_copy (EVCardAttributeParam *param)
1877 EVCardAttributeParam *p;
1880 g_return_val_if_fail (param != NULL, NULL);
1882 p = e_vcard_attribute_param_new (e_vcard_attribute_param_get_name (param));
1884 for (l = param->values; l; l = l->next) {
1885 e_vcard_attribute_param_add_value (p, l->data);
1892 * e_vcard_attribute_add_param:
1893 * @attr: an #EVCardAttribute
1894 * @param: (transfer full): an #EVCardAttributeParam to add
1896 * Adds @param to @attr's list of parameters.
1897 * It tests for duplicities, only new parameters are added,
1898 * when a new parameter already exists in attr, then those
1899 * values are merged, also without creating duplicities.
1900 * When we will not add whole param, then it's freed here.
1903 e_vcard_attribute_add_param (EVCardAttribute *attr,
1904 EVCardAttributeParam *param)
1908 const gchar *par_name;
1910 g_return_if_fail (attr != NULL);
1911 g_return_if_fail (param != NULL);
1914 params = attr->params;
1915 par_name = param->name;
1917 for (p = params; p; p = p->next) {
1918 EVCardAttributeParam *param2 = p->data;
1919 if (g_ascii_strcasecmp (param2->name, par_name) == 0) {
1920 /* param2 has same name as our new param;
1921 * better merge them than have more parameters
1922 * with same name within one attribute.
1926 vals = param->values;
1928 for (v = vals; v; v = v->next) {
1929 const gchar *my_value;
1932 my_value = (const gchar *) v->data;
1933 vals2 = param2->values;
1935 for (v2 = vals2; v2; v2 = v2->next) {
1936 if (g_ascii_strcasecmp ((const gchar *) v2->data, my_value) == 0) {
1942 /* we did loop through all values and none of them was my_value */
1943 e_vcard_attribute_param_add_value (param2, my_value);
1953 attr->params = g_list_prepend (attr->params, param);
1956 /* we handle our special encoding stuff here */
1958 if (!g_ascii_strcasecmp (param->name, EVC_ENCODING)) {
1959 if (attr->encoding_set) {
1960 g_warning ("ENCODING specified twice");
1962 e_vcard_attribute_param_free (param);
1967 if (param->values && param->values->data) {
1968 if (!g_ascii_strcasecmp ((gchar *) param->values->data, "b") ||
1969 !g_ascii_strcasecmp ((gchar *) param->values->data, "BASE64"))
1970 attr->encoding = EVC_ENCODING_BASE64;
1971 else if (!g_ascii_strcasecmp ((gchar *) param->values->data, EVC_QUOTEDPRINTABLE))
1972 attr->encoding = EVC_ENCODING_QP;
1975 "Unknown value `%s' for ENCODING parameter. values will be treated as raw",
1976 (gchar *) param->values->data);
1979 attr->encoding_set = TRUE;
1982 g_warning ("ENCODING parameter added with no value");
1987 e_vcard_attribute_param_free (param);
1992 * e_vcard_attribute_param_add_value:
1993 * @param: an #EVCardAttributeParam
1994 * @value: a string value to add
1996 * Adds @value to @param's list of values.
1999 e_vcard_attribute_param_add_value (EVCardAttributeParam *param,
2002 g_return_if_fail (param != NULL);
2004 param->values = g_list_append (param->values, g_strdup (value));
2008 * e_vcard_attribute_param_add_values:
2009 * @param: an #EVCardAttributeParam
2010 * @...: a %NULL-terminated list of strings
2012 * Adds a list of values to @param.
2015 e_vcard_attribute_param_add_values (EVCardAttributeParam *param,
2021 g_return_if_fail (param != NULL);
2023 va_start (ap, param);
2025 while ((v = va_arg (ap, gchar *))) {
2026 e_vcard_attribute_param_add_value (param, v);
2033 * e_vcard_attribute_add_param_with_value:
2034 * @attr: an #EVCardAttribute
2035 * @param: (transfer full): an #EVCardAttributeParam
2036 * @value: a string value
2038 * Adds @value to @param, then adds @param to @attr.
2041 e_vcard_attribute_add_param_with_value (EVCardAttribute *attr,
2042 EVCardAttributeParam *param,
2045 g_return_if_fail (attr != NULL);
2046 g_return_if_fail (param != NULL);
2048 e_vcard_attribute_param_add_value (param, value);
2050 e_vcard_attribute_add_param (attr, param);
2054 * e_vcard_attribute_add_param_with_values:
2055 * @attr: an #EVCardAttribute
2056 * @param: (transfer full): an #EVCardAttributeParam
2057 * @...: a %NULL-terminated list of strings
2059 * Adds the list of values to @param, then adds @param
2063 e_vcard_attribute_add_param_with_values (EVCardAttribute *attr,
2064 EVCardAttributeParam *param, ...)
2069 g_return_if_fail (attr != NULL);
2070 g_return_if_fail (param != NULL);
2072 va_start (ap, param);
2074 while ((v = va_arg (ap, gchar *))) {
2075 e_vcard_attribute_param_add_value (param, v);
2080 e_vcard_attribute_add_param (attr, param);
2084 * e_vcard_attribute_param_remove_values:
2085 * @param: an #EVCardAttributeParam
2087 * Removes and frees all values from @param.
2090 e_vcard_attribute_param_remove_values (EVCardAttributeParam *param)
2092 g_return_if_fail (param != NULL);
2094 g_list_foreach (param->values, (GFunc) g_free, NULL);
2095 g_list_free (param->values);
2096 param->values = NULL;
2100 * e_vcard_attribute_remove_param_value:
2101 * @attr: an #EVCardAttribute
2102 * @param_name: a parameter name
2105 * Removes the value @s from the parameter @param_name on the attribute @attr.
2108 e_vcard_attribute_remove_param_value (EVCardAttribute *attr,
2109 const gchar *param_name,
2113 EVCardAttributeParam *param;
2115 g_return_if_fail (attr != NULL);
2116 g_return_if_fail (param_name != NULL);
2117 g_return_if_fail (s != NULL);
2119 params = e_vcard_attribute_get_params (attr);
2121 for (l = params; l; l = l->next) {
2123 if (g_ascii_strcasecmp (e_vcard_attribute_param_get_name (param), param_name) == 0) {
2124 l = g_list_find_custom (param->values, s, (GCompareFunc) strcmp);
2129 param->values = g_list_delete_link (param->values, l);
2130 if (param->values == NULL) {
2131 e_vcard_attribute_param_free (param);
2132 attr->params = g_list_remove (attr->params, param);
2141 * e_vcard_get_attributes:
2142 * @evcard: an #EVCard
2144 * Gets the list of attributes from @evcard. The list and its
2145 * contents are owned by @evcard, and must not be freed.
2147 * Returns: (transfer none) (element-type EVCardAttribute): A list of attributes
2148 * of type #EVCardAttribute.
2151 e_vcard_get_attributes (EVCard *evcard)
2153 g_return_val_if_fail (E_IS_VCARD (evcard), NULL);
2155 return e_vcard_ensure_attributes (evcard);
2159 * e_vcard_get_attribute:
2161 * @name: the name of the attribute to get
2163 * Get the attribute @name from @evc. The #EVCardAttribute is owned by
2164 * @evcard and should not be freed. If the attribute does not exist, %NULL is
2167 * Returns: (transfer none) (allow-none): An #EVCardAttribute if found, or %NULL.
2170 e_vcard_get_attribute (EVCard *evc,
2174 EVCardAttribute *attr;
2176 g_return_val_if_fail (E_IS_VCARD (evc), NULL);
2177 g_return_val_if_fail (name != NULL, NULL);
2179 /* Handle UID special case */
2180 if (evc->priv->vcard != NULL && g_ascii_strcasecmp (name, EVC_UID) == 0) {
2181 for (l = evc->priv->attributes; l != NULL; l = l->next) {
2182 attr = (EVCardAttribute *) l->data;
2183 if (g_ascii_strcasecmp (attr->name, name) == 0)
2188 attrs = e_vcard_ensure_attributes (evc);
2189 for (l = attrs; l; l = l->next) {
2190 attr = (EVCardAttribute *) l->data;
2191 if (g_ascii_strcasecmp (attr->name, name) == 0)
2199 * e_vcard_get_attribute_if_parsed:
2201 * @name: the name of the attribute to get
2203 * Similar to e_vcard_get_attribute() but this method will not attempt to
2204 * parse the vcard if not already parsed.
2206 * Returns: (transfer none) (allow-none): An #EVCardAttribute if found, or %NULL.
2211 e_vcard_get_attribute_if_parsed (EVCard *evc,
2215 EVCardAttribute *attr;
2217 g_return_val_if_fail (E_IS_VCARD (evc), NULL);
2218 g_return_val_if_fail (name != NULL, NULL);
2220 for (l = evc->priv->attributes; l != NULL; l = l->next) {
2221 attr = (EVCardAttribute *) l->data;
2222 if (g_ascii_strcasecmp (attr->name, name) == 0)
2230 * e_vcard_attribute_get_group:
2231 * @attr: an #EVCardAttribute
2233 * Gets the group name of @attr.
2235 * Returns: (allow-none): The attribute's group name, or %NULL.
2238 e_vcard_attribute_get_group (EVCardAttribute *attr)
2240 g_return_val_if_fail (attr != NULL, NULL);
2246 * e_vcard_attribute_get_name:
2247 * @attr: an #EVCardAttribute
2249 * Gets the name of @attr.
2251 * Returns: The attribute's name.
2254 e_vcard_attribute_get_name (EVCardAttribute *attr)
2256 g_return_val_if_fail (attr != NULL, NULL);
2262 * e_vcard_attribute_get_values:
2263 * @attr: an #EVCardAttribute
2265 * Gets the list of values from @attr. The list and its
2266 * contents are owned by @attr, and must not be freed.
2268 * Returns: (transfer none) (element-type utf8): A list of string values. They
2269 * will all be non-%NULL, but may be empty strings. The list itself may be
2273 e_vcard_attribute_get_values (EVCardAttribute *attr)
2275 g_return_val_if_fail (attr != NULL, NULL);
2277 return attr->values;
2281 * e_vcard_attribute_get_values_decoded:
2282 * @attr: an #EVCardAttribute
2284 * Gets the list of values from @attr, decoding them if
2285 * necessary. The list and its contents are owned by @attr,
2286 * and must not be freed.
2288 * Returns: (transfer none) (element-type GString): A list of values of type #GString.
2291 e_vcard_attribute_get_values_decoded (EVCardAttribute *attr)
2293 g_return_val_if_fail (attr != NULL, NULL);
2295 if (!attr->decoded_values) {
2297 switch (attr->encoding) {
2298 case EVC_ENCODING_RAW:
2299 for (l = attr->values; l; l = l->next)
2300 attr->decoded_values = g_list_prepend (attr->decoded_values, g_string_new ((gchar *) l->data));
2301 attr->decoded_values = g_list_reverse (attr->decoded_values);
2303 case EVC_ENCODING_BASE64:
2304 for (l = attr->values; l; l = l->next) {
2308 decoded = g_base64_decode (l->data, &len);
2309 attr->decoded_values = g_list_prepend (attr->decoded_values, g_string_new_len ((gchar *) decoded, len));
2312 attr->decoded_values = g_list_reverse (attr->decoded_values);
2314 case EVC_ENCODING_QP:
2315 g_warning ("need to implement quoted printable decoding");
2320 return attr->decoded_values;
2324 * e_vcard_attribute_is_single_valued:
2325 * @attr: an #EVCardAttribute
2327 * Checks if @attr has a single value.
2329 * Returns: %TRUE if the attribute has exactly one value, %FALSE otherwise.
2332 e_vcard_attribute_is_single_valued (EVCardAttribute *attr)
2334 g_return_val_if_fail (attr != NULL, FALSE);
2336 if (attr->values == NULL
2337 || attr->values->next != NULL)
2344 * e_vcard_attribute_get_value:
2345 * @attr: an #EVCardAttribute
2347 * Gets the value of a single-valued #EVCardAttribute, @attr.
2349 * Returns: (allow-none): A newly allocated string representing the value, or %NULL if the attribute has no value.
2352 e_vcard_attribute_get_value (EVCardAttribute *attr)
2356 g_return_val_if_fail (attr != NULL, NULL);
2358 values = e_vcard_attribute_get_values (attr);
2360 if (!e_vcard_attribute_is_single_valued (attr))
2361 g_warning ("e_vcard_attribute_get_value called on multivalued attribute");
2363 return values ? g_strdup ((gchar *) values->data) : NULL;
2367 * e_vcard_attribute_get_value_decoded:
2368 * @attr: an #EVCardAttribute
2370 * Gets the value of a single-valued #EVCardAttribute, @attr, decoding
2373 * Note: this function seems currently to be unused. Could be removed.
2375 * Returns: (allow-none): A newly allocated #GString representing the value, or %NULL if the attribute has no value.
2378 e_vcard_attribute_get_value_decoded (EVCardAttribute *attr)
2381 GString *str = NULL;
2383 g_return_val_if_fail (attr != NULL, NULL);
2385 values = e_vcard_attribute_get_values_decoded (attr);
2387 if (!e_vcard_attribute_is_single_valued (attr))
2388 g_warning ("e_vcard_attribute_get_value_decoded called on multivalued attribute");
2393 return str ? g_string_new_len (str->str, str->len) : NULL;
2397 * e_vcard_attribute_has_type:
2398 * @attr: an #EVCardAttribute
2399 * @typestr: a string representing the type
2401 * Checks if @attr has an #EVCardAttributeParam of the specified type.
2403 * Returns: %TRUE if such a parameter exists, %FALSE otherwise.
2406 e_vcard_attribute_has_type (EVCardAttribute *attr,
2407 const gchar *typestr)
2412 g_return_val_if_fail (attr != NULL, FALSE);
2413 g_return_val_if_fail (typestr != NULL, FALSE);
2415 params = e_vcard_attribute_get_params (attr);
2417 for (p = params; p; p = p->next) {
2418 EVCardAttributeParam *param = p->data;
2420 if (!g_ascii_strcasecmp (e_vcard_attribute_param_get_name (param), EVC_TYPE)) {
2421 GList *values = e_vcard_attribute_param_get_values (param);
2424 for (v = values; v; v = v->next) {
2425 if (!g_ascii_strcasecmp ((gchar *) v->data, typestr))
2435 * e_vcard_attribute_get_params:
2436 * @attr: an #EVCardAttribute
2438 * Gets the list of parameters from @attr. The list and its
2439 * contents are owned by @attr, and must not be freed.
2441 * Returns: (transfer none) (element-type EVCardAttributeParam): A list of
2442 * elements of type #EVCardAttributeParam.
2445 e_vcard_attribute_get_params (EVCardAttribute *attr)
2447 g_return_val_if_fail (attr != NULL, NULL);
2449 return attr->params;
2453 * e_vcard_attribute_get_param:
2454 * @attr: an #EVCardAttribute
2455 * @name: a parameter name
2457 * Gets the list of values for the paramater @name from @attr. The list and its
2458 * contents are owned by @attr, and must not be freed.
2460 * Returns: (transfer none) (element-type utf8): A list of string elements
2461 * representing the parameter's values.
2464 e_vcard_attribute_get_param (EVCardAttribute *attr,
2469 g_return_val_if_fail (attr != NULL, NULL);
2470 g_return_val_if_fail (name != NULL, NULL);
2472 params = e_vcard_attribute_get_params (attr);
2474 for (p = params; p; p = p->next) {
2475 EVCardAttributeParam *param = p->data;
2476 if (g_ascii_strcasecmp (e_vcard_attribute_param_get_name (param), name) == 0) {
2477 return e_vcard_attribute_param_get_values (param);
2485 * e_vcard_is_parsed:
2488 * Check if the @evc has been parsed already. Used for debugging.
2490 * Return value: %TRUE if @evc has been parsed, %FALSE otherwise.
2495 e_vcard_is_parsed (EVCard *evc)
2497 g_return_val_if_fail (E_IS_VCARD (evc), FALSE);
2499 return (!evc->priv->vcard && evc->priv->attributes);
2503 * e_vcard_attribute_param_get_name:
2504 * @param: an #EVCardAttributeParam
2506 * Gets the name of @param.
2508 * Returns: The name of the parameter.
2511 e_vcard_attribute_param_get_name (EVCardAttributeParam *param)
2513 g_return_val_if_fail (param != NULL, NULL);
2519 * e_vcard_attribute_param_get_values:
2520 * @param: an #EVCardAttributeParam
2522 * Gets the list of values from @param. The list and its
2523 * contents are owned by @param, and must not be freed.
2525 * Returns: (transfer none) (element-type utf8): A list of string elements
2526 * representing the parameter's values.
2529 e_vcard_attribute_param_get_values (EVCardAttributeParam *param)
2531 g_return_val_if_fail (param != NULL, NULL);
2533 return param->values;