/silc-toolkit-1.1.10/lib/silcvcard/silcvcard.c
C | 463 lines | 393 code | 36 blank | 34 comment | 97 complexity | 852b7981ba740237543953259b713365 MD5 | raw file
Possible License(s): GPL-2.0
- /*
- silcvcard.c
- Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2002 - 2005 Pekka Riikonen
- The contents of this file are subject to one of the Licenses specified
- in the COPYING file; You may not use this file except in compliance
- with the License.
- The software distributed under the License is distributed on an "AS IS"
- basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
- KIND, either expressed or implied. See the COPYING file for more
- information.
- */
- /* $Id$ */
- /* Implementation of the VCard (RFC 2426) */
- #include "silc.h"
- #define VCARD_HEADER "BEGIN:VCARD\n"
- #define VCARD_VERSION "VERSION:3.0\n"
- #define VCARD_FOOTER "END:VCARD\n"
- /* Encode VCard */
- unsigned char *silc_vcard_encode(SilcVCard vcard, SilcUInt32 *vcard_len)
- {
- SilcBufferStruct buffer;
- int i;
- if (!vcard->full_name || !vcard->family_name || !vcard->first_name)
- return NULL;
- memset(&buffer, 0, sizeof(buffer));
- silc_buffer_strformat(
- &buffer,
- VCARD_HEADER,
- VCARD_VERSION,
- "FN:", vcard->full_name, "\n",
- "N:", vcard->family_name, ";", vcard->first_name, ";",
- vcard->middle_names, ";", vcard->prefix, ";", vcard->suffix, "\n",
- SILC_STRFMT_END);
- if (vcard->nickname)
- silc_buffer_strformat(&buffer,
- "NICKNAME:", vcard->nickname, "\n",
- SILC_STRFMT_END);
- if (vcard->bday)
- silc_buffer_strformat(&buffer,
- "BDAY:", vcard->bday, "\n",
- SILC_STRFMT_END);
- if (vcard->title)
- silc_buffer_strformat(&buffer,
- "TITLE:", vcard->title, "\n",
- SILC_STRFMT_END);
- if (vcard->role)
- silc_buffer_strformat(&buffer,
- "ROLE:", vcard->role, "\n",
- SILC_STRFMT_END);
- if (vcard->org_name)
- silc_buffer_strformat(&buffer,
- "ORG:", vcard->org_name, ";", vcard->org_unit, "\n",
- SILC_STRFMT_END);
- if (vcard->categories)
- silc_buffer_strformat(&buffer,
- "CATEGORIES:", vcard->categories, "\n",
- SILC_STRFMT_END);
- if (vcard->catclass)
- silc_buffer_strformat(&buffer,
- "CLASS:", vcard->catclass, "\n",
- SILC_STRFMT_END);
- if (vcard->url)
- silc_buffer_strformat(&buffer,
- "URL:", vcard->url, "\n",
- SILC_STRFMT_END);
- if (vcard->label)
- silc_buffer_strformat(&buffer,
- "LABEL;", vcard->url, "\n",
- SILC_STRFMT_END);
- for (i = 0; i < vcard->num_addrs; i++) {
- silc_buffer_strformat(&buffer,
- "ADR;TYPE=",
- vcard->addrs[i].type, ":",
- vcard->addrs[i].pbox, ";",
- vcard->addrs[i].ext_addr, ";",
- vcard->addrs[i].street_addr, ";",
- vcard->addrs[i].city, ";",
- vcard->addrs[i].state, ";",
- vcard->addrs[i].code, ";",
- vcard->addrs[i].country, "\n",
- SILC_STRFMT_END);
- }
- for (i = 0; i < vcard->num_tels; i++) {
- silc_buffer_strformat(&buffer,
- "TEL;TYPE=",
- vcard->tels[i].type, ":",
- vcard->tels[i].telnum, "\n",
- SILC_STRFMT_END);
- }
- for (i = 0; i < vcard->num_emails; i++) {
- silc_buffer_strformat(&buffer,
- "EMAIL;TYPE=",
- vcard->emails[i].type, ":",
- vcard->emails[i].address, "\n",
- SILC_STRFMT_END);
- }
- if (vcard->note)
- silc_buffer_strformat(&buffer,
- "NOTE:", vcard->note, "\n",
- SILC_STRFMT_END);
- if (vcard->rev)
- silc_buffer_strformat(&buffer,
- "REV:", vcard->rev, "\n",
- SILC_STRFMT_END);
- silc_buffer_strformat(&buffer, VCARD_FOOTER, SILC_STRFMT_END);
- if (vcard_len)
- *vcard_len = silc_buffer_truelen(&buffer);
- return buffer.head;
- }
- /* Take one token */
- #define VCARD_TOKEN(x) \
- if (!(x)) { \
- (x) = silc_memdup(val + off, i - off); \
- off = i + 1; \
- continue; \
- }
- /* Take on TYPE= token and prepare for next token, accept the
- type also without TYPE= as it is possible */
- #define VCARD_TYPETOKEN(x) \
- if (!(x)) { \
- int tmpi = 0; \
- if (!strncasecmp(val + off, "TYPE=", 5)) \
- tmpi = 5; \
- (x) = silc_memdup(val + off + tmpi, i - off - tmpi - 1); \
- tmpi = off + tmpi + strlen((x)) + 1; \
- off = i; \
- i = tmpi; \
- }
- /* Take last token */
- #define VCARD_LASTTOKEN(x) \
- if (!(x)) { \
- if (off < len) \
- (x) = silc_memdup(val + off, len - off); \
- } \
- /* Get one (single) field */
- #define VCARD_FIELD(val, c, x) \
- do { \
- if (!strncasecmp(val, (c), strlen((c)))) { \
- int tmpl = strlen((c)); \
- if ((x)) \
- break; \
- if (len - tmpl > 0) \
- (x) = silc_memdup(val + tmpl, len - tmpl); \
- goto next; \
- } \
- } while(0)
- /* Decode VCard */
- SilcBool silc_vcard_decode(const unsigned char *data, SilcUInt32 data_len,
- SilcVCard vcard)
- {
- unsigned char *val;
- SilcBool has_begin = FALSE, has_end = FALSE;
- int len, i, off = 0;
- val = (unsigned char *)data;
- while (val) {
- len = 0;
- for (i = (val - data); i < data_len; i++) {
- if (data[i] == '\0' || data[i] == '\n') {
- len = i - (val - data);
- break;
- }
- }
- if (!len || len > data_len - (val - data))
- break;
- /* Check for mandatory header and footer */
- if (!strncasecmp(val, VCARD_HEADER, strlen(VCARD_HEADER))) {
- has_begin = TRUE;
- goto next;
- }
- if (!strncasecmp(val, VCARD_FOOTER, strlen(VCARD_FOOTER))) {
- has_end = TRUE;
- goto next;
- }
- /* Get single fields */
- VCARD_FIELD(val, "FN:", vcard->full_name);
- VCARD_FIELD(val, "NICKNAME:", vcard->nickname);
- VCARD_FIELD(val, "BDAY:", vcard->bday);
- VCARD_FIELD(val, "TITLE:", vcard->title);
- VCARD_FIELD(val, "ROLE:", vcard->role);
- VCARD_FIELD(val, "CATEGORIES:", vcard->categories);
- VCARD_FIELD(val, "CLASS:", vcard->catclass);
- VCARD_FIELD(val, "URL:", vcard->url);
- VCARD_FIELD(val, "LABEL;", vcard->label);
- VCARD_FIELD(val, "NOTE:", vcard->note);
- VCARD_FIELD(val, "REV:", vcard->rev);
- /* Get multi-column fields */
- if (!strncasecmp(val, "N:", 2)) {
- if (vcard->family_name)
- break;
- if (len - 2) {
- off = 2;
- for (i = off; i < len; i++)
- if (val[i] == ';') {
- VCARD_TOKEN(vcard->family_name);
- VCARD_TOKEN(vcard->first_name);
- VCARD_TOKEN(vcard->middle_names);
- VCARD_TOKEN(vcard->prefix);
- }
- if (!vcard->family_name && !vcard->first_name) {
- VCARD_LASTTOKEN(vcard->family_name);
- off += (len - off);
- }
- if (!vcard->first_name) {
- VCARD_LASTTOKEN(vcard->first_name);
- } else {
- VCARD_LASTTOKEN(vcard->suffix);
- }
- }
- goto next;
- }
- if (!strncasecmp(val, "ORG:", 4)) {
- if (vcard->org_name)
- continue;
- if (len - 4) {
- off = 4;
- for (i = off; i < len; i++) {
- if (val[i] == ';') {
- VCARD_TOKEN(vcard->org_name);
- break;
- }
- }
- /* It's possible to have ORG without last ';', so check for it */
- if (!vcard->org_name) {
- VCARD_LASTTOKEN(vcard->org_name);
- } else {
- VCARD_LASTTOKEN(vcard->org_unit);
- }
- }
- goto next;
- }
- if (!strncasecmp(val, "ADR;", 4)) {
- vcard->addrs = silc_realloc(vcard->addrs, sizeof(*vcard->addrs) *
- (vcard->num_addrs + 1));
- memset(&vcard->addrs[vcard->num_addrs], 0, sizeof(*vcard->addrs));
- if (len - 4) {
- off = 4;
- for (i = off; i < len; i++)
- if (val[i] == ';') {
- VCARD_TYPETOKEN(vcard->addrs[vcard->num_addrs].type);
- VCARD_TOKEN(vcard->addrs[vcard->num_addrs].pbox);
- VCARD_TOKEN(vcard->addrs[vcard->num_addrs].ext_addr);
- VCARD_TOKEN(vcard->addrs[vcard->num_addrs].street_addr);
- VCARD_TOKEN(vcard->addrs[vcard->num_addrs].city);
- VCARD_TOKEN(vcard->addrs[vcard->num_addrs].state);
- VCARD_TOKEN(vcard->addrs[vcard->num_addrs].code);
- }
- VCARD_LASTTOKEN(vcard->addrs[vcard->num_addrs].country);
- }
- vcard->num_addrs++;
- goto next;
- }
- if (!strncasecmp(val, "TEL;", 4)) {
- vcard->tels = silc_realloc(vcard->tels, sizeof(*vcard->tels) *
- (vcard->num_tels + 1));
- memset(&vcard->tels[vcard->num_tels], 0, sizeof(*vcard->tels));
- if (len - 4) {
- off = 4;
- for (i = off; i < len; i++)
- if (val[i] == ':') {
- i++;
- VCARD_TYPETOKEN(vcard->tels[vcard->num_tels].type);
- break;
- }
- VCARD_LASTTOKEN(vcard->tels[vcard->num_tels].telnum);
- }
- vcard->num_tels++;
- goto next;
- }
- if (!strncasecmp(val, "EMAIL;", 6)) {
- vcard->emails = silc_realloc(vcard->emails, sizeof(*vcard->emails) *
- (vcard->num_emails + 1));
- memset(&vcard->emails[vcard->num_emails], 0, sizeof(*vcard->emails));
- if (len - 6) {
- off = 6;
- for (i = off; i < len; i++)
- if (val[i] == ':') {
- i++;
- VCARD_TYPETOKEN(vcard->emails[vcard->num_emails].type);
- break;
- }
- VCARD_LASTTOKEN(vcard->emails[vcard->num_emails].address);
- }
- vcard->num_emails++;
- goto next;
- }
- next:
- val = strchr(val, '\n');
- if (!val)
- break;
- val++;
- if (!val || !(*val))
- break;
- }
- if (!has_begin || !has_end || !vcard->full_name) {
- silc_vcard_free(vcard);
- return FALSE;
- }
- return TRUE;
- }
- /* Allocate vcard context */
- SilcVCard silc_vcard_alloc(void)
- {
- SilcVCard vcard = silc_calloc(1, sizeof(*vcard));
- if (!vcard)
- return NULL;
- vcard->dynamic = TRUE;
- return vcard;
- }
- /* Free the vcard structure */
- void silc_vcard_free(SilcVCard vcard)
- {
- int i;
- silc_free(vcard->full_name);
- silc_free(vcard->family_name);
- silc_free(vcard->first_name);
- silc_free(vcard->middle_names);
- silc_free(vcard->prefix);
- silc_free(vcard->suffix);
- silc_free(vcard->nickname);
- silc_free(vcard->bday);
- silc_free(vcard->title);
- silc_free(vcard->role);
- silc_free(vcard->org_name);
- silc_free(vcard->org_unit);
- silc_free(vcard->categories);
- silc_free(vcard->catclass);
- silc_free(vcard->url);
- silc_free(vcard->label);
- for (i = 0; i < vcard->num_addrs; i++) {
- silc_free(vcard->addrs[i].type);
- silc_free(vcard->addrs[i].pbox);
- silc_free(vcard->addrs[i].ext_addr);
- silc_free(vcard->addrs[i].street_addr);
- silc_free(vcard->addrs[i].city);
- silc_free(vcard->addrs[i].state);
- silc_free(vcard->addrs[i].code);
- silc_free(vcard->addrs[i].country);
- }
- silc_free(vcard->addrs);
- for (i = 0; i < vcard->num_tels; i++) {
- silc_free(vcard->tels[i].type);
- silc_free(vcard->tels[i].telnum);
- }
- silc_free(vcard->tels);
- for (i = 0; i < vcard->num_emails; i++) {
- silc_free(vcard->emails[i].type);
- silc_free(vcard->emails[i].address);
- }
- silc_free(vcard->emails);
- silc_free(vcard->note);
- silc_free(vcard->rev);
- if (!vcard->dynamic)
- memset(vcard, 0, sizeof(*vcard));
- if (vcard->dynamic) {
- memset(vcard, 0, sizeof(*vcard));
- silc_free(vcard);
- }
- }
- /* Print card to file stream */
- void silc_vcard_fprintf(SilcVCard vcard, FILE *stream)
- {
- int i;
- fprintf(stream, "%s", VCARD_HEADER);
- fprintf(stream, "%s", VCARD_VERSION);
- if (vcard->full_name)
- fprintf(stream, "FN:%s\n", vcard->full_name);
- if (vcard->family_name)
- fprintf(stream, "N:%s;%s;%s;%s;%s\n",
- vcard->family_name,
- vcard->first_name ? vcard->first_name : "",
- vcard->middle_names ? vcard->middle_names : "",
- vcard->prefix ? vcard->prefix : "",
- vcard->suffix ? vcard->suffix : "");
- if (vcard->nickname)
- fprintf(stream, "NICKNAME:%s\n", vcard->nickname);
- if (vcard->bday)
- fprintf(stream, "BDAY:%s\n", vcard->bday);
- if (vcard->title)
- fprintf(stream, "TITLE:%s\n", vcard->title);
- if (vcard->role)
- fprintf(stream, "ROLE:%s\n", vcard->role);
- if (vcard->org_name)
- fprintf(stream, "ORG:%s;%s\n", vcard->org_name,
- vcard->org_unit ? vcard->org_unit : "");
- if (vcard->categories)
- fprintf(stream, "CATEGORIES:%s\n", vcard->categories);
- if (vcard->catclass)
- fprintf(stream, "CLASS:%s\n", vcard->catclass);
- if (vcard->url)
- fprintf(stream, "URL:%s\n", vcard->url);
- if (vcard->label)
- fprintf(stream, "LABEL;%s\n", vcard->label);
- for (i = 0; i < vcard->num_addrs; i++) {
- fprintf(stream, "ADR;TYPE=%s:%s;%s;%s;%s;%s;%s;%s\n",
- vcard->addrs[i].type,
- vcard->addrs[i].pbox ? vcard->addrs[i].pbox : "",
- vcard->addrs[i].ext_addr ? vcard->addrs[i].ext_addr : "",
- vcard->addrs[i].street_addr ? vcard->addrs[i].street_addr : "",
- vcard->addrs[i].city ? vcard->addrs[i].city : "",
- vcard->addrs[i].state ? vcard->addrs[i].state : "",
- vcard->addrs[i].code ? vcard->addrs[i].code : "",
- vcard->addrs[i].country ? vcard->addrs[i].country : "");
- }
- for (i = 0; i < vcard->num_tels; i++) {
- fprintf(stream, "TEL;TYPE=%s:%s\n",
- vcard->tels[i].type,
- vcard->tels[i].telnum ? vcard->tels[i].telnum : "");
- }
- for (i = 0; i < vcard->num_emails; i++) {
- fprintf(stream, "EMAIL;TYPE=%s:%s\n",
- vcard->emails[i].type,
- vcard->emails[i].address ? vcard->emails[i].address : "");
- }
- if (vcard->note)
- fprintf(stream, "NOTE:%s\n", vcard->note);
- if (vcard->rev)
- fprintf(stream, "REV:%s\n", vcard->rev);
- fprintf(stream, "%s", VCARD_FOOTER);
- fflush(stream);
- }