| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- /*
- * OBEX Server
- *
- * Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
- *
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #include <string.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdint.h>
- #include <ctype.h>
- #include <errno.h>
- #include <glib.h>
- #include "gdbus/gdbus.h"
- #include "vcard.h"
- #define ADDR_FIELD_AMOUNT 7
- #define LEN_MAX 128
- #define TYPE_INTERNATIONAL 145
- #define PHONEBOOK_FLAG_CACHED 0x1
- #define FILTER_VERSION (1 << 0)
- #define FILTER_FN (1 << 1)
- #define FILTER_N (1 << 2)
- #define FILTER_PHOTO (1 << 3)
- #define FILTER_BDAY (1 << 4)
- #define FILTER_ADR (1 << 5)
- #define FILTER_LABEL (1 << 6)
- #define FILTER_TEL (1 << 7)
- #define FILTER_EMAIL (1 << 8)
- #define FILTER_MAILER (1 << 9)
- #define FILTER_TZ (1 << 10)
- #define FILTER_GEO (1 << 11)
- #define FILTER_TITLE (1 << 12)
- #define FILTER_ROLE (1 << 13)
- #define FILTER_LOGO (1 << 14)
- #define FILTER_AGENT (1 << 15)
- #define FILTER_ORG (1 << 16)
- #define FILTER_NOTE (1 << 17)
- #define FILTER_REV (1 << 18)
- #define FILTER_SOUND (1 << 19)
- #define FILTER_URL (1 << 20)
- #define FILTER_UID (1 << 21)
- #define FILTER_KEY (1 << 22)
- #define FILTER_NICKNAME (1 << 23)
- #define FILTER_CATEGORIES (1 << 24)
- #define FILTER_PROID (1 << 25)
- #define FILTER_CLASS (1 << 26)
- #define FILTER_SORT_STRING (1 << 27)
- #define FILTER_X_IRMC_CALL_DATETIME (1 << 28)
- #define FORMAT_VCARD21 0x00
- #define FORMAT_VCARD30 0x01
- #define QP_LINE_LEN 75
- #define QP_CHAR_LEN 3
- #define QP_CR 0x0D
- #define QP_LF 0x0A
- #define QP_ESC 0x5C
- #define QP_SOFT_LINE_BREAK "="
- #define QP_SELECT "\n!\"#$=@[\\]^`{|}~"
- #define ASCII_LIMIT 0x7F
- /* according to RFC 2425, the output string may need folding */
- static void vcard_printf(GString *str, const char *fmt, ...)
- {
- char buf[1024];
- va_list ap;
- int len_temp, line_number, i;
- unsigned int line_delimit = 75;
- va_start(ap, fmt);
- vsnprintf(buf, sizeof(buf), fmt, ap);
- va_end(ap);
- line_number = strlen(buf) / line_delimit + 1;
- for (i = 0; i < line_number; i++) {
- len_temp = MIN(line_delimit, strlen(buf) - line_delimit * i);
- g_string_append_len(str, buf + line_delimit * i, len_temp);
- if (i != line_number - 1)
- g_string_append(str, "\r\n ");
- }
- g_string_append(str, "\r\n");
- }
- /* According to RFC 2426, we need escape following characters:
- * '\n', '\r', ';', ',', '\'.
- */
- static void add_slash(char *dest, const char *src, int len_max, int len)
- {
- int i, j;
- for (i = 0, j = 0; i < len && j + 1 < len_max; i++, j++) {
- /* filling dest buffer - last field need to be reserved
- * for '\0'*/
- switch (src[i]) {
- case '\n':
- if (j + 2 >= len_max)
- /* not enough space in the buffer to put char
- * preceded with escaping sequence (and '\0' in
- * the end) */
- goto done;
- dest[j++] = '\\';
- dest[j] = 'n';
- break;
- case '\r':
- if (j + 2 >= len_max)
- goto done;
- dest[j++] = '\\';
- dest[j] = 'r';
- break;
- case '\\':
- case ';':
- case ',':
- if (j + 2 >= len_max)
- goto done;
- dest[j++] = '\\';
- /* fall through */
- default:
- dest[j] = src[i];
- break;
- }
- }
- done:
- dest[j] = 0;
- }
- 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 + 1 < len_max; i++, j++) {
- if (src[i] == ';') {
- if (j + 2 >= len_max)
- break;
- dest[j++] = '\\';
- }
- dest[j] = src[i];
- }
- dest[j] = 0;
- }
- static void set_escape(uint8_t format, char *dest, const char *src,
- int len_max, int len)
- {
- if (format == FORMAT_VCARD30)
- add_slash(dest, src, len_max, len);
- else if (format == FORMAT_VCARD21)
- escape_semicolon(dest, src, len_max, len);
- }
- static void get_escaped_fields(uint8_t format, char **fields, ...)
- {
- va_list ap;
- GString *line;
- char *field;
- char escaped[LEN_MAX];
- va_start(ap, fields);
- line = g_string_new("");
- for (field = va_arg(ap, char *); field; ) {
- set_escape(format, escaped, field, LEN_MAX, strlen(field));
- g_string_append(line, escaped);
- field = va_arg(ap, char *);
- if (field)
- g_string_append(line, ";");
- }
- va_end(ap);
- *fields = g_string_free(line, FALSE);
- }
- static gboolean set_qp_encoding(char c)
- {
- unsigned char q = c;
- if (strchr(QP_SELECT, q) != NULL)
- return TRUE;
- if (q < '!' || q > '~')
- return TRUE;
- return FALSE;
- }
- static void append_qp_break_line(GString *vcards, size_t *limit)
- {
- /* Quoted Printable lines of text must be limited to less than 76
- * characters and terminated by Quoted Printable softline break
- * sequence of "=" (if some more characters left) */
- g_string_append(vcards, QP_SOFT_LINE_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)
- {
- if (*limit < QP_CHAR_LEN)
- append_qp_break_line(vcards, limit);
- g_string_append_printf(vcards, "=%2.2X", (unsigned char) c);
- *limit -= QP_CHAR_LEN;
- }
- static void append_qp_new_line(GString *vcards, size_t *limit)
- {
- /* Multiple lines of text are separated with a Quoted Printable CRLF
- * sequence of "=0D" followed by "=0A" followed by a Quoted Printable
- * softline break sequence of "=" */
- append_qp_hex(vcards, limit, QP_CR);
- append_qp_hex(vcards, limit, QP_LF);
- append_qp_break_line(vcards, limit);
- }
- static gboolean utf8_select(const char *field)
- {
- const char *pos;
- if (g_utf8_validate(field, -1, NULL) == FALSE)
- return FALSE;
- for (pos = field; *pos != '\0'; pos = g_utf8_next_char(pos)) {
- /* Test for non-standard UTF-8 character (out of range
- * standard ASCII set), composed of more than single byte
- * and represented by 32-bit value greater than 0x7F */
- if (g_utf8_get_char(pos) > ASCII_LIMIT)
- return TRUE;
- }
- return FALSE;
- }
- static void vcard_qp_print_encoded(GString *vcards, const char *desc, ...)
- {
- const char *field, *charset = "";
- const char *encoding = ";ENCODING=QUOTED-PRINTABLE";
- size_t limit, param_len;
- va_list ap;
- va_start(ap, desc);
- for (field = va_arg(ap, char *); field; field = va_arg(ap, char *)) {
- if (utf8_select(field) == TRUE) {
- charset = ";CHARSET=UTF-8";
- break;
- }
- }
- va_end(ap);
- vcard_printf(vcards, "%s%s%s:", desc, encoding, charset);
- g_string_truncate(vcards, vcards->len - 2);
- param_len = strlen(desc) + strlen(encoding) + strlen(charset) + 1;
- limit = QP_LINE_LEN - param_len;
- va_start(ap, desc);
- for (field = va_arg(ap, char *); field != NULL; ) {
- size_t i, size = strlen(field);
- for (i = 0; i < size; ++i) {
- if (set_qp_encoding(field[i])) {
- if (field[i] == '\n') {
- append_qp_new_line(vcards, &limit);
- continue;
- }
- append_qp_hex(vcards, &limit, field[i]);
- } else {
- /* According to vCard 2.1 spec. semicolons in
- * property parameter value must be escaped */
- if (field[i] == ';')
- append_qp_hex(vcards, &limit, QP_ESC);
- 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 gboolean select_qp_encoding(uint8_t format, ...)
- {
- char *field;
- va_list ap;
- if (format != FORMAT_VCARD21)
- return FALSE;
- va_start(ap, format);
- for (field = va_arg(ap, char *); field; field = va_arg(ap, char *)) {
- int i;
- unsigned char c;
- if (strpbrk(field, QP_SELECT)) {
- va_end(ap);
- return TRUE;
- }
- /* Quoted Printable encoding is selected if there is
- * a character, which value is out of range standard
- * ASCII set, since it may be a part of some
- * non-standard character such as specified by UTF-8 */
- for (i = 0; (c = field[i]) != '\0'; ++i) {
- if (c > ASCII_LIMIT) {
- va_end(ap);
- return TRUE;
- }
- }
- }
- va_end(ap);
- return FALSE;
- }
- static void vcard_printf_begin(GString *vcards, uint8_t format)
- {
- vcard_printf(vcards, "BEGIN:VCARD");
- if (format == FORMAT_VCARD30)
- vcard_printf(vcards, "VERSION:3.0");
- else if (format == FORMAT_VCARD21)
- vcard_printf(vcards, "VERSION:2.1");
- }
- /* check if there is at least one contact field with personal data present */
- static gboolean contact_fields_present(struct phonebook_contact * contact)
- {
- if (contact->family && strlen(contact->family) > 0)
- return TRUE;
- if (contact->given && strlen(contact->given) > 0)
- return TRUE;
- if (contact->additional && strlen(contact->additional) > 0)
- return TRUE;
- if (contact->prefix && strlen(contact->prefix) > 0)
- return TRUE;
- if (contact->suffix && strlen(contact->suffix) > 0)
- return TRUE;
- /* none of the personal data fields are present*/
- return FALSE;
- }
- static void vcard_printf_name(GString *vcards, uint8_t format,
- struct phonebook_contact *contact)
- {
- char *fields;
- if (contact_fields_present(contact) == FALSE) {
- /* If fields are empty, add only 'N:' as parameter.
- * This is crucial for some devices (Nokia BH-903) which
- * have problems with history listings and can't determine
- * that a parameter is really empty if there are unnecessary
- * characters after 'N:' (e.g. 'N:;;;;').
- * We need to add only'N:' param - without semicolons.
- */
- vcard_printf(vcards, "N:");
- return;
- }
- if (select_qp_encoding(format, contact->family, contact->given,
- contact->additional, contact->prefix,
- contact->suffix, NULL)) {
- vcard_qp_print_encoded(vcards, "N", contact->family,
- contact->given, contact->additional,
- contact->prefix, contact->suffix,
- NULL);
- return;
- }
- get_escaped_fields(format, &fields, contact->family,
- contact->given, contact->additional,
- contact->prefix, contact->suffix,
- NULL);
- vcard_printf(vcards, "N:%s", fields);
- g_free(fields);
- }
- static void vcard_printf_fullname(GString *vcards, uint8_t format,
- const char *text)
- {
- char field[LEN_MAX];
- if (!text || strlen(text) == 0) {
- vcard_printf(vcards, "FN:");
- return;
- }
- if (select_qp_encoding(format, text, NULL)) {
- vcard_qp_print_encoded(vcards, "FN", text, NULL);
- return;
- }
- set_escape(format, field, text, LEN_MAX, strlen(text));
- vcard_printf(vcards, "FN:%s", field);
- }
- static void vcard_printf_number(GString *vcards, uint8_t format,
- const char *number, int type,
- enum phonebook_number_type category)
- {
- const char *intl = "", *category_string = "";
- char buf[LEN_MAX], field[LEN_MAX];
- /* TEL is a mandatory field, include even if empty */
- if (!number || !strlen(number) || !type) {
- vcard_printf(vcards, "TEL:");
- return;
- }
- switch (category) {
- case TEL_TYPE_HOME:
- if (format == FORMAT_VCARD21)
- category_string = "HOME;VOICE";
- else if (format == FORMAT_VCARD30)
- category_string = "TYPE=HOME;TYPE=VOICE";
- break;
- case TEL_TYPE_MOBILE:
- if (format == FORMAT_VCARD21)
- category_string = "CELL;VOICE";
- else if (format == FORMAT_VCARD30)
- category_string = "TYPE=CELL;TYPE=VOICE";
- break;
- case TEL_TYPE_FAX:
- if (format == FORMAT_VCARD21)
- category_string = "FAX";
- else if (format == FORMAT_VCARD30)
- category_string = "TYPE=FAX";
- break;
- case TEL_TYPE_WORK:
- if (format == FORMAT_VCARD21)
- category_string = "WORK;VOICE";
- else if (format == FORMAT_VCARD30)
- category_string = "TYPE=WORK;TYPE=VOICE";
- break;
- case TEL_TYPE_OTHER:
- if (format == FORMAT_VCARD21)
- category_string = "OTHER;VOICE";
- else if (format == FORMAT_VCARD30)
- category_string = "TYPE=OTHER;TYPE=VOICE";
- break;
- }
- if ((type == TYPE_INTERNATIONAL) && (number[0] != '+'))
- intl = "+";
- snprintf(field, sizeof(field), "%s%s", intl, number);
- if (select_qp_encoding(format, number, NULL)) {
- snprintf(buf, sizeof(buf), "TEL;%s", category_string);
- vcard_qp_print_encoded(vcards, buf, field, NULL);
- return;
- }
- vcard_printf(vcards, "TEL;%s:%s", category_string, field);
- }
- static void vcard_printf_tag(GString *vcards, uint8_t format,
- const char *tag, const char *category,
- const char *fld)
- {
- int len;
- char *separator = "", *type = "";
- char buf[LEN_MAX], field[LEN_MAX];
- if (tag == NULL || strlen(tag) == 0)
- return;
- if (fld == NULL || (len = strlen(fld)) == 0) {
- vcard_printf(vcards, "%s:", tag);
- return;
- }
- if (category && strlen(category)) {
- separator = ";";
- if (format == FORMAT_VCARD30)
- type = "TYPE=";
- } else {
- category = "";
- }
- snprintf(buf, LEN_MAX, "%s%s%s%s", tag, separator, type, category);
- if (select_qp_encoding(format, fld, NULL)) {
- vcard_qp_print_encoded(vcards, buf, fld, NULL);
- return;
- }
- set_escape(format, field, fld, LEN_MAX, len);
- vcard_printf(vcards, "%s:%s", buf, field);
- }
- static void vcard_printf_email(GString *vcards, uint8_t format,
- const char *address,
- enum phonebook_field_type category)
- {
- const char *category_string = "";
- char buf[LEN_MAX], field[LEN_MAX];
- int len = 0;
- if (!address || !(len = strlen(address))) {
- vcard_printf(vcards, "EMAIL:");
- return;
- }
- switch (category) {
- case FIELD_TYPE_HOME:
- if (format == FORMAT_VCARD21)
- category_string = "INTERNET;HOME";
- else if (format == FORMAT_VCARD30)
- category_string = "TYPE=INTERNET;TYPE=HOME";
- break;
- case FIELD_TYPE_WORK:
- if (format == FORMAT_VCARD21)
- category_string = "INTERNET;WORK";
- else if (format == FORMAT_VCARD30)
- category_string = "TYPE=INTERNET;TYPE=WORK";
- break;
- case FIELD_TYPE_OTHER:
- default:
- if (format == FORMAT_VCARD21)
- category_string = "INTERNET";
- else if (format == FORMAT_VCARD30)
- category_string = "TYPE=INTERNET;TYPE=OTHER";
- }
- if (select_qp_encoding(format, address, NULL)) {
- snprintf(buf, sizeof(buf), "EMAIL;%s", category_string);
- vcard_qp_print_encoded(vcards, buf, address, NULL);
- return;
- }
- set_escape(format, field, address, LEN_MAX, len);
- vcard_printf(vcards, "EMAIL;%s:%s", category_string, field);
- }
- static void vcard_printf_url(GString *vcards, uint8_t format,
- const char *url,
- enum phonebook_field_type category)
- {
- const char *category_string = "";
- char buf[LEN_MAX], field[LEN_MAX];
- if (!url || strlen(url) == 0) {
- vcard_printf(vcards, "URL:");
- return;
- }
- switch (category) {
- case FIELD_TYPE_HOME:
- if (format == FORMAT_VCARD21)
- category_string = "INTERNET;HOME";
- else if (format == FORMAT_VCARD30)
- category_string = "TYPE=INTERNET;TYPE=HOME";
- break;
- case FIELD_TYPE_WORK:
- if (format == FORMAT_VCARD21)
- category_string = "INTERNET;WORK";
- else if (format == FORMAT_VCARD30)
- category_string = "TYPE=INTERNET;TYPE=WORK";
- break;
- case FIELD_TYPE_OTHER:
- default:
- if (format == FORMAT_VCARD21)
- category_string = "INTERNET";
- else if (format == FORMAT_VCARD30)
- category_string = "TYPE=INTERNET";
- break;
- }
- if (select_qp_encoding(format, url, NULL)) {
- snprintf(buf, sizeof(buf), "URL;%s", category_string);
- vcard_qp_print_encoded(vcards, buf, url, NULL);
- return;
- }
- set_escape(format, field, url, LEN_MAX, strlen(url));
- vcard_printf(vcards, "URL;%s:%s", category_string, field);
- }
- static gboolean org_fields_present(struct phonebook_contact *contact)
- {
- if (contact->company && strlen(contact->company))
- return TRUE;
- if (contact->department && strlen(contact->department))
- return TRUE;
- return FALSE;
- }
- static void vcard_printf_org(GString *vcards, uint8_t format,
- struct phonebook_contact *contact)
- {
- char *fields;
- if (org_fields_present(contact) == FALSE)
- return;
- if (select_qp_encoding(format, contact->company,
- contact->department, NULL)) {
- vcard_qp_print_encoded(vcards, "ORG", contact->company,
- contact->department, NULL);
- return;
- }
- get_escaped_fields(format, &fields, contact->company,
- contact->department, NULL);
- vcard_printf(vcards, "ORG:%s", fields);
- g_free(fields);
- }
- static void vcard_printf_address(GString *vcards, uint8_t format,
- struct phonebook_addr *address)
- {
- char *fields, field_esc[LEN_MAX];
- const char *category_string = "";
- char buf[LEN_MAX], *address_fields[ADDR_FIELD_AMOUNT];
- int i;
- size_t len;
- GSList *l;
- if (!address) {
- vcard_printf(vcards, "ADR:");
- return;
- }
- switch (address->type) {
- case FIELD_TYPE_HOME:
- if (format == FORMAT_VCARD21)
- category_string = "HOME";
- else if (format == FORMAT_VCARD30)
- category_string = "TYPE=HOME";
- break;
- case FIELD_TYPE_WORK:
- if (format == FORMAT_VCARD21)
- category_string = "WORK";
- else if (format == FORMAT_VCARD30)
- category_string = "TYPE=WORK";
- break;
- default:
- if (format == FORMAT_VCARD21)
- category_string = "OTHER";
- else if (format == FORMAT_VCARD30)
- category_string = "TYPE=OTHER";
- break;
- }
- for (i = 0, l = address->fields; l; l = l->next)
- address_fields[i++] = l->data;
- if (select_qp_encoding(format, address_fields[0], address_fields[1],
- address_fields[2], address_fields[3],
- address_fields[4], address_fields[5],
- address_fields[6], NULL)) {
- snprintf(buf, sizeof(buf), "ADR;%s", category_string);
- vcard_qp_print_encoded(vcards, buf,
- address_fields[0], address_fields[1],
- address_fields[2], address_fields[3],
- address_fields[4], address_fields[5],
- address_fields[6], NULL);
- return;
- }
- /* allocate enough memory to insert address fields separated by ';'
- * and terminated by '\0' */
- len = ADDR_FIELD_AMOUNT * LEN_MAX;
- fields = g_malloc0(len);
- for (l = address->fields; l; l = l->next) {
- char *field = l->data;
- if (field) {
- set_escape(format, field_esc, field, LEN_MAX,
- strlen(field));
- g_strlcat(fields, field_esc, len);
- }
- if (l->next)
- /* not adding ';' after last addr field */
- g_strlcat(fields, ";", len);
- }
- vcard_printf(vcards,"ADR;%s:%s", category_string, fields);
- g_free(fields);
- }
- static void vcard_printf_datetime(GString *vcards, uint8_t format,
- struct phonebook_contact *contact)
- {
- const char *type;
- char buf[LEN_MAX];
- switch (contact->calltype) {
- case CALL_TYPE_MISSED:
- type = "MISSED";
- break;
- case CALL_TYPE_INCOMING:
- type = "RECEIVED";
- break;
- case CALL_TYPE_OUTGOING:
- type = "DIALED";
- break;
- case CALL_TYPE_NOT_A_CALL:
- default:
- return;
- }
- if (select_qp_encoding(format, contact->datetime, NULL)) {
- snprintf(buf, sizeof(buf), "X-IRMC-CALL-DATETIME;%s", type);
- vcard_qp_print_encoded(vcards, buf, contact->datetime, NULL);
- return;
- }
- vcard_printf(vcards, "X-IRMC-CALL-DATETIME;%s:%s", type,
- contact->datetime);
- }
- static void vcard_printf_end(GString *vcards)
- {
- vcard_printf(vcards, "END:VCARD");
- }
- void phonebook_add_contact(GString *vcards, struct phonebook_contact *contact,
- uint64_t filter, uint8_t format)
- {
- if (format == FORMAT_VCARD30 && filter)
- filter |= (FILTER_VERSION | FILTER_FN | FILTER_N | FILTER_TEL);
- else if (format == FORMAT_VCARD21 && filter)
- filter |= (FILTER_VERSION | FILTER_N | FILTER_TEL);
- else
- filter = (FILTER_VERSION | FILTER_UID | FILTER_N | FILTER_FN |
- FILTER_TEL | FILTER_EMAIL | FILTER_ADR |
- FILTER_BDAY | FILTER_NICKNAME | FILTER_URL |
- FILTER_PHOTO | FILTER_ORG | FILTER_ROLE |
- FILTER_TITLE | FILTER_X_IRMC_CALL_DATETIME);
- vcard_printf_begin(vcards, format);
- if (filter & FILTER_UID && *contact->uid)
- vcard_printf_tag(vcards, format, "UID", NULL, contact->uid);
- if (filter & FILTER_N)
- vcard_printf_name(vcards, format, contact);
- if (filter & FILTER_FN && (*contact->fullname ||
- format == FORMAT_VCARD30))
- vcard_printf_fullname(vcards, format, contact->fullname);
- if (filter & FILTER_TEL) {
- GSList *l = contact->numbers;
- if (g_slist_length(l) == 0)
- vcard_printf_number(vcards, format, NULL, 1,
- TEL_TYPE_OTHER);
- for (; l; l = l->next) {
- struct phonebook_field *number = l->data;
- vcard_printf_number(vcards, format, number->text, 1,
- number->type);
- }
- }
- if (filter & FILTER_EMAIL) {
- GSList *l = contact->emails;
- for (; l; l = l->next) {
- struct phonebook_field *email = l->data;
- vcard_printf_email(vcards, format, email->text,
- email->type);
- }
- }
- if (filter & FILTER_ADR) {
- GSList *l = contact->addresses;
- for (; l; l = l->next) {
- struct phonebook_addr *addr = l->data;
- vcard_printf_address(vcards, format, addr);
- }
- }
- if (filter & FILTER_BDAY && *contact->birthday)
- vcard_printf_tag(vcards, format, "BDAY", NULL,
- contact->birthday);
- if (filter & FILTER_NICKNAME && *contact->nickname)
- vcard_printf_tag(vcards, format, "NICKNAME", NULL,
- contact->nickname);
- if (filter & FILTER_URL) {
- GSList *l = contact->urls;
- for (; l; l = l->next) {
- struct phonebook_field *url = l->data;
- vcard_printf_url(vcards, format, url->text, url->type);
- }
- }
- if (filter & FILTER_PHOTO && *contact->photo)
- vcard_printf_tag(vcards, format, "PHOTO", NULL,
- contact->photo);
- if (filter & FILTER_ORG)
- vcard_printf_org(vcards, format, contact);
- if (filter & FILTER_ROLE && *contact->role)
- vcard_printf_tag(vcards, format, "ROLE", NULL, contact->role);
- if (filter & FILTER_TITLE && *contact->title)
- vcard_printf_tag(vcards, format, "TITLE", NULL, contact->title);
- if (filter & FILTER_X_IRMC_CALL_DATETIME)
- vcard_printf_datetime(vcards, format, contact);
- vcard_printf_end(vcards);
- }
- static void field_free(gpointer data)
- {
- struct phonebook_field *field = data;
- g_free(field->text);
- g_free(field);
- }
- void phonebook_addr_free(gpointer addr)
- {
- struct phonebook_addr *address = addr;
- g_slist_free_full(address->fields, g_free);
- g_free(address);
- }
- void phonebook_contact_free(struct phonebook_contact *contact)
- {
- if (contact == NULL)
- return;
- g_slist_free_full(contact->numbers, field_free);
- g_slist_free_full(contact->emails, field_free);
- g_slist_free_full(contact->addresses, phonebook_addr_free);
- g_slist_free_full(contact->urls, field_free);
- g_free(contact->uid);
- g_free(contact->fullname);
- g_free(contact->given);
- g_free(contact->family);
- g_free(contact->additional);
- g_free(contact->prefix);
- g_free(contact->suffix);
- g_free(contact->birthday);
- g_free(contact->nickname);
- g_free(contact->photo);
- g_free(contact->company);
- g_free(contact->department);
- g_free(contact->role);
- g_free(contact->title);
- g_free(contact->datetime);
- g_free(contact);
- }
|