From 06ea0b6cb33dff027bb23dde7d0ae19b1ff05720 Mon Sep 17 00:00:00 2001 From: Chris Toshok Date: Mon, 31 Mar 2003 05:18:28 +0000 Subject: braindead, and *extremely* forgiving vcard parser. not for public 2003-03-30 Chris Toshok * backend/ebook/e-vcard.[ch]: braindead, and *extremely* forgiving vcard parser. not for public consumption yet. svn path=/trunk/; revision=20589 --- addressbook/backend/ebook/e-vcard.c | 925 ++++++++++++++++++++++++++++++++++++ addressbook/backend/ebook/e-vcard.h | 108 +++++ 2 files changed, 1033 insertions(+) create mode 100644 addressbook/backend/ebook/e-vcard.c create mode 100644 addressbook/backend/ebook/e-vcard.h (limited to 'addressbook/backend') diff --git a/addressbook/backend/ebook/e-vcard.c b/addressbook/backend/ebook/e-vcard.c new file mode 100644 index 0000000000..62ebda9349 --- /dev/null +++ b/addressbook/backend/ebook/e-vcard.c @@ -0,0 +1,925 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* evcard.h + * + * Copyright (C) 2003 Ximian, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Chris Toshok (toshok@ximian.com) + */ + +#include +#include +#include +#include "e-vcard.h" + +#define CRLF "\r\n" + +struct _EVCardPrivate { + GList *attributes; +}; + +struct _EVCardAttribute { + char *group; + char *name; + GList *params; /* EVCardParam */ + GList *values; +}; + +struct _EVCardAttributeParam { + char *name; + GList *values; /* GList of char*'s*/ +}; + +static GObjectClass *parent_class; + +static void +e_vcard_dispose (GObject *object) +{ + EVCard *evc = E_VCARD (object); + + if (!evc->priv) + return; + + g_list_foreach (evc->priv->attributes, (GFunc)e_vcard_attribute_free, NULL); + g_list_free (evc->priv->attributes); + + g_free (evc->priv); + evc->priv = NULL; + + if (G_OBJECT_CLASS (parent_class)->dispose) + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +e_vcard_class_init (EVCardClass *klass) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS(klass); + + parent_class = g_type_class_ref (G_TYPE_OBJECT); + + object_class->dispose = e_vcard_dispose; +} + +static void +e_vcard_init (EVCard *evc) +{ + evc->priv = g_new0 (EVCardPrivate, 1); +} + +GType +e_vcard_get_type (void) +{ + static GType vcard_type = 0; + + if (!vcard_type) { + static const GTypeInfo vcard_info = { + sizeof (EVCardClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) e_vcard_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EVCard), + 0, /* n_preallocs */ + (GInstanceInitFunc) e_vcard_init, + }; + + vcard_type = g_type_register_static (G_TYPE_OBJECT, "EVCard", &vcard_info, 0); + } + + return vcard_type; +} + + + +static char* +fold_lines (char *buf) +{ + GString *str = g_string_new (""); + char *p = buf; + char *next, *next2; + + /* we're pretty liberal with line folding here. We handle + lines folded with \r\n... and \n\r... and + \n... We also turn single \r's and \n's not followed by + WS into \r\n's. */ + while (*p) { + if (*p == '\r' || *p == '\n') { + next = g_utf8_next_char (p); + if (*next == '\n' || *next == '\r') { + next2 = g_utf8_next_char (next); + if (*next2 == ' ' || *next2 == '\t') { + p = g_utf8_next_char (next2); + } + else { + str = g_string_append (str, CRLF); + p = g_utf8_next_char (next); + } + } + else if (*next == ' ' || *next == '\t') { + p = g_utf8_next_char (next); + } + else { + str = g_string_append (str, CRLF); + p = g_utf8_next_char (p); + } + } + else { + str = g_string_append_unichar (str, g_utf8_get_char (p)); + p = g_utf8_next_char (p); + } + } + + g_free (buf); + + return g_string_free (str, FALSE); +} + +/* skip forward until we hit the CRLF, or \0 */ +static void +skip_to_next_line (char **p) +{ + char *lp; + lp = *p; + + while (*lp != '\r' && *lp != '\0') + lp = g_utf8_next_char (lp); + + if (*lp == '\r') { + lp = g_utf8_next_char (lp); /* \n */ + lp = g_utf8_next_char (lp); /* start of the next line */ + } + + *p = lp; +} + +/* skip forward until we hit a character in @s, CRLF, or \0 */ +static void +skip_until (char **p, char *s) +{ + /* XXX write me plz k thx */ + g_assert_not_reached(); +} + +static void +read_attribute_value (EVCardAttribute *attr, char **p, gboolean quoted_printable) +{ + char *lp = *p; + GString *str; + + /* read in the value */ + str = g_string_new (""); + while (*lp != '\r' && *lp != '\0') { + if (*lp == '=' && quoted_printable) { + char a, b; + if ((a = *(++lp)) == '\0') break; + if ((b = *(++lp)) == '\0') break; + if (a == '\r' && b == '\n') { + /* it was a = at the end of the line, + * just ignore this and continue + * parsing on the next line. yay for + * 2 kinds of line folding + */ + } + else if (isalnum(a) && isalnum (b)) { + char c; + + a = tolower (a); + b = tolower (b); + + c = (((a>='a'?a-'a'+10:a-'0')&0x0f) << 4) + | ((b>='a'?b-'a'+10:b-'0')&0x0f); + + str = g_string_append_c (str, c); + } + /* silently consume malformed input, and + continue parsing */ + lp++; + } + else if (*lp == '\\') { + /* convert back to the non-escaped version of + the characters */ + lp = g_utf8_next_char(lp); + if (*lp == '\0') { + str = g_string_append_c (str, '\\'); + break; + } + switch (*lp) { + case 'n': str = g_string_append_c (str, '\n'); break; + case 'r': str = g_string_append_c (str, '\r'); break; + case ';': str = g_string_append_c (str, ';'); break; + case ',': str = g_string_append_c (str, ','); break; + case '\\': str = g_string_append_c (str, '\\'); break; + default: + g_warning ("invalid escape, passing it through"); + str = g_string_append_c (str, '\\'); + str = g_string_append_unichar (str, g_utf8_get_char(lp)); + lp = g_utf8_next_char(lp); + break; + } + } + else if (*lp == ';') { + e_vcard_attribute_add_value (attr, g_string_free (str, FALSE)); + str = g_string_new (""); + lp = g_utf8_next_char(lp); + } + else { + str = g_string_append_unichar (str, g_utf8_get_char (lp)); + lp = g_utf8_next_char(lp); + } + } + if (str) + e_vcard_attribute_add_value (attr, g_string_free (str, FALSE)); + + if (*lp == '\r') { + lp = g_utf8_next_char (lp); /* \n */ + lp = g_utf8_next_char (lp); /* start of the next line */ + } + + *p = lp; +} + +static void +read_attribute_params (EVCardAttribute *attr, char **p, gboolean *quoted_printable) +{ + char *lp = *p; + GString *str; + EVCardAttributeParam *param = NULL; + + str = g_string_new (""); + while (*lp != '\0') { + /* accumulate until we hit the '=' or ';'. If we hit + * a '=' the string contains the parameter name. if + * we hit a ';' the string contains the parameter + * value and the name is either ENCODING (if value == + * QUOTED-PRINTABLE) or TYPE (in any other case.) + */ + if (*lp == '=') { + if (str->len > 0) { + param = e_vcard_attribute_param_new (str->str); + str = g_string_assign (str, ""); + lp = g_utf8_next_char (lp); + } + else { + skip_until (&lp, ":;"); + if (*lp == '\r') { + lp = g_utf8_next_char (lp); /* \n */ + lp = g_utf8_next_char (lp); /* start of the next line */ + break; + } + else if (*lp == ';') + lp = g_utf8_next_char (lp); + } + } + else if (*lp == ';' || *lp == ':' || *lp == ',') { + gboolean colon = (*lp == ':'); + gboolean comma = (*lp == ','); + + if (param) { + if (str->len > 0) { + e_vcard_attribute_param_add_value (param, str->str); + str = g_string_assign (str, ""); + if (!colon) + lp = g_utf8_next_char (lp); + } + else { + /* we've got a parameter of the form: + * PARAM=(.*,)?[:;] + * so what we do depends on if there are already values + * for the parameter. If there are, we just finish + * this parameter and skip past the offending character + * (unless it's the ':'). If there aren't values, we free + * the parameter then skip past the character. + */ + if (!param->values) { + e_vcard_attribute_param_free (param); + param = NULL; + } + } + + if (param + && !g_ascii_strcasecmp (param->name, "encoding") + && !g_ascii_strcasecmp (param->values->data, "quoted-printable")) { + *quoted_printable = TRUE; + e_vcard_attribute_param_free (param); + param = NULL; + } + } + else { + if (str->len > 0) { + char *param_name; + if (!g_ascii_strcasecmp (str->str, + "quoted-printable")) { + param_name = NULL; + *quoted_printable = TRUE; + } + else { + param_name = "TYPE"; + } + + if (param_name) { + param = e_vcard_attribute_param_new (param_name); + e_vcard_attribute_param_add_value (param, str->str); + } + str = g_string_assign (str, ""); + if (!colon) + lp = g_utf8_next_char (lp); + } + else { + /* XXX more here */ + g_assert_not_reached (); + } + } + if (param && !comma) { + e_vcard_attribute_add_param (attr, param); + param = NULL; + } + if (colon) + break; + } + else if (g_unichar_isalnum (g_utf8_get_char (lp)) || *lp == '-' || *lp == '_') { + str = g_string_append_unichar (str, g_utf8_get_char (lp)); + lp = g_utf8_next_char (lp); + } + else { + g_warning ("invalid character found in parameter spec"); + str = g_string_assign (str, ""); + skip_until (&lp, ":;"); + } + } + + if (str) + g_string_free (str, TRUE); + + *p = lp; +} + +/* reads an entire attribute from the input buffer, leaving p pointing + at the start of the next line (past the \r\n) */ +static EVCardAttribute* +read_attribute (char **p) +{ + char *attr_group = NULL; + char *attr_name = NULL; + EVCardAttribute *attr = NULL; + GString *str; + char *lp = *p; + gboolean is_qp = FALSE; + + /* first read in the group/name */ + str = g_string_new (""); + while (*lp != '\r' && *lp != '\0') { + if (*lp == ':' || *lp == ';') { + if (str->len != 0) { + /* we've got a name, break out to the value/attribute parsing */ + attr_name = g_string_free (str, FALSE); + break; + } + else { + /* a line of the form: + * (group.)?[:;] + * + * since we don't have an attribute + * name, skip to the end of the line + * and try again. + */ + g_string_free (str, TRUE); + *p = lp; + skip_to_next_line(p); + goto lose; + } + } + else if (*lp == '.') { + if (attr_group) { + g_warning ("extra `.' in attribute specification. ignoring extra group `%s'", + str->str); + g_string_free (str, TRUE); + str = g_string_new (""); + } + if (str->len != 0) { + attr_group = g_string_free (str, FALSE); + str = g_string_new (""); + } + } + else if (g_unichar_isalnum (g_utf8_get_char (lp)) || *lp == '-' || *lp == '_') { + str = g_string_append_unichar (str, g_utf8_get_char (lp)); + } + else { + g_warning ("invalid character found in attribute group/name"); + g_string_free (str, TRUE); + *p = lp; + skip_to_next_line(p); + goto lose; + } + + lp = g_utf8_next_char(lp); + } + + if (!attr_name) { + skip_to_next_line (p); + goto lose; + } + + attr = e_vcard_attribute_new (attr_group, attr_name); + g_free (attr_group); + g_free (attr_name); + + if (*lp == ';') { + /* skip past the ';' */ + lp = g_utf8_next_char(lp); + read_attribute_params (attr, &lp, &is_qp); + } + if (*lp == ':') { + /* skip past the ':' */ + lp = g_utf8_next_char(lp); + read_attribute_value (attr, &lp, is_qp); + } + + *p = lp; + + if (!attr->values) + goto lose; + + return attr; + lose: + if (attr) + e_vcard_attribute_free (attr); + return NULL; +} + +/* we try to be as forgiving as we possibly can here - this isn't a + * validator. Almost nothing is considered a fatal error. We always + * try to return *something*. + */ +static void +parse (EVCard *evc, const char *str) +{ + char *buf = g_strdup (str); + char *p, *end; + EVCardAttribute *attr; + + /* first validate the string is valid utf8 */ + if (!g_utf8_validate (buf, -1, (const char **)&end)) { + /* if the string isn't valid, we parse as much as we can from it */ + g_warning ("invalid utf8 passed to EVCard. Limping along."); + *end = '\0'; + } + + printf ("BEFORE FOLDING:\n"); + printf (str); + + buf = fold_lines (buf); + + printf ("\n\nAFTER FOLDING:\n"); + printf (buf); + + p = buf; + + attr = read_attribute (&p); + if (!attr || attr->group || g_ascii_strcasecmp (attr->name, "begin")) { + g_warning ("vcard began without a BEGIN:VCARD\n"); + } + + while (*p) { + EVCardAttribute *next_attr = read_attribute (&p); + + if (next_attr) { + if (g_ascii_strcasecmp (next_attr->name, "end")) + e_vcard_add_attribute (evc, next_attr); + attr = next_attr; + } + } + + if (!attr || attr->group || g_ascii_strcasecmp (attr->name, "end")) { + g_warning ("vcard ended without END:VCARD\n"); + } +} + +static char* +escape_string (const char *s) +{ + GString *str = g_string_new (""); + const char *p; + + /* Escape a string as described in RFC2426, section 5 */ + for (p = s; *p; p++) { + switch (*p) { + case '\n': + str = g_string_append (str, "\\n"); + break; + case '\r': + if (*(p+1) == '\n') + p++; + str = g_string_append (str, "\\n"); + break; + case ';': + str = g_string_append (str, "\\;"); + break; + case ',': + str = g_string_append (str, "\\,"); + break; + case '\\': + str = g_string_append (str, "\\\\"); + break; + default: + str = g_string_append_c (str, *p); + break; + } + } + + return g_string_free (str, FALSE); +} + +#if notyet +static char* +unescape_string (const char *s) +{ + GString *str = g_string_new (""); + const char *p; + + /* Unescape a string as described in RFC2426, section 5 */ + for (p = s; *p; p++) { + if (*p == '\\') { + p++; + if (*p == '\0') { + str = g_string_append_c (str, '\\'); + break; + } + switch (*p) { + case 'n': str = g_string_append_c (str, '\n'); break; + case 'r': str = g_string_append_c (str, '\r'); break; + case ';': str = g_string_append_c (str, ';'); break; + case ',': str = g_string_append_c (str, ','); break; + case '\\': str = g_string_append_c (str, '\\'); break; + default: + g_warning ("invalid escape, passing it through"); + str = g_string_append_c (str, '\\'); + str = g_string_append_unichar (str, g_utf8_get_char(p)); + break; + } + } + } + + return g_string_free (str, FALSE); +} +#endif + +EVCard * +e_vcard_new () +{ + return g_object_new (E_TYPE_VCARD, NULL); +} + +EVCard * +e_vcard_new_from_string (const char *str) +{ + EVCard *evc = e_vcard_new (); + + parse (evc, str); + + return evc; +} + +char* +e_vcard_to_string (EVCard *evc) +{ + GList *l; + GList *v; + + GString *str = g_string_new (""); + + str = g_string_append (str, "BEGIN:vCard" CRLF); + + for (l = evc->priv->attributes; l; l = l->next) { + GList *p; + EVCardAttribute *attr = l->data; + GString *attr_str = g_string_new (""); + int l; + + /* From rfc2425, 5.8.2 + * + * contentline = [group "."] name *(";" param) ":" value CRLF + */ + + if (attr->group) { + attr_str = g_string_append (attr_str, attr->group); + attr_str = g_string_append_c (attr_str, '.'); + } + attr_str = g_string_append (attr_str, attr->name); + + /* handle the parameters */ + for (p = attr->params; p; p = p->next) { + EVCardAttributeParam *param = p->data; + /* 5.8.2: + * param = param-name "=" param-value *("," param-value) + */ + attr_str = g_string_append_c (attr_str, ';'); + attr_str = g_string_append (attr_str, param->name); + if (param->values) { + attr_str = g_string_append_c (attr_str, '='); + for (v = param->values; v; v = v->next) { + char *value = v->data; + attr_str = g_string_append (attr_str, value); + if (v->next) + attr_str = g_string_append_c (attr_str, ','); + } + } + } + + attr_str = g_string_append_c (attr_str, ':'); + + for (v = attr->values; v; v = v->next) { + char *value = v->data; + char *escaped_value = NULL; + + escaped_value = escape_string (value); + + attr_str = g_string_append (attr_str, escaped_value); + if (v->next) + attr_str = g_string_append_c (attr_str, ';'); + + g_free (escaped_value); + } + + /* 5.8.2: + * When generating a content line, lines longer than 75 + * characters SHOULD be folded + */ + l = 0; + do { + if (attr_str->len - l > 75) { + l += 75; + attr_str = g_string_insert_len (attr_str, l, CRLF " ", sizeof (CRLF " ") - 1); + } + else + break; + } while (l < attr_str->len); + + attr_str = g_string_append (attr_str, CRLF); + + str = g_string_append (str, g_string_free (attr_str, FALSE)); + } + + str = g_string_append (str, "END:vCard"); + + return g_string_free (str, FALSE); +} + +void +e_vcard_dump_structure (EVCard *evc) +{ + GList *a; + GList *v; + int i; + + printf ("vCard\n"); + for (a = evc->priv->attributes; a; a = a->next) { + GList *p; + EVCardAttribute *attr = a->data; + printf ("+-- %s\n", attr->name); + if (attr->params) { + printf (" +- params=\n"); + + for (p = attr->params, i = 0; p; p = p->next, i++) { + EVCardAttributeParam *param = p->data; + printf (" | [%d] = %s", i,param->name); + printf ("("); + for (v = param->values; v; v = v->next) { + char *value = escape_string ((char*)v->data); + printf ("%s", value); + if (v->next) + printf (","); + g_free (value); + } + + printf (")\n"); + } + } + printf (" +- values=\n"); + for (v = attr->values, i = 0; v; v = v->next, i++) { + printf (" [%d] = `%s'\n", i, (char*)v->data); + } + } +} + + +EVCardAttribute* +e_vcard_attribute_new (const char *attr_group, const char *attr_name) +{ + EVCardAttribute *attr = g_new0 (EVCardAttribute, 1); + + attr->group = g_strdup (attr_group); + attr->name = g_strdup (attr_name); + + return attr; +} + +void +e_vcard_attribute_free (EVCardAttribute *attr) +{ + GList *p; + + g_free (attr->group); + g_free (attr->name); + + g_list_foreach (attr->values, (GFunc)g_free, NULL); + g_list_free (attr->values); + + for (p = attr->params; p; p = p->next) { + EVCardAttributeParam *param = p->data; + + g_free (param->name); + g_list_foreach (param->values, (GFunc)g_free, NULL); + g_list_free (param->values); + g_free (param); + } + + g_free (attr); +} + +void +e_vcard_add_attribute (EVCard *evc, EVCardAttribute *attr) +{ + evc->priv->attributes = g_list_append (evc->priv->attributes, attr); +} + +void +e_vcard_add_attribute_with_value (EVCard *evcard, + EVCardAttribute *attr, const char *value) +{ + e_vcard_attribute_add_value (attr, value); + + e_vcard_add_attribute (evcard, attr); +} + +void +e_vcard_add_attribute_with_values (EVCard *evcard, EVCardAttribute *attr, ...) +{ + va_list ap; + char *v; + + va_start (ap, attr); + + while ((v = va_arg (ap, char*))) { + e_vcard_attribute_add_value (attr, v); + } + + va_end (ap); + + e_vcard_add_attribute (evcard, attr); +} + +void +e_vcard_attribute_add_value (EVCardAttribute *attr, const char *value) +{ + attr->values = g_list_append (attr->values, g_strdup (value)); +} + +void +e_vcard_attribute_add_values (EVCardAttribute *attr, + ...) +{ + va_list ap; + char *v; + + va_start (ap, attr); + + while ((v = va_arg (ap, char*))) { + e_vcard_attribute_add_value (attr, v); + } + + va_end (ap); +} + + +EVCardAttributeParam* +e_vcard_attribute_param_new (const char *name) +{ + EVCardAttributeParam *param = g_new0 (EVCardAttributeParam, 1); + param->name = g_strdup (name); + + return param; +} + +void +e_vcard_attribute_param_free (EVCardAttributeParam *param) +{ + g_free (param->name); + g_list_foreach (param->values, (GFunc)g_free, NULL); + g_list_free (param->values); + g_free (param); +} + +void +e_vcard_attribute_add_param (EVCardAttribute *attr, + EVCardAttributeParam *param) +{ + attr->params = g_list_append (attr->params, param); +} + +void +e_vcard_attribute_param_add_value (EVCardAttributeParam *param, + const char *value) +{ + param->values = g_list_append (param->values, g_strdup (value)); +} + +void +e_vcard_attribute_param_add_values (EVCardAttributeParam *param, + ...) +{ + va_list ap; + char *v; + + va_start (ap, param); + + while ((v = va_arg (ap, char*))) { + e_vcard_attribute_param_add_value (param, v); + } + + va_end (ap); +} + +void +e_vcard_attribute_add_param_with_value (EVCardAttribute *attr, + EVCardAttributeParam *param, const char *value) +{ + e_vcard_attribute_param_add_value (param, value); + + e_vcard_attribute_add_param (attr, param); +} + +void +e_vcard_attribute_add_param_with_values (EVCardAttribute *attr, + EVCardAttributeParam *param, ...) +{ + va_list ap; + char *v; + + va_start (ap, param); + + while ((v = va_arg (ap, char*))) { + e_vcard_attribute_param_add_value (param, v); + } + + va_end (ap); + + e_vcard_attribute_add_param (attr, param); +} + +GList* +e_vcard_get_attributes (EVCard *evcard) +{ + return evcard->priv->attributes; +} + +const char* +e_vcard_attribute_get_group (EVCardAttribute *attr) +{ + return attr->group; +} + +const char* +e_vcard_attribute_get_name (EVCardAttribute *attr) +{ + return attr->name; +} + +GList* +e_vcard_attribute_get_values (EVCardAttribute *attr) +{ + return attr->values; +} + +GList* +e_vcard_attribute_get_params (EVCardAttribute *attr) +{ + return attr->params; +} + +const char* +e_vcard_attribute_param_get_name (EVCardAttributeParam *param) +{ + return param->name; +} + +GList* +e_vcard_attribute_param_get_values (EVCardAttributeParam *param) +{ + return param->values; +} diff --git a/addressbook/backend/ebook/e-vcard.h b/addressbook/backend/ebook/e-vcard.h new file mode 100644 index 0000000000..69e0a3e10b --- /dev/null +++ b/addressbook/backend/ebook/e-vcard.h @@ -0,0 +1,108 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* e-vcard.h + * + * Copyright (C) 2003 Ximian, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Chris Toshok (toshok@ximian.com) + */ + +#ifndef _EVCARD_H +#define _EVCARD_H + +#include +#include + +#define EVC_FN "FN" +#define EVC_ORG "ORG" +#define EVC_URL "URL" +#define EVC_VERSION "VERSION" +#define EVC_REV "REV" +#define EVC_PRODID "PRODID" +#define EVC_TYPE "TYPE" +#define EVC_ADR "ADR" +#define EVC_TEL "TEL" + +#define EVC_ENCODING "ENCODING" +#define EVC_QUOTEDPRINTABLE "QUOTED-PRINTABLE" + +#define E_TYPE_VCARD (e_vcard_get_type ()) +#define E_VCARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_VCARD, EVCard)) +#define E_VCARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_VCARD, EVCardClass)) +#define E_IS_VCARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_VCARD)) +#define E_IS_VCARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_VCARD)) +#define E_VCARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_VCARD, EVCardClass)) + +typedef struct _EVCard EVCard; +typedef struct _EVCardClass EVCardClass; +typedef struct _EVCardPrivate EVCardPrivate; +typedef struct _EVCardAttribute EVCardAttribute; +typedef struct _EVCardAttributeParam EVCardAttributeParam; + +struct _EVCard { + GObject parent; + + EVCardPrivate *priv; +}; + +struct _EVCardClass { + GObjectClass parent_class; +}; + +GType e_vcard_get_type (void); +EVCard* e_vcard_new (void); +EVCard* e_vcard_new_from_string (const char *str); +char* e_vcard_to_string (EVCard *evcard); +/* mostly for debugging */ +void e_vcard_dump_structure (EVCard *evc); + + +/* attributes */ +EVCardAttribute *e_vcard_attribute_new (const char *attr_group, const char *attr_name); +void e_vcard_attribute_free (EVCardAttribute *attr); +void e_vcard_add_attribute (EVCard *evcard, EVCardAttribute *attr); +void e_vcard_add_attribute_with_value (EVCard *evcard, EVCardAttribute *attr, const char *value); +void e_vcard_add_attribute_with_values (EVCard *evcard, EVCardAttribute *attr, ...); +void e_vcard_attribute_add_value (EVCardAttribute *attr, const char *value); +void e_vcard_attribute_add_values (EVCardAttribute *attr, ...); + +/* attribute parameters */ +EVCardAttributeParam* e_vcard_attribute_param_new (const char *param_name); +void e_vcard_attribute_param_free (EVCardAttributeParam *param); +void e_vcard_attribute_add_param (EVCardAttribute *attr, EVCardAttributeParam *param); +void e_vcard_attribute_add_param_with_value (EVCardAttribute *attr, + EVCardAttributeParam *param, const char *value); +void e_vcard_attribute_add_param_with_values (EVCardAttribute *attr, + EVCardAttributeParam *param, ...); + +void e_vcard_attribute_param_add_value (EVCardAttributeParam *param, + const char *value); +void e_vcard_attribute_param_add_values (EVCardAttributeParam *param, + ...); + +/* EVCard* accessors. nothing returned from these functions should be + freed by the caller. */ +GList* e_vcard_get_attributes (EVCard *evcard); +const char* e_vcard_attribute_get_group (EVCardAttribute *attr); +const char* e_vcard_attribute_get_name (EVCardAttribute *attr); +GList* e_vcard_attribute_get_values (EVCardAttribute *attr); + +GList* e_vcard_attribute_get_params (EVCardAttribute *attr); +const char* e_vcard_attribute_param_get_name (EVCardAttributeParam *param); +GList* e_vcard_attribute_param_get_values (EVCardAttributeParam *param); + + +#endif /* _EVCARD_H */ -- cgit v1.2.3