1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
4 * Copyright (C) 2003 Ximian, Inc.
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
37 /** Encoding used in v-card
38 * Note: v-card spec defines additional 7BIT 8BIT and X- encoding
41 EVC_ENCODING_RAW, /* no encoding */
42 EVC_ENCODING_BASE64, /* base64 */
43 EVC_ENCODING_QP /* quoted-printable */
46 struct _EVCardPrivate {
50 struct _EVCardAttribute {
53 GList *params; /* EVCardParam */
55 GList *decoded_values;
56 EVCardEncoding encoding;
57 gboolean encoding_set;
60 struct _EVCardAttributeParam {
62 GList *values; /* GList of char*'s*/
65 static GObjectClass *parent_class;
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);
74 e_vcard_dispose (GObject *object)
76 EVCard *evc = E_VCARD (object);
80 g_list_foreach (evc->priv->attributes, (GFunc)e_vcard_attribute_free, NULL);
81 g_list_free (evc->priv->attributes);
87 if (G_OBJECT_CLASS (parent_class)->dispose)
88 G_OBJECT_CLASS (parent_class)->dispose (object);
92 e_vcard_class_init (EVCardClass *klass)
94 GObjectClass *object_class;
96 object_class = G_OBJECT_CLASS(klass);
98 parent_class = g_type_class_ref (G_TYPE_OBJECT);
100 object_class->dispose = e_vcard_dispose;
106 e_vcard_init (EVCard *evc)
108 evc->priv = g_new0 (EVCardPrivate, 1);
112 e_vcard_get_type (void)
114 static GType vcard_type = 0;
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 */
126 (GInstanceInitFunc) e_vcard_init,
129 vcard_type = g_type_register_static (G_TYPE_OBJECT, "EVCard", &vcard_info, 0);
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.
143 skip_newline (char *str, gboolean quoted_printable)
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 */
158 if ((*p == '\r' || *p == '\n') && *p != *next ) {
159 p = g_utf8_next_char (p); /* swallow second newline */
161 if (*p == ' ' || *p == '\t') {
162 p = g_utf8_next_char (p); /* swallow whitespace */
168 /* -- swallow newline and (if present) following whitespaces */
169 } else if (*p == '\r' || *p == '\n') {
171 next = g_utf8_next_char (p);
172 if ((*next == '\n' || *next == '\r') && *p != *next) {
174 next2 = g_utf8_next_char (next);
175 if (*next2 == ' ' || *next2 == '\t') {
176 p = g_utf8_next_char (next2); /* we found a line folding */
179 } else if (*next == ' ' || *next == '\t') {
180 p = g_utf8_next_char (next); /* we found a line folding */
188 /* skip forward until we hit the CRLF, or \0 */
190 skip_to_next_line (char **p)
195 while (*lp != '\n' && *lp != '\r' && *lp != '\0')
196 lp = g_utf8_next_char (lp);
198 /* -- skip over the endline */
199 while( *lp == '\r' || *lp == '\n' ) {
200 lp = g_utf8_next_char (lp);
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 */
209 skip_until (char **p, char *s)
215 while (*lp != '\r' && *lp != '\0') {
216 gboolean s_matches = FALSE;
218 for (ls = s; *ls; ls = g_utf8_next_char (ls)) {
219 if (g_utf8_get_char (ls) == g_utf8_get_char (lp)) {
227 lp = g_utf8_next_char (lp);
234 read_attribute_value (EVCardAttribute *attr, char **p, gboolean quoted_printable)
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 ) ) {
245 if (*lp == '=' && quoted_printable) {
247 if ((a = *(++lp)) == '\0') break;
248 if ((b = *(++lp)) == '\0') break;
249 if (isxdigit(a) && isxdigit (b)) {
255 c = (((a>='a'?a-'a'+10:a-'0')&0x0f) << 4)
256 | ((b>='a'?b-'a'+10:b-'0')&0x0f);
258 g_string_append_c (str, c); /* add decoded byte (this is not a unicode yet) */
262 g_string_append_c (str, a);
263 g_string_append_c (str, b);
268 } else if (*lp == '\\') {
269 /* convert back to the non-escaped version of
271 lp = g_utf8_next_char(lp);
273 g_string_append_c (str, '\\');
277 /* beware, there might be a line break due to folding,
278 * need next real character
280 lp = skip_newline (lp, quoted_printable);
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;
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));
296 lp = g_utf8_next_char(lp);
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);
305 g_string_append_unichar (str, g_utf8_get_char (lp));
306 lp = g_utf8_next_char(lp);
310 e_vcard_attribute_add_value (attr, str->str);
311 g_string_free (str, TRUE);
314 skip_to_next_line( &lp );
320 read_attribute_params (EVCardAttribute *attr, char **p, gboolean *quoted_printable)
324 EVCardAttributeParam *param = NULL;
325 gboolean in_quote = FALSE;
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 ) ) {
333 in_quote = !in_quote;
334 lp = g_utf8_next_char (lp);
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);
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.)
346 else if (*lp == '=') {
348 param = e_vcard_attribute_param_new (str->str);
349 g_string_assign (str, "");
350 lp = g_utf8_next_char (lp);
353 skip_until (&lp, ":;");
355 lp = g_utf8_next_char (lp);
357 } else if (*lp == ':') {
361 skip_to_next_line( &lp );
366 else if (*lp == ';' || *lp == ':' || *lp == ',') {
367 gboolean colon = (*lp == ':');
368 gboolean comma = (*lp == ',');
372 e_vcard_attribute_param_add_value (param, str->str);
373 g_string_assign (str, "");
375 lp = g_utf8_next_char (lp);
378 /* we've got a parameter of the form:
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.
386 if (!param->values) {
387 e_vcard_attribute_param_free (param);
390 lp = g_utf8_next_char (lp);
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);
405 if (!g_ascii_strcasecmp (str->str,
406 "quoted-printable")) {
407 param_name = "ENCODING";
408 *quoted_printable = TRUE;
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,
414 param_name = "ENCODING";
415 g_string_assign (str, "b");
422 param = e_vcard_attribute_param_new (param_name);
423 e_vcard_attribute_param_add_value (param, str->str);
425 g_string_assign (str, "");
427 lp = g_utf8_next_char (lp);
430 /* we've got an attribute with a truly empty
431 attribute parameter. So it's of the form:
433 ATTR;[PARAM=value;]*;[PARAM=value;]*:
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 ':' */
443 lp = g_utf8_next_char (lp);
446 if (param && !comma) {
447 e_vcard_attribute_add_param (attr, param);
454 g_warning ("invalid character found in parameter spec");
455 g_string_assign (str, "");
456 /* skip_until (&lp, ":;"); */
458 skip_to_next_line( &lp );
463 g_string_free (str, TRUE);
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)
473 char *attr_group = NULL;
474 char *attr_name = NULL;
475 EVCardAttribute *attr = NULL;
478 gboolean is_qp = FALSE;
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 ) ) {
486 if (*lp == ':' || *lp == ';') {
488 /* we've got a name, break out to the value/attribute parsing */
489 attr_name = g_string_free (str, FALSE);
493 /* a line of the form:
496 * since we don't have an attribute
497 * name, skip to the end of the line
500 g_string_free (str, TRUE);
502 skip_to_next_line(p);
506 else if (*lp == '.') {
508 g_warning ("extra `.' in attribute specification. ignoring extra group `%s'",
510 g_string_free (str, TRUE);
511 str = g_string_new ("");
514 attr_group = g_string_free (str, FALSE);
515 str = g_string_new ("");
518 else if (g_unichar_isalnum (g_utf8_get_char (lp)) || *lp == '-' || *lp == '_') {
519 g_string_append_unichar (str, g_utf8_get_char (lp));
522 g_warning ("invalid character found in attribute group/name");
523 g_string_free (str, TRUE);
525 skip_to_next_line(p);
529 lp = g_utf8_next_char(lp);
533 skip_to_next_line (p);
537 attr = e_vcard_attribute_new (attr_group, attr_name);
542 /* skip past the ';' */
543 lp = g_utf8_next_char(lp);
544 read_attribute_params (attr, &lp, &is_qp);
546 attr->encoding = EVC_ENCODING_RAW;
549 /* skip past the ':' */
550 lp = g_utf8_next_char(lp);
551 read_attribute_value (attr, &lp, is_qp);
562 e_vcard_attribute_free (attr);
566 /* Stolen from glib/glib/gconvert.c */
568 make_valid_utf8 (const gchar *name)
571 const gchar *remainder, *invalid;
572 gint remaining_bytes, valid_bytes;
576 remaining_bytes = strlen (name);
578 while (remaining_bytes != 0) {
579 if (g_utf8_validate (remainder, remaining_bytes, &invalid))
581 valid_bytes = invalid - remainder;
584 string = g_string_sized_new (remaining_bytes);
586 g_string_append_len (string, remainder, valid_bytes);
587 /* append U+FFFD REPLACEMENT CHARACTER */
588 g_string_append (string, "\357\277\275");
590 remaining_bytes -= valid_bytes + 1;
591 remainder = invalid + 1;
595 return g_strdup (name);
597 g_string_append (string, remainder);
599 g_assert (g_utf8_validate (string->str, -1, NULL));
601 return g_string_free (string, FALSE);
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*.
609 parse (EVCard *evc, const char *str)
613 EVCardAttribute *attr;
615 buf = make_valid_utf8 (str);
617 //buf = fold_lines (buf);
619 d(printf ("BEFORE FOLDING:\n"));
621 d(printf ("\n\nAFTER FOLDING:\n"));
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");
630 if (attr && !g_ascii_strcasecmp (attr->name, "begin"))
631 e_vcard_attribute_free (attr);
633 e_vcard_add_attribute (evc, attr);
636 EVCardAttribute *next_attr = read_attribute (&p);
639 if (g_ascii_strcasecmp (next_attr->name, "end"))
640 e_vcard_add_attribute (evc, next_attr);
645 if (!attr || attr->group || g_ascii_strcasecmp (attr->name, "end")) {
646 g_warning ("vcard ended without END:VCARD\n");
649 if (attr && !g_ascii_strcasecmp (attr->name, "end"))
650 e_vcard_attribute_free (attr);
654 evc->priv->attributes = g_list_reverse (evc->priv->attributes);
658 * e_vcard_escape_string:
659 * @s: the string to escape
661 * Escapes a string according to RFC2426, section 5.
663 * Return value: A newly allocated, escaped string.
666 e_vcard_escape_string (const char *s)
671 str = g_string_new ("");
673 /* Escape a string as described in RFC2426, section 5 */
674 for (p = s; p && *p; p++) {
677 g_string_append (str, "\\n");
682 g_string_append (str, "\\n");
685 g_string_append (str, "\\;");
688 g_string_append (str, "\\,");
691 g_string_append (str, "\\\\");
694 g_string_append_c (str, *p);
699 return g_string_free (str, FALSE);
703 * e_vcard_unescape_string:
704 * @s: the string to unescape
706 * Unescapes a string according to RFC2426, section 5.
708 * Return value: A newly allocated, unescaped string.
711 e_vcard_unescape_string (const char *s)
716 g_return_val_if_fail (s != NULL, NULL);
718 str = g_string_new ("");
720 /* Unescape a string as described in RFC2426, section 5 */
721 for (p = s; *p; p++) {
725 g_string_append_c (str, '\\');
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;
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));
743 return g_string_free (str, FALSE);
747 e_vcard_construct (EVCard *evc, const char *str)
749 g_return_if_fail (E_IS_VCARD (evc));
750 g_return_if_fail (str != NULL);
759 * Creates a new, blank #EVCard.
761 * Return value: A new, blank #EVCard.
766 return e_vcard_new_from_string ("");
770 * e_vcard_new_from_string:
771 * @str: a string representation of the vcard to create
773 * Creates a new #EVCard from the passed-in string
776 * Return value: A new #EVCard.
779 e_vcard_new_from_string (const char *str)
783 g_return_val_if_fail (str != NULL, NULL);
785 evc = g_object_new (E_TYPE_VCARD, NULL);
787 e_vcard_construct (evc, str);
793 e_vcard_to_string_vcard_21 (EVCard *evc)
795 g_warning ("need to implement e_vcard_to_string_vcard_21");
796 return g_strdup ("");
800 e_vcard_to_string_vcard_30 (EVCard *evc)
805 GString *str = g_string_new ("");
807 g_string_append (str, "BEGIN:VCARD" CRLF);
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);
814 for (l = evc->priv->attributes; l; l = l->next) {
816 EVCardAttribute *attr = l->data;
820 if (!g_ascii_strcasecmp (attr->name, "VERSION"))
823 attr_str = g_string_new ("");
825 /* From rfc2425, 5.8.2
827 * contentline = [group "."] name *(";" param) ":" value CRLF
831 g_string_append (attr_str, attr->group);
832 g_string_append_c (attr_str, '.');
834 g_string_append (attr_str, attr->name);
836 /* handle the parameters */
837 for (list = attr->params; list; list = list->next) {
838 EVCardAttributeParam *param = list->data;
840 * param = param-name "=" param-value *("," param-value)
842 g_string_append_c (attr_str, ';');
843 g_string_append (attr_str, param->name);
845 g_string_append_c (attr_str, '=');
846 for (v = param->values; v; v = v->next) {
847 char *value = v->data;
849 gboolean quotes = FALSE;
851 if (!g_unichar_isalnum (g_utf8_get_char (pval))) {
855 pval = g_utf8_next_char (pval);
858 g_string_append_c (attr_str, '"');
859 g_string_append (attr_str, value);
861 g_string_append_c (attr_str, '"');
863 g_string_append_c (attr_str, ',');
868 g_string_append_c (attr_str, ':');
870 for (v = attr->values; v; v = v->next) {
871 char *value = v->data;
872 char *escaped_value = NULL;
874 escaped_value = e_vcard_escape_string (value);
876 g_string_append (attr_str, escaped_value);
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, ',');
884 g_string_append_c (attr_str, ';');
887 g_free (escaped_value);
891 * When generating a content line, lines longer than 75
892 * characters SHOULD be folded
894 len = g_utf8_strlen (attr_str->str, -1);
896 GString *fold_str = g_string_sized_new (attr_str->len + len/74*3);
897 gchar *pos1 = attr_str->str;
899 pos2 = g_utf8_offset_to_pointer (pos2, 75);
902 g_string_append_len (fold_str, pos1, pos2 - pos1);
903 g_string_append (fold_str, CRLF " ");
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);
911 g_string_append (attr_str, CRLF);
913 g_string_append (str, attr_str->str);
914 g_string_free (attr_str, TRUE);
917 g_string_append (str, "END:VCARD");
919 return g_string_free (str, FALSE);
924 * @evc: the #EVCard to export
925 * @format: the format to export to
927 * Exports @evc to a string representation, specified
928 * by the @format argument.
930 * Return value: A newly allocated string representing the vcard.
933 e_vcard_to_string (EVCard *evc, EVCardFormat format)
935 g_return_val_if_fail (E_IS_VCARD (evc), NULL);
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);
943 g_warning ("invalid format specifier passed to e_vcard_to_string");
944 return g_strdup ("");
949 * e_vcard_dump_structure:
950 * @evc: the #EVCard to dump
952 * Prints a dump of @evc's structure to stdout. Used for
956 e_vcard_dump_structure (EVCard *evc)
962 g_return_if_fail (E_IS_VCARD (evc));
965 for (a = evc->priv->attributes; a; a = a->next) {
967 EVCardAttribute *attr = a->data;
968 printf ("+-- %s\n", attr->name);
970 printf (" +- params=\n");
972 for (p = attr->params, i = 0; p; p = p->next, i++) {
973 EVCardAttributeParam *param = p->data;
974 printf (" | [%d] = %s", i,param->name);
976 for (v = param->values; v; v = v->next) {
977 char *value = e_vcard_escape_string ((char*)v->data);
978 printf ("%s", value);
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);
995 * e_vcard_attribute_new:
996 * @attr_group: a group name
997 * @attr_name: an attribute name
999 * Creates a new #EVCardAttribute with the specified group and
1002 * Return value: A new #EVCardAttribute.
1005 e_vcard_attribute_new (const char *attr_group, const char *attr_name)
1007 EVCardAttribute *attr;
1009 attr = g_slice_new0 (EVCardAttribute);
1011 attr->group = g_strdup (attr_group);
1012 attr->name = g_strdup (attr_name);
1018 * e_vcard_attribute_free:
1019 * @attr: attribute to free
1021 * Frees an attribute, its values and its parameters.
1024 e_vcard_attribute_free (EVCardAttribute *attr)
1026 g_return_if_fail (attr != NULL);
1028 g_free (attr->group);
1029 g_free (attr->name);
1031 e_vcard_attribute_remove_values (attr);
1033 e_vcard_attribute_remove_params (attr);
1035 g_slice_free (EVCardAttribute, attr);
1039 * e_vcard_attribute_copy:
1040 * @attr: attribute to copy
1042 * Makes a copy of @attr.
1044 * Return value: A new #EVCardAttribute identical to @attr.
1047 e_vcard_attribute_copy (EVCardAttribute *attr)
1052 g_return_val_if_fail (attr != NULL, NULL);
1054 a = e_vcard_attribute_new (attr->group, attr->name);
1056 for (p = attr->values; p; p = p->next)
1057 e_vcard_attribute_add_value (a, p->data);
1059 for (p = attr->params; p; p = p->next)
1060 e_vcard_attribute_add_param (a, e_vcard_attribute_param_copy (p->data));
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
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.
1077 e_vcard_remove_attributes (EVCard *evc, const char *attr_group, const char *attr_name)
1081 g_return_if_fail (E_IS_VCARD (evc));
1082 g_return_if_fail (attr_name != NULL);
1084 attr = evc->priv->attributes;
1087 EVCardAttribute *a = attr->data;
1089 next_attr = attr->next;
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))) {
1095 /* matches, remove/delete the attribute */
1096 evc->priv->attributes = g_list_delete_link (evc->priv->attributes, attr);
1098 e_vcard_attribute_free (a);
1106 * e_vcard_remove_attribute:
1108 * @attr: an #EVCardAttribute to remove
1110 * Removes @attr from @evc and frees it.
1113 e_vcard_remove_attribute (EVCard *evc, EVCardAttribute *attr)
1115 g_return_if_fail (E_IS_VCARD (evc));
1116 g_return_if_fail (attr != NULL);
1118 evc->priv->attributes = g_list_remove (evc->priv->attributes, attr);
1119 e_vcard_attribute_free (attr);
1123 * e_vcard_add_attribute:
1125 * @attr: an #EVCardAttribute to add
1127 * Adds @attr to @evc.
1130 e_vcard_add_attribute (EVCard *evc, EVCardAttribute *attr)
1132 g_return_if_fail (E_IS_VCARD (evc));
1133 g_return_if_fail (attr != NULL);
1135 evc->priv->attributes = g_list_prepend (evc->priv->attributes, attr);
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
1144 * Adds @attr to @evcard, setting it to @value.
1147 e_vcard_add_attribute_with_value (EVCard *evcard,
1148 EVCardAttribute *attr, const char *value)
1150 g_return_if_fail (E_IS_VCARD (evcard));
1151 g_return_if_fail (attr != NULL);
1153 e_vcard_attribute_add_value (attr, value);
1155 e_vcard_add_attribute (evcard, attr);
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
1164 * Adds @attr to @evcard, assigning the list of values to it.
1167 e_vcard_add_attribute_with_values (EVCard *evcard, EVCardAttribute *attr, ...)
1172 g_return_if_fail (E_IS_VCARD (evcard));
1173 g_return_if_fail (attr != NULL);
1175 va_start (ap, attr);
1177 while ((v = va_arg (ap, char*))) {
1178 e_vcard_attribute_add_value (attr, v);
1183 e_vcard_add_attribute (evcard, attr);
1187 * e_vcard_attribute_add_value:
1188 * @attr: an #EVCardAttribute
1189 * @value: a string value
1191 * Adds @value to @attr's list of values.
1194 e_vcard_attribute_add_value (EVCardAttribute *attr, const char *value)
1196 g_return_if_fail (attr != NULL);
1198 attr->values = g_list_append (attr->values, g_strdup (value));
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
1207 * Decodes @value according to the encoding used for @attr, and
1208 * adds it to @attr's list of values.
1211 e_vcard_attribute_add_value_decoded (EVCardAttribute *attr, const char *value, int len)
1213 g_return_if_fail (attr != NULL);
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");
1219 case EVC_ENCODING_BASE64: {
1220 char *b64_data = _evc_base64_encode_simple (value, len);
1221 GString *decoded = g_string_new_len (value, len);
1223 /* make sure the decoded list is up to date */
1224 e_vcard_attribute_get_values_decoded (attr);
1226 d(printf ("base64 encoded value: %s\n", b64_data));
1227 d(printf ("original length: %d\n", len));
1229 attr->values = g_list_append (attr->values, b64_data);
1230 attr->decoded_values = g_list_append (attr->decoded_values, decoded);
1233 case EVC_ENCODING_QP:
1234 g_warning ("need to implement quoted printable decoding");
1240 * e_vcard_attribute_add_values:
1241 * @attr: an #EVCardAttribute
1242 * @Varargs: a %NULL-terminated list of strings
1244 * Adds a list of values to @attr.
1247 e_vcard_attribute_add_values (EVCardAttribute *attr,
1253 g_return_if_fail (attr != NULL);
1255 va_start (ap, attr);
1257 while ((v = va_arg (ap, char*))) {
1258 e_vcard_attribute_add_value (attr, v);
1265 free_gstring (GString *str)
1267 g_string_free (str, TRUE);
1271 * e_vcard_attribute_remove_values:
1272 * @attr: an #EVCardAttribute
1274 * Removes all values from @attr.
1277 e_vcard_attribute_remove_values (EVCardAttribute *attr)
1279 g_return_if_fail (attr != NULL);
1281 g_list_foreach (attr->values, (GFunc)g_free, NULL);
1282 g_list_free (attr->values);
1283 attr->values = NULL;
1285 g_list_foreach (attr->decoded_values, (GFunc)free_gstring, NULL);
1286 g_list_free (attr->decoded_values);
1287 attr->decoded_values = NULL;
1291 * e_vcard_attribute_remove_value:
1292 * @attr: an #EVCardAttribute
1293 * @s: an value to remove
1295 * Removes from the value list in @attr the value @s.
1298 e_vcard_attribute_remove_value (EVCardAttribute *attr, const char *s)
1302 g_return_if_fail (attr != NULL);
1303 g_return_if_fail (s != NULL);
1305 l = g_list_find_custom (attr->values, s, (GCompareFunc)strcmp);
1310 attr->values = g_list_delete_link (attr->values, l);
1314 * e_vcard_attribute_remove_param:
1315 * @attr: an #EVCardAttribute
1316 * @param_name: a parameter name
1318 * Removes the parameter @param_name from the attribute @attr.
1323 e_vcard_attribute_remove_param (EVCardAttribute *attr, const char *param_name)
1326 EVCardAttributeParam *param;
1328 g_return_if_fail (attr != NULL);
1329 g_return_if_fail (param_name != NULL);
1331 for (l = attr->params; l; l = l->next) {
1333 if (g_ascii_strcasecmp (e_vcard_attribute_param_get_name (param),
1335 attr->params = g_list_delete_link (attr->params, l);
1336 e_vcard_attribute_param_free(param);
1343 * e_vcard_attribute_remove_params:
1344 * @attr: an #EVCardAttribute
1346 * Removes all parameters from @attr.
1349 e_vcard_attribute_remove_params (EVCardAttribute *attr)
1351 g_return_if_fail (attr != NULL);
1353 g_list_foreach (attr->params, (GFunc)e_vcard_attribute_param_free, NULL);
1354 g_list_free (attr->params);
1355 attr->params = NULL;
1357 /* also remove the cached encoding on this attribute */
1358 attr->encoding_set = FALSE;
1359 attr->encoding = EVC_ENCODING_RAW;
1363 * e_vcard_attribute_param_new:
1364 * @name: the name of the new parameter
1366 * Creates a new parameter named @name.
1368 * Return value: A new #EVCardAttributeParam.
1370 EVCardAttributeParam*
1371 e_vcard_attribute_param_new (const char *name)
1373 EVCardAttributeParam *param = g_slice_new (EVCardAttributeParam);
1374 param->values = NULL;
1375 param->name = g_strdup (name);
1381 * e_vcard_attribute_param_free:
1382 * @param: an #EVCardAttributeParam
1384 * Frees @param and its values.
1387 e_vcard_attribute_param_free (EVCardAttributeParam *param)
1389 g_return_if_fail (param != NULL);
1391 g_free (param->name);
1393 e_vcard_attribute_param_remove_values (param);
1395 g_slice_free (EVCardAttributeParam, param);
1399 * e_vcard_attribute_param_copy:
1400 * @param: an #EVCardAttributeParam
1402 * Makes a copy of @param.
1404 * Return value: a new #EVCardAttributeParam identical to @param.
1406 EVCardAttributeParam*
1407 e_vcard_attribute_param_copy (EVCardAttributeParam *param)
1409 EVCardAttributeParam *p;
1412 g_return_val_if_fail (param != NULL, NULL);
1414 p = e_vcard_attribute_param_new (e_vcard_attribute_param_get_name (param));
1416 for (l = param->values; l; l = l->next) {
1417 e_vcard_attribute_param_add_value (p, l->data);
1424 * e_vcard_attribute_add_param:
1425 * @attr: an #EVCardAttribute
1426 * @param: an #EVCardAttributeParam to add
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.
1435 e_vcard_attribute_add_param (EVCardAttribute *attr,
1436 EVCardAttributeParam *param)
1440 const char *par_name;
1442 g_return_if_fail (attr != NULL);
1443 g_return_if_fail (param != NULL);
1446 params = attr->params;
1447 par_name = param->name;
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.
1458 vals = param->values;
1460 for (v = vals; v; v = v->next) {
1461 const char *my_value;
1464 my_value = (const char *)v->data;
1465 vals2 = param2->values;
1467 for (v2 = vals2; v2; v2 = v2->next) {
1468 if (g_ascii_strcasecmp ((const char *)v2->data, my_value) == 0) {
1474 /* we did loop through all values and none of them was my_value */
1475 e_vcard_attribute_param_add_value (param2, my_value);
1485 attr->params = g_list_prepend (attr->params, param);
1488 /* we handle our special encoding stuff here */
1490 if (!g_ascii_strcasecmp (param->name, EVC_ENCODING)) {
1491 if (attr->encoding_set) {
1492 g_warning ("ENCODING specified twice");
1494 e_vcard_attribute_param_free (param);
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;
1506 g_warning ("Unknown value `%s' for ENCODING parameter. values will be treated as raw",
1507 (char*)param->values->data);
1510 attr->encoding_set = TRUE;
1513 g_warning ("ENCODING parameter added with no value");
1518 e_vcard_attribute_param_free (param);
1523 * e_vcard_attribute_param_add_value:
1524 * @param: an #EVCardAttributeParam
1525 * @value: a string value to add
1527 * Adds @value to @param's list of values.
1530 e_vcard_attribute_param_add_value (EVCardAttributeParam *param,
1533 g_return_if_fail (param != NULL);
1535 param->values = g_list_append (param->values, g_strdup (value));
1539 * e_vcard_attribute_param_add_values:
1540 * @param: an #EVCardAttributeParam
1541 * @Varargs: a %NULL-terminated list of strings
1543 * Adds a list of values to @param.
1546 e_vcard_attribute_param_add_values (EVCardAttributeParam *param,
1552 g_return_if_fail (param != NULL);
1554 va_start (ap, param);
1556 while ((v = va_arg (ap, char*))) {
1557 e_vcard_attribute_param_add_value (param, v);
1564 * e_vcard_attribute_add_param_with_value:
1565 * @attr: an #EVCardAttribute
1566 * @param: an #EVCardAttributeParam
1567 * @value: a string value
1569 * Adds @value to @param, then adds @param to @attr.
1572 e_vcard_attribute_add_param_with_value (EVCardAttribute *attr,
1573 EVCardAttributeParam *param, const char *value)
1575 g_return_if_fail (attr != NULL);
1576 g_return_if_fail (param != NULL);
1578 e_vcard_attribute_param_add_value (param, value);
1580 e_vcard_attribute_add_param (attr, param);
1584 * e_vcard_attribute_add_param_with_values:
1585 * @attr: an #EVCardAttribute
1586 * @param: an #EVCardAttributeParam
1587 * @Varargs: a %NULL-terminated list of strings
1589 * Adds the list of values to @param, then adds @param
1593 e_vcard_attribute_add_param_with_values (EVCardAttribute *attr,
1594 EVCardAttributeParam *param, ...)
1599 g_return_if_fail (attr != NULL);
1600 g_return_if_fail (param != NULL);
1602 va_start (ap, param);
1604 while ((v = va_arg (ap, char*))) {
1605 e_vcard_attribute_param_add_value (param, v);
1610 e_vcard_attribute_add_param (attr, param);
1614 * e_vcard_attribute_param_remove_values:
1615 * @param: an #EVCardAttributeParam
1617 * Removes and frees all values from @param.
1620 e_vcard_attribute_param_remove_values (EVCardAttributeParam *param)
1622 g_return_if_fail (param != NULL);
1624 g_list_foreach (param->values, (GFunc)g_free, NULL);
1625 g_list_free (param->values);
1626 param->values = NULL;
1630 * e_vcard_attribute_remove_param_value:
1631 * @attr: an #EVCardAttribute
1632 * @param_name: a parameter name
1635 * Removes the value @s from the parameter @param_name on the attribute @attr.
1638 e_vcard_attribute_remove_param_value (EVCardAttribute *attr, const char *param_name, const char *s)
1641 EVCardAttributeParam *param;
1643 g_return_if_fail (attr != NULL);
1644 g_return_if_fail (param_name != NULL);
1645 g_return_if_fail (s != NULL);
1647 params = e_vcard_attribute_get_params (attr);
1649 for (l = params; l; l = l->next) {
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);
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);
1669 * e_vcard_get_attributes:
1670 * @evcard: an #EVCard
1672 * Gets the list of attributes from @evcard. The list and its
1673 * contents are owned by @evcard, and must not be freed.
1675 * Return value: A list of attributes of type #EVCardAttribute.
1678 e_vcard_get_attributes (EVCard *evcard)
1680 g_return_val_if_fail (E_IS_VCARD (evcard), NULL);
1682 return evcard->priv->attributes;
1686 * e_vcard_get_attribute:
1688 * @name: the name of the attribute to get
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
1694 * Return value: An #EVCardAttribute if found, or #NULL.
1697 e_vcard_get_attribute (EVCard *evc,
1702 g_return_val_if_fail (E_IS_VCARD (evc), NULL);
1703 g_return_val_if_fail (name != NULL, NULL);
1705 attrs = e_vcard_get_attributes (evc);
1706 for (l = attrs; l; l = l->next) {
1707 EVCardAttribute *attr;
1709 attr = (EVCardAttribute *) l->data;
1710 if (strcmp (attr->name, name) == 0)
1717 * e_vcard_attribute_get_group:
1718 * @attr: an #EVCardAttribute
1720 * Gets the group name of @attr.
1722 * Return value: The attribute's group name.
1725 e_vcard_attribute_get_group (EVCardAttribute *attr)
1727 g_return_val_if_fail (attr != NULL, NULL);
1733 * e_vcard_attribute_get_name:
1734 * @attr: an #EVCardAttribute
1736 * Gets the name of @attr.
1738 * Return value: The attribute's name.
1741 e_vcard_attribute_get_name (EVCardAttribute *attr)
1743 g_return_val_if_fail (attr != NULL, NULL);
1749 * e_vcard_attribute_get_values:
1750 * @attr: an #EVCardAttribute
1752 * Gets the list of values from @attr. The list and its
1753 * contents are owned by @attr, and must not be freed.
1755 * Return value: A list of string values.
1758 e_vcard_attribute_get_values (EVCardAttribute *attr)
1760 g_return_val_if_fail (attr != NULL, NULL);
1762 return attr->values;
1766 * e_vcard_attribute_get_values_decoded:
1767 * @attr: an #EVCardAttribute
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.
1773 * Return value: A list of values of type #GString.
1776 e_vcard_attribute_get_values_decoded (EVCardAttribute *attr)
1778 g_return_val_if_fail (attr != NULL, NULL);
1780 if (!attr->decoded_values) {
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);
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));
1795 attr->decoded_values = g_list_reverse (attr->decoded_values);
1797 case EVC_ENCODING_QP:
1798 g_warning ("need to implement quoted printable decoding");
1803 return attr->decoded_values;
1807 * e_vcard_attribute_is_single_valued:
1808 * @attr: an #EVCardAttribute
1810 * Checks if @attr has a single value.
1812 * Return value: %TRUE if the attribute has exactly one value, %FALSE otherwise.
1815 e_vcard_attribute_is_single_valued (EVCardAttribute *attr)
1817 g_return_val_if_fail (attr != NULL, FALSE);
1819 if (attr->values == NULL
1820 || attr->values->next != NULL)
1827 * e_vcard_attribute_get_value:
1828 * @attr: an #EVCardAttribute
1830 * Gets the value of a single-valued #EVCardAttribute, @attr.
1832 * Return value: A newly allocated string representing the value.
1835 e_vcard_attribute_get_value (EVCardAttribute *attr)
1839 g_return_val_if_fail (attr != NULL, NULL);
1841 values = e_vcard_attribute_get_values (attr);
1843 if (!e_vcard_attribute_is_single_valued (attr))
1844 g_warning ("e_vcard_attribute_get_value called on multivalued attribute");
1846 return values ? g_strdup ((char*)values->data) : NULL;
1850 * e_vcard_attribute_get_value_decoded:
1851 * @attr: an #EVCardAttribute
1853 * Gets the value of a single-valued #EVCardAttribute, @attr, decoding
1856 * Note: this function seems currently to be unused. Could be removed.
1858 * Return value: A newly allocated #GString representing the value.
1861 e_vcard_attribute_get_value_decoded (EVCardAttribute *attr)
1864 GString *str = NULL;
1866 g_return_val_if_fail (attr != NULL, NULL);
1868 values = e_vcard_attribute_get_values_decoded (attr);
1870 if (!e_vcard_attribute_is_single_valued (attr))
1871 g_warning ("e_vcard_attribute_get_value_decoded called on multivalued attribute");
1876 return str ? g_string_new_len (str->str, str->len) : NULL;
1880 * e_vcard_attribute_has_type:
1881 * @attr: an #EVCardAttribute
1882 * @typestr: a string representing the type
1884 * Checks if @attr has an #EVCardAttributeParam of the specified type.
1886 * Return value: %TRUE if such a parameter exists, %FALSE otherwise.
1889 e_vcard_attribute_has_type (EVCardAttribute *attr, const char *typestr)
1894 g_return_val_if_fail (attr != NULL, FALSE);
1895 g_return_val_if_fail (typestr != NULL, FALSE);
1897 params = e_vcard_attribute_get_params (attr);
1899 for (p = params; p; p = p->next) {
1900 EVCardAttributeParam *param = p->data;
1902 if (!g_ascii_strcasecmp (e_vcard_attribute_param_get_name (param), EVC_TYPE)) {
1903 GList *values = e_vcard_attribute_param_get_values (param);
1906 for (v = values; v; v = v->next) {
1907 if (!g_ascii_strcasecmp ((char*)v->data, typestr))
1917 * e_vcard_attribute_get_params:
1918 * @attr: an #EVCardAttribute
1920 * Gets the list of parameters from @attr. The list and its
1921 * contents are owned by @attr, and must not be freed.
1923 * Return value: A list of elements of type #EVCardAttributeParam.
1926 e_vcard_attribute_get_params (EVCardAttribute *attr)
1928 g_return_val_if_fail (attr != NULL, NULL);
1930 return attr->params;
1934 * e_vcard_attribute_get_param:
1935 * @attr: an #EVCardAttribute
1936 * @name: a parameter name
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.
1941 * Return value: A list of string elements representing the parameter's values.
1944 e_vcard_attribute_get_param (EVCardAttribute *attr, const char *name)
1948 g_return_val_if_fail (attr != NULL, NULL);
1949 g_return_val_if_fail (name != NULL, NULL);
1951 params = e_vcard_attribute_get_params (attr);
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);
1964 * e_vcard_attribute_param_get_name:
1965 * @param: an #EVCardAttributeParam
1967 * Gets the name of @param.
1969 * Return value: The name of the parameter.
1972 e_vcard_attribute_param_get_name (EVCardAttributeParam *param)
1974 g_return_val_if_fail (param != NULL, NULL);
1980 * e_vcard_attribute_param_get_values:
1981 * @param: an #EVCardAttributeParam
1983 * Gets the list of values from @param. The list and its
1984 * contents are owned by @param, and must not be freed.
1986 * Return value: A list of string elements representing the parameter's values.
1989 e_vcard_attribute_param_get_values (EVCardAttributeParam *param)
1991 g_return_val_if_fail (param != NULL, NULL);
1993 return param->values;
1998 /* encoding/decoding stuff ripped from camel-mime-utils.c */
2000 static char *_evc_base64_alphabet =
2001 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2003 static unsigned char _evc_base64_rank[256];
2006 _evc_base64_init(void)
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;
2014 _evc_base64_rank['='] = 0;
2017 /* call this when finished encoding everything, to
2018 flush off the last little bit */
2020 _evc_base64_encode_close(unsigned char *in, size_t inlen, gboolean break_lines, unsigned char *out, int *state, int *save)
2023 unsigned char *outptr = out;
2026 outptr += _evc_base64_encode_step(in, inlen, break_lines, outptr, state, save);
2028 c1 = ((unsigned char *)save)[1];
2029 c2 = ((unsigned char *)save)[2];
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]));
2036 switch (((char *)save)[0]) {
2038 outptr[2] = _evc_base64_alphabet[ ( (c2 &0x0f) << 2 ) ];
2039 g_assert(outptr[2] != 0);
2044 outptr[0] = _evc_base64_alphabet[ c1 >> 2 ];
2045 outptr[1] = _evc_base64_alphabet[ c2 >> 4 | ( (c1&0x3) << 4 )];
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).
2065 _evc_base64_encode_step(unsigned char *in, size_t len, gboolean break_lines, unsigned char *out, int *state, int *save)
2067 register unsigned char *inptr, *outptr;
2075 d(printf("we have %d chars, and %d saved chars\n", len, ((char *)save)[0]));
2077 if (len + ((char *)save)[0] > 2) {
2078 unsigned char *inend = in+len-2;
2079 register int c1, c2, c3;
2080 register int already;
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;
2090 /* yes, we jump into the loop, no i'm not going to change it, it's beautiful! */
2091 while (inptr < inend) {
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) {
2108 ((char *)save)[0] = 0;
2109 len = 2-(inptr-inend);
2113 d(printf("state = %d, len = %d\n",
2114 (int)((char *)save)[0],
2118 register char *saveout;
2120 /* points to the slot for the next char to save */
2121 saveout = & (((char *)save)[1]) + ((char *)save)[0];
2123 /* len can only be 0 1 or 2 */
2125 case 2: *saveout++ = *inptr++;
2126 case 1: *saveout++ = *inptr++;
2128 ((char *)save)[0]+=len;
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]));
2141 * base64_decode_step: decode a chunk of base64 encoded data
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
2148 * Decodes a chunk of base64 encoded data
2151 _evc_base64_decode_step(unsigned char *in, size_t len, unsigned char *out, int *state, unsigned int *save)
2153 register unsigned char *inptr, *outptr;
2154 unsigned char *inend, c;
2155 register unsigned int v;
2161 /* convert 4 base64 bytes to 3 normal bytes */
2165 while (inptr<inend) {
2166 c = _evc_base64_rank[*inptr++];
2182 /* quick scan back for '=' on the end somewhere */
2183 /* fortunately we can drop 1 output char for each trailing = (upto 2) */
2185 while (inptr>in && i) {
2187 if (_evc_base64_rank[*inptr] != 0xff) {
2188 if (*inptr == '=' && outptr>out)
2194 /* if i!= 0 then there is a truncation error! */
2199 _evc_base64_encode_simple (const char *data, size_t len)
2202 int state = 0, outlen;
2205 g_return_val_if_fail (data != NULL, NULL);
2207 out = g_malloc (len * 4 / 3 + 5);
2208 outlen = _evc_base64_encode_close ((unsigned char *)data, len, FALSE,
2209 out, &state, &save);
2215 _evc_base64_decode_simple (char *data, size_t len)
2218 unsigned int save = 0;
2220 g_return_val_if_fail (data != NULL, 0);
2222 return _evc_base64_decode_step ((unsigned char *)data, len,
2223 (unsigned char *)data, &state, &save);