According to specification of vcard 2.1, semicolon is only character
which is escaped with a backslash character (in vcard's property field
content). This patch provides "escape_semicolon" function which handles
this issue.
---
plugins/vcard.c | 14 ++++++++++++++
1 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/plugins/vcard.c b/plugins/vcard.c
index b997fc4..4f61368 100644
--- a/plugins/vcard.c
+++ b/plugins/vcard.c
@@ -149,6 +149,20 @@ static void get_escaped_fields(char **fields, ...)
*fields = g_string_free(line, FALSE);
}
+static void escape_semicolon(char *dest, const char *src, int len_max, int len)
+{
+ int i, j;
+
+ for (i = 0, j = 0; i < len && j < len_max - 1; i++, j++) {
+ if (src[i] == ';')
+ dest[j++] = '\\';
+
+ dest[j] = src[i];
+ }
+
+ dest[j] = 0;
+}
+
static void vcard_printf_begin(GString *vcards, uint8_t format)
{
vcard_printf(vcards, "BEGIN:VCARD");
--
1.6.3.3
Hi Rafal,
On Wed, Jul 20, 2011, Rafal Michalski wrote:
> According to specification of vcard 2.1, semicolon is only character
> which is escaped with a backslash character (in vcard's property field
> content). This patch provides "escape_semicolon" function which handles
> this issue.
> ---
> plugins/vcard.c | 14 ++++++++++++++
> 1 files changed, 14 insertions(+), 0 deletions(-)
Doesn't compile:
plugins/vcard.c:152:13: error: ‘escape_semicolon’ defined but not used [-Werror=unused-function]
If you're going to add a static function you also need to have at least
one user of it in the same patch.
Johan
This patch makes vcard module adjusted to escaping and encoding methods
depending on formatting vcard type and its properties field's content.
In general here are three possibilities (selection from escaping and
encoding methods is applied for each property separately):
default encoding and standard escaping method (for character set:
'\n', '\r', ';', ',', '\') - preferable for vcard 3.0
default encoding and only semicolon escaped - preferable for vcard 2.1
which property field does not contain newline character (and character
from set: '!', '"', '#', '$', '@', '[', '\', ']', '^', '`', '{', '|',
'}', '~' as well) - in this situation "quoted printable" encoding is not
taken into account
"quoted printable" encoding - preferable for vcard 2.1 which property
field contains newline character or character from set:
'!', '"', '#', '$', '@', '[', '\', ']', '^', '`', '{', '|', '}', '~'
Semicolon escaping is not taken into account since ';' character
(contained in property field) is always converted to "=3B" sequence.
---
plugins/vcard.c | 183 +++++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 145 insertions(+), 38 deletions(-)
diff --git a/plugins/vcard.c b/plugins/vcard.c
index 3e978ee..df865ab 100644
--- a/plugins/vcard.c
+++ b/plugins/vcard.c
@@ -350,10 +350,11 @@ gboolean address_fields_present(const char *address)
return FALSE;
}
-static void vcard_printf_name(GString *vcards,
+static void vcard_printf_name(GString *vcards, uint8_t format,
struct phonebook_contact *contact)
{
char *fields;
+ struct encoding_type encoding;
if (contact_fields_present(contact) == FALSE) {
/* If fields are empty, add only 'N:' as parameter.
@@ -367,22 +368,45 @@ static void vcard_printf_name(GString *vcards,
return;
}
+ select_fields_encoding(format, &encoding, contact->family,
+ contact->given, contact->additional,
+ contact->prefix, contact->suffix, NULL);
- get_escaped_fields(&fields, contact->family,
- contact->given, contact->additional,
- contact->prefix, contact->suffix,
- NULL);
+ if (encoding.type == ENCODING_TYPE_DEFAULT) {
+ escape_handler escape = get_escape_handler(format);
- vcard_printf(vcards, "N:%s", fields);
+ get_escaped_fields(escape, &fields, contact->family,
+ contact->given, contact->additional,
+ contact->prefix, contact->suffix, NULL);
- g_free(fields);
+ vcard_printf(vcards, "N:%s", fields);
+
+ g_free(fields);
+ } else if (encoding.type == ENCODING_TYPE_QUOTED_PRINTABLE) {
+ vcard_printf(vcards, "N;%s:", encoding.text);
+ g_string_truncate(vcards, vcards->len - 2);
+ vcard_qp_fields_printf(vcards, contact->family, contact->given,
+ contact->additional, contact->prefix,
+ contact->suffix, NULL);
+ }
}
-static void vcard_printf_fullname(GString *vcards, const char *text)
+static void vcard_printf_fullname(GString *vcards, uint8_t format,
+ const char *text)
{
char field[LEN_MAX];
- add_slash(field, text, LEN_MAX, strlen(text));
- vcard_printf(vcards, "FN:%s", field);
+ struct encoding_type encoding;
+
+ select_fields_encoding(format, &encoding, text, NULL);
+
+ if (encoding.type == ENCODING_TYPE_DEFAULT) {
+ select_escape(format, field, text, LEN_MAX, strlen(text));
+ vcard_printf(vcards, "FN:%s", field);
+ } else if (encoding.type == ENCODING_TYPE_QUOTED_PRINTABLE) {
+ vcard_printf(vcards, "FN;%s:", encoding.text);
+ g_string_truncate(vcards, vcards->len - 2);
+ vcard_qp_fields_printf(vcards, text, NULL);
+ }
}
static void vcard_printf_number(GString *vcards, uint8_t format,
@@ -391,6 +415,7 @@ static void vcard_printf_number(GString *vcards, uint8_t format,
{
const char *intl = "", *category_string = "";
char buf[128];
+ struct encoding_type encoding;
/* TEL is a mandatory field, include even if empty */
if (!number || !strlen(number) || !type) {
@@ -434,10 +459,19 @@ static void vcard_printf_number(GString *vcards, uint8_t format,
if ((type == TYPE_INTERNATIONAL) && (number[0] != '+'))
intl = "+";
- snprintf(buf, sizeof(buf), "TEL;%s:%s%s", category_string,
- intl, number);
+ select_fields_encoding(format, &encoding, number, NULL);
- vcard_printf(vcards, "%s", buf);
+ if (encoding.type == ENCODING_TYPE_DEFAULT) {
+ snprintf(buf, sizeof(buf), "TEL;%s:%s%s", category_string,
+ intl, number);
+ vcard_printf(vcards, "%s", buf);
+ } else if (encoding.type == ENCODING_TYPE_QUOTED_PRINTABLE) {
+ snprintf(buf, sizeof(buf), "TEL;%s", category_string);
+ vcard_printf(vcards, "%s;%s:", buf, encoding.text);
+ g_string_truncate(vcards, vcards->len - 2);
+ snprintf(buf, sizeof(buf), "%s%s", intl, number);
+ vcard_qp_fields_printf(vcards, buf, NULL);
+ }
}
static void vcard_printf_tag(GString *vcards, uint8_t format,
@@ -447,6 +481,7 @@ static void vcard_printf_tag(GString *vcards, uint8_t format,
int len;
char *separator = "", *type = "";
char buf[LEN_MAX], field[LEN_MAX];
+ struct encoding_type encoding;
if (tag == NULL || strlen(tag) == 0)
return;
@@ -466,8 +501,16 @@ static void vcard_printf_tag(GString *vcards, uint8_t format,
snprintf(buf, LEN_MAX, "%s%s%s%s", tag, separator, type, category);
- add_slash(field, fld, LEN_MAX, len);
- vcard_printf(vcards, "%s:%s", buf, field);
+ select_fields_encoding(format, &encoding, fld, NULL);
+
+ if (encoding.type == ENCODING_TYPE_DEFAULT) {
+ select_escape(format, field, fld, LEN_MAX, len);
+ vcard_printf(vcards, "%s:%s", buf, field);
+ } else if (encoding.type == ENCODING_TYPE_QUOTED_PRINTABLE) {
+ vcard_printf(vcards, "%s;%s:", buf, encoding.text);
+ g_string_truncate(vcards, vcards->len - 2);
+ vcard_qp_fields_printf(vcards, fld, NULL);
+ }
}
static void vcard_printf_email(GString *vcards, uint8_t format,
@@ -477,6 +520,7 @@ static void vcard_printf_email(GString *vcards, uint8_t format,
const char *category_string = "";
char field[LEN_MAX];
int len = 0;
+ struct encoding_type encoding;
if (!address || !(len = strlen(address))) {
vcard_printf(vcards, "EMAIL:");
@@ -502,8 +546,17 @@ static void vcard_printf_email(GString *vcards, uint8_t format,
category_string = "TYPE=INTERNET";
}
- add_slash(field, address, LEN_MAX, len);
- vcard_printf(vcards, "EMAIL;%s:%s", category_string, field);
+ select_fields_encoding(format, &encoding, address, NULL);
+
+ if (encoding.type == ENCODING_TYPE_DEFAULT) {
+ select_escape(format, field, address, LEN_MAX, len);
+ vcard_printf(vcards, "EMAIL;%s:%s", category_string, field);
+ } else if (encoding.type == ENCODING_TYPE_QUOTED_PRINTABLE) {
+ vcard_printf(vcards, "EMAIL;%s;%s:",
+ category_string, encoding.text);
+ g_string_truncate(vcards, vcards->len - 2);
+ vcard_qp_fields_printf(vcards, address, NULL);
+ }
}
static void vcard_printf_url(GString *vcards, uint8_t format,
@@ -512,6 +565,7 @@ static void vcard_printf_url(GString *vcards, uint8_t format,
{
const char *category_string = "";
char field[LEN_MAX];
+ struct encoding_type encoding;
if (!url || strlen(url) == 0) {
vcard_printf(vcards, "URL:");
@@ -539,8 +593,17 @@ static void vcard_printf_url(GString *vcards, uint8_t format,
break;
}
- add_slash(field, url, LEN_MAX, strlen(url));
- vcard_printf(vcards, "URL;%s:%s", category_string, field);
+ select_fields_encoding(format, &encoding, url, NULL);
+
+ if (encoding.type == ENCODING_TYPE_DEFAULT) {
+ select_escape(format, field, url, LEN_MAX, strlen(url));
+ vcard_printf(vcards, "URL;%s:%s", category_string, field);
+ } else if (encoding.type == ENCODING_TYPE_QUOTED_PRINTABLE) {
+ vcard_printf(vcards, "URL;%s;%s:",
+ category_string, encoding.text);
+ g_string_truncate(vcards, vcards->len - 2);
+ vcard_qp_fields_printf(vcards, url, NULL);
+ }
}
static gboolean org_fields_present(struct phonebook_contact *contact)
@@ -554,20 +617,33 @@ static gboolean org_fields_present(struct phonebook_contact *contact)
return FALSE;
}
-static void vcard_printf_org(GString *vcards,
+static void vcard_printf_org(GString *vcards, uint8_t format,
struct phonebook_contact *contact)
{
char *fields;
+ struct encoding_type encoding;
if (org_fields_present(contact) == FALSE)
return;
- get_escaped_fields(&fields, contact->company,
- contact->department, NULL);
+ select_fields_encoding(format, &encoding, contact->company,
+ contact->department, NULL);
+
+ if (encoding.type == ENCODING_TYPE_DEFAULT) {
+ escape_handler escape = get_escape_handler(format);
- vcard_printf(vcards, "ORG:%s", fields);
+ get_escaped_fields(escape, &fields, contact->company,
+ contact->department, NULL);
- g_free(fields);
+ vcard_printf(vcards, "ORG:%s", fields);
+
+ g_free(fields);
+ } else if (encoding.type == ENCODING_TYPE_QUOTED_PRINTABLE) {
+ vcard_printf(vcards, "ORG;%s:", encoding.text);
+ g_string_truncate(vcards, vcards->len - 2);
+ vcard_qp_fields_printf(vcards, contact->company,
+ contact->department, NULL);
+ }
}
static void vcard_printf_address(GString *vcards, uint8_t format,
@@ -579,6 +655,7 @@ static void vcard_printf_address(GString *vcards, uint8_t format,
const char *category_string = "";
int len, i;
gchar **address_fields;
+ struct encoding_type encoding;
if (!address || address_fields_present(address) == FALSE) {
vcard_printf(vcards, "ADR:");
@@ -608,22 +685,43 @@ static void vcard_printf_address(GString *vcards, uint8_t format,
address_fields = g_strsplit(address, ";", ADDR_FIELD_AMOUNT);
- for (i = 0; i < ADDR_FIELD_AMOUNT; ++i) {
- len = strlen(address_fields[i]);
- add_slash(field[i], address_fields[i], LEN_MAX, len);
+ select_fields_encoding(format, &encoding, address_fields[0],
+ address_fields[1], address_fields[2],
+ address_fields[3], address_fields[4],
+ address_fields[5], address_fields[6],
+ NULL);
+
+ if (encoding.type == ENCODING_TYPE_DEFAULT) {
+ for (i = 0; i < ADDR_FIELD_AMOUNT; ++i) {
+ len = strlen(address_fields[i]);
+ select_escape(format, field[i], address_fields[i],
+ LEN_MAX, len);
+ }
+
+ snprintf(buf, LEN_MAX, "%s;%s;%s;%s;%s;%s;%s",
+ field[0], field[1], field[2], field[3],
+ field[4], field[5], field[6]);
+
+ vcard_printf(vcards,"ADR;%s:%s", category_string, buf);
+ } else if (encoding.type == ENCODING_TYPE_QUOTED_PRINTABLE) {
+ vcard_printf(vcards, "ADR;%s;%s:",
+ category_string, encoding.text);
+ g_string_truncate(vcards, vcards->len - 2);
+ vcard_qp_fields_printf(vcards, address_fields[0],
+ address_fields[1], address_fields[2],
+ address_fields[3], address_fields[4],
+ address_fields[5], address_fields[6],
+ NULL);
}
- snprintf(buf, LEN_MAX, "%s;%s;%s;%s;%s;%s;%s",
- field[0], field[1], field[2], field[3], field[4], field[5], field[6]);
g_strfreev(address_fields);
-
- vcard_printf(vcards,"ADR;%s:%s", category_string, buf);
}
-static void vcard_printf_datetime(GString *vcards,
+static void vcard_printf_datetime(GString *vcards, uint8_t format,
struct phonebook_contact *contact)
{
const char *type;
+ struct encoding_type encoding;
switch (contact->calltype) {
case CALL_TYPE_MISSED:
@@ -643,8 +741,17 @@ static void vcard_printf_datetime(GString *vcards,
return;
}
- vcard_printf(vcards, "X-IRMC-CALL-DATETIME;%s:%s", type,
- contact->datetime);
+ select_fields_encoding(format, &encoding, contact->datetime, NULL);
+
+ if (encoding.type == ENCODING_TYPE_DEFAULT) {
+ vcard_printf(vcards, "X-IRMC-CALL-DATETIME;%s:%s",
+ type, contact->datetime);
+ } else if (encoding.type == ENCODING_TYPE_QUOTED_PRINTABLE) {
+ vcard_printf(vcards, "X-IRMC-CALL-DATETIME;%s;%s:",
+ type, encoding.text);
+ g_string_truncate(vcards, vcards->len - 2);
+ vcard_qp_fields_printf(vcards, contact->datetime, NULL);
+ }
}
static void vcard_printf_end(GString *vcards)
@@ -672,11 +779,11 @@ void phonebook_add_contact(GString *vcards, struct phonebook_contact *contact,
vcard_printf_tag(vcards, format, "UID", NULL, contact->uid);
if (filter & FILTER_N)
- vcard_printf_name(vcards, contact);
+ vcard_printf_name(vcards, format, contact);
if (filter & FILTER_FN && (*contact->fullname ||
format == FORMAT_VCARD30))
- vcard_printf_fullname(vcards, contact->fullname);
+ vcard_printf_fullname(vcards, format, contact->fullname);
if (filter & FILTER_TEL) {
GSList *l = contact->numbers;
@@ -735,7 +842,7 @@ void phonebook_add_contact(GString *vcards, struct phonebook_contact *contact,
contact->photo);
if (filter & FILTER_ORG)
- vcard_printf_org(vcards, contact);
+ vcard_printf_org(vcards, format, contact);
if (filter & FILTER_ROLE && *contact->role)
vcard_printf_tag(vcards, format, "ROLE", NULL, contact->role);
@@ -744,7 +851,7 @@ void phonebook_add_contact(GString *vcards, struct phonebook_contact *contact,
vcard_printf_tag(vcards, format, "TITLE", NULL, contact->title);
if (filter & FILTER_X_IRMC_CALL_DATETIME)
- vcard_printf_datetime(vcards, contact);
+ vcard_printf_datetime(vcards, format, contact);
vcard_printf_end(vcards);
}
--
1.6.3.3
Previously, it was trynig to create string (stored in "buf" buffer)
containing "%s" formatting piece for "vcard_printf" function and "number"
field. In this case "\%" is not valid escape sequence (for percent
character, "%%" is a valid sequence) - backslash is ignored, so sequence
"\%s" is treated as "%s" and replaced by string for "number" field,
hence "vcard_printf" function has nothing to do with "number" field, since
"buf" does not contain any "%s" formatting sequence (to get this
formatting sequence "buf" should contain "%%s" sequence).
However, this patch make simplification for printing phone number field by
avoiding storing formatting pieces (for instance "%%s") in "buf".
Now string for phone number field is stored directly in "buf" which is
simply passed to "vcard_printf" function (which uses "%s" formatting
string for this purpose).
---
plugins/vcard.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/plugins/vcard.c b/plugins/vcard.c
index 88851a6..3e978ee 100644
--- a/plugins/vcard.c
+++ b/plugins/vcard.c
@@ -434,10 +434,10 @@ static void vcard_printf_number(GString *vcards, uint8_t format,
if ((type == TYPE_INTERNATIONAL) && (number[0] != '+'))
intl = "+";
- snprintf(buf, sizeof(buf), "TEL;%s:%s\%s", category_string,
+ snprintf(buf, sizeof(buf), "TEL;%s:%s%s", category_string,
intl, number);
- vcard_printf(vcards, buf, number);
+ vcard_printf(vcards, "%s", buf);
}
static void vcard_printf_tag(GString *vcards, uint8_t format,
--
1.6.3.3
This patch provides mechanism of selection between two methods of encoding
vcard's property field, depending on vcard format and field's content.
In general "quoted printable" is selected, if vcard's 2.1 property field
contains newline character or some specific ASCII character from set:
'!', '"', '#', '$', '@', '[', '\', ']', '^', '`', '{', '|', '}', '~'.
In other cases default encoding is taken into account.
---
plugins/vcard.c | 26 ++++++++++++++++++++++++++
plugins/vcard.h | 5 +++++
2 files changed, 31 insertions(+), 0 deletions(-)
diff --git a/plugins/vcard.c b/plugins/vcard.c
index e2bbf4e..88851a6 100644
--- a/plugins/vcard.c
+++ b/plugins/vcard.c
@@ -274,6 +274,32 @@ static void vcard_qp_fields_printf(GString *vcards, ...)
g_string_append(vcards, "\r\n");
}
+static void select_fields_encoding(uint8_t format,
+ struct encoding_type *encoding, ...)
+{
+ char *field;
+ va_list ap;
+
+ encoding->type = ENCODING_TYPE_DEFAULT;
+ encoding->text = "";
+
+ if (format == FORMAT_VCARD21) {
+ va_start(ap, encoding);
+
+ for (field = va_arg(ap, char *); field; ) {
+ if (strpbrk(field, QP_SELECT)) {
+ encoding->type = ENCODING_TYPE_QUOTED_PRINTABLE;
+ encoding->text = "ENCODING=QUOTED-PRINTABLE";
+ break;
+ }
+
+ field = va_arg(ap, char *);
+ }
+
+ va_end(ap);
+ }
+}
+
static void vcard_printf_begin(GString *vcards, uint8_t format)
{
vcard_printf(vcards, "BEGIN:VCARD");
diff --git a/plugins/vcard.h b/plugins/vcard.h
index c317b1f..128a927 100644
--- a/plugins/vcard.h
+++ b/plugins/vcard.h
@@ -73,6 +73,11 @@ struct phonebook_contact {
int calltype;
};
+struct encoding_type {
+ char *text;
+ int type;
+};
+
void phonebook_add_contact(GString *vcards, struct phonebook_contact *contact,
uint64_t filter, uint8_t format);
--
1.6.3.3
Accoridng to vcard 2.1 specification, this patch provides
"quoted printable" encoding (described in RFC1521 document), which is
specific for vcard 2.1 formatting and should be preferable for instance,
if vcard's property field contains newline character.
---
plugins/vcard.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
plugins/vcard.h | 5 +++
2 files changed, 89 insertions(+), 0 deletions(-)
diff --git a/plugins/vcard.c b/plugins/vcard.c
index 544ea82..e2bbf4e 100644
--- a/plugins/vcard.c
+++ b/plugins/vcard.c
@@ -70,6 +70,15 @@
#define FORMAT_VCARD21 0x00
#define FORMAT_VCARD30 0x01
+#define QP_LINE_LEN 75
+#define QP_SELECT "\n!\"#$@[\\]^`{|}~"
+#define QP_ALWAYS "\t ;="
+#define QP_SUBSET QP_SELECT QP_ALWAYS
+#define QP_CR 0x0D
+#define QP_LF 0x0A
+#define QP_SOFT_BREAK "="
+#define QP_CHAR_LEN 3
+
typedef void (*escape_handler)
(char *dest, const char *src, int len_max, int len);
@@ -190,6 +199,81 @@ static void select_escape(uint8_t format, char *dest, const char *src,
}
}
+static gboolean qp_set(char c)
+{
+ unsigned char q = c;
+ int i;
+
+ for (i = 0; QP_SUBSET[i] != '\0' && q != QP_SUBSET[i]; i++);
+
+ if (QP_SUBSET[i] != '\0' || q < 0x20 || q > 0x7E)
+ return TRUE;
+
+ return FALSE;
+}
+
+static void append_qp_break_line(GString *vcards, size_t *limit)
+{
+ g_string_append(vcards, QP_SOFT_BREAK);
+ g_string_append(vcards, "\r\n ");
+ *limit = QP_LINE_LEN - 1;
+}
+
+static void append_qp_ascii(GString *vcards, size_t *limit, char c)
+{
+ if (*limit == 0)
+ append_qp_break_line(vcards, limit);
+
+ g_string_append_c(vcards, c);
+ --*limit;
+}
+
+static void append_qp_hex(GString *vcards, size_t *limit, char c)
+{
+ char hex[QP_CHAR_LEN + 1];
+
+ snprintf(hex, QP_CHAR_LEN + 1, "=%2.2X", (unsigned char) c);
+
+ if (*limit < QP_CHAR_LEN)
+ append_qp_break_line(vcards, limit);
+
+ g_string_append(vcards, hex);
+ *limit -= QP_CHAR_LEN;
+}
+
+static void vcard_qp_fields_printf(GString *vcards, ...)
+{
+ size_t i, size, limit = QP_LINE_LEN;
+ char *field;
+ va_list ap;
+
+ va_start(ap, vcards);
+
+ for (field = va_arg(ap, char *); field; ) {
+ size = strlen(field);
+
+ for (i = 0; i < size; ++i) {
+ if (field[i] == '\n') {
+ append_qp_hex(vcards, &limit, QP_CR);
+ append_qp_hex(vcards, &limit, QP_LF);
+ } else if (qp_set(field[i])) {
+ append_qp_hex(vcards, &limit, field[i]);
+ } else {
+ append_qp_ascii(vcards, &limit, field[i]);
+ }
+ }
+
+ field = va_arg(ap, char *);
+
+ if (field)
+ append_qp_ascii(vcards, &limit, ';');
+ }
+
+ va_end(ap);
+
+ g_string_append(vcards, "\r\n");
+}
+
static void vcard_printf_begin(GString *vcards, uint8_t format)
{
vcard_printf(vcards, "BEGIN:VCARD");
diff --git a/plugins/vcard.h b/plugins/vcard.h
index 88cdbed..c317b1f 100644
--- a/plugins/vcard.h
+++ b/plugins/vcard.h
@@ -40,6 +40,11 @@ enum phonebook_call_type {
CALL_TYPE_OUTGOING,
};
+enum encoding_field_type {
+ ENCODING_TYPE_DEFAULT,
+ ENCODING_TYPE_QUOTED_PRINTABLE,
+};
+
struct phonebook_field {
char *text;
int type;
--
1.6.3.3
This patch provides mechanism of selection between two methods of
escaping, depending on vcard format - vcard 2.1 requires only semicolon
for escaping ("escape_semicolon" function) and vcard 3.0 requires some
set of characters ('\n', '\r', ';', ',', '\') for escaping
("add_slash" function).
---
plugins/vcard.c | 31 +++++++++++++++++++++++++++++--
1 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/plugins/vcard.c b/plugins/vcard.c
index 4f61368..544ea82 100644
--- a/plugins/vcard.c
+++ b/plugins/vcard.c
@@ -70,6 +70,9 @@
#define FORMAT_VCARD21 0x00
#define FORMAT_VCARD30 0x01
+typedef void (*escape_handler)
+ (char *dest, const char *src, int len_max, int len);
+
/* according to RFC 2425, the output string may need folding */
static void vcard_printf(GString *str, const char *fmt, ...)
{
@@ -124,7 +127,7 @@ static void add_slash(char *dest, const char *src, int len_max, int len)
return;
}
-static void get_escaped_fields(char **fields, ...)
+static void get_escaped_fields(escape_handler escape, char **fields, ...)
{
va_list ap;
GString *line;
@@ -135,7 +138,7 @@ static void get_escaped_fields(char **fields, ...)
line = g_string_new("");
for (field = va_arg(ap, char *); field; ) {
- add_slash(escaped, field, LEN_MAX, strlen(field));
+ escape(escaped, field, LEN_MAX, strlen(field));
g_string_append(line, escaped);
field = va_arg(ap, char *);
@@ -163,6 +166,30 @@ static void escape_semicolon(char *dest, const char *src, int len_max, int len)
dest[j] = 0;
}
+static escape_handler get_escape_handler(uint8_t format)
+{
+ if (format == FORMAT_VCARD21)
+ return escape_semicolon;
+ else if (format == FORMAT_VCARD30)
+ return add_slash;
+
+ return add_slash;
+}
+
+static void select_escape(uint8_t format, char *dest, const char *src,
+ int len_max, int len)
+{
+ switch (format) {
+ case FORMAT_VCARD21:
+ escape_semicolon(dest, src, len_max, len);
+ break;
+ case FORMAT_VCARD30:
+ default:
+ add_slash(dest, src, len_max, len);
+ break;
+ }
+}
+
static void vcard_printf_begin(GString *vcards, uint8_t format)
{
vcard_printf(vcards, "BEGIN:VCARD");
--
1.6.3.3