546 lines
12 KiB
C
546 lines
12 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
/* macros */
|
|
#define FBUF_SIZE 4096
|
|
|
|
typedef struct {
|
|
char *address;
|
|
char *birth_date;
|
|
char *cellphone;
|
|
char *email;
|
|
char *name;
|
|
char *note;
|
|
char *organization;
|
|
char *phone;
|
|
char *surname;
|
|
char *website;
|
|
char *work_address;
|
|
char *work_cellphone;
|
|
char *work_email;
|
|
char *work_phone;
|
|
char *work_xmpp;
|
|
char *xmpp;
|
|
} Contatto;
|
|
|
|
/* function declarations */
|
|
static int convert_vcard(char **contact);
|
|
static int convert_vcard_line(Contatto *contatto, const char *line);
|
|
static void convert_vcard_property_adr(Contatto *contatto, const char *value, const char *parameter);
|
|
static void convert_vcard_property_email(Contatto *contatto, const char *value, const char *parameter);
|
|
static void convert_vcard_property_n(Contatto *contatto, const char *value);
|
|
static void convert_vcard_property_note(Contatto *contatto, const char *value);
|
|
static void convert_vcard_property_org(Contatto *contatto, const char *value);
|
|
static void convert_vcard_property_tel(Contatto *contatto, const char *value, const char *parameter);
|
|
static Contatto *create_contatto(void);
|
|
static void free_contact(char ***contact);
|
|
static void free_contatto(Contatto *contatto);
|
|
static void *safe_malloc(const size_t size);
|
|
static void strcut_d(char **ds1, char **ds2, const char *src, const char s);
|
|
static void strexp_d(char ***dst, const char *src, const char s);
|
|
static void strncat_d(char **dst, const char *src, const size_t sz);
|
|
static void strrmchar_d(char **src, const char r);
|
|
|
|
/* function implementations */
|
|
int
|
|
convert_vcard(char **contact)
|
|
{
|
|
Contatto *contatto;
|
|
|
|
contatto = create_contatto();
|
|
|
|
while (*contact != NULL) {
|
|
convert_vcard_line(contatto, *contact);
|
|
(contact)++;
|
|
}
|
|
|
|
printf("------------------------------------------------------------------------\n");
|
|
if (contatto->cellphone != NULL)
|
|
printf("Cellulare: %s\n", contatto->cellphone);
|
|
if (contatto->work_cellphone != NULL)
|
|
printf("Cellulare di lavoro: %s\n", contatto->work_cellphone);
|
|
if (contatto->surname != NULL)
|
|
printf("Cognome: %s\n", contatto->surname);
|
|
if (contatto->email != NULL)
|
|
printf("Email: %s\n", contatto->email);
|
|
if (contatto->work_email != NULL)
|
|
printf("Email di lavoro: %s\n", contatto->work_email);
|
|
if (contatto->address != NULL)
|
|
printf("Indirizzo: %s\n", contatto->address);
|
|
if (contatto->work_address != NULL)
|
|
printf("Indirizzo di lavoro: %s\n", contatto->work_address);
|
|
if (contatto->name != NULL)
|
|
printf("Nome: %s\n", contatto->name);
|
|
if (contatto->note != NULL)
|
|
printf("Note: %s\n", contatto->note);
|
|
if (contatto->organization != NULL)
|
|
printf("Organizzazione: %s\n", contatto->organization);
|
|
if (contatto->phone != NULL)
|
|
printf("Telefono: %s\n", contatto->phone);
|
|
if (contatto->work_phone != NULL)
|
|
printf("Telefono di lavoro: %s\n", contatto->work_phone);
|
|
|
|
free_contatto(contatto);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
convert_vcard_line(Contatto *contatto, const char *line)
|
|
{
|
|
char *property, *parameter, *value, *tmp;
|
|
|
|
strcut_d(&property, &value, line, ':');
|
|
tmp = safe_malloc(sizeof(char) * (strlen(property) + 1));
|
|
strcpy(tmp, property);
|
|
strcut_d(&property, ¶meter, tmp, ';');
|
|
free(tmp);
|
|
|
|
|
|
if (!strcmp(property, "BEGIN")) {
|
|
if (strcmp(value, "VCARD") != 0) {
|
|
fprintf(stderr, "Unexpected value \"%s\" for BEGIN property.\n", value);
|
|
}
|
|
|
|
} else if (!strcmp(property, "VERSION")) {
|
|
/* to do: handle different versions than 4.0 */
|
|
|
|
} else if (!strcmp(property, "FN")) {
|
|
/* ignore FN property, we don't need it */
|
|
|
|
} else if (!strcmp(property, "N")) {
|
|
convert_vcard_property_n(contatto, value);
|
|
|
|
} else if (!strcmp(property, "ADR")) {
|
|
strrmchar_d(&value, '\\');
|
|
convert_vcard_property_adr(contatto, value, parameter);
|
|
|
|
} else if (!strcmp(property, "TEL")) {
|
|
convert_vcard_property_tel(contatto, value, parameter);
|
|
|
|
} else if (!strcmp(property, "EMAIL")) {
|
|
convert_vcard_property_email(contatto, value, parameter);
|
|
|
|
} else if (!strcmp(property, "ORG")) {
|
|
strrmchar_d(&value, '\\');
|
|
convert_vcard_property_org(contatto, value);
|
|
|
|
} else if (!strcmp(property, "NOTE")) {
|
|
strrmchar_d(&value, '\\');
|
|
convert_vcard_property_note(contatto, value);
|
|
|
|
} else if (!strcmp(property, "END")) {
|
|
if (strcmp(value, "VCARD") != 0) {
|
|
fprintf(stderr, "Unexpected value \"%s\" for END property.\n", value);
|
|
}
|
|
|
|
} else {
|
|
fprintf(stderr, "Unknown property %s.\n", property);
|
|
}
|
|
|
|
free(property);
|
|
free(parameter);
|
|
free(value);
|
|
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
convert_vcard_property_adr(Contatto *contatto, const char *value, const char *parameter)
|
|
{
|
|
char **dst, **tmp;
|
|
unsigned int i, to_trim;
|
|
size_t len;
|
|
|
|
tmp = NULL;
|
|
to_trim = 0;
|
|
|
|
dst = strstr(parameter, "WORK") != NULL ? &contatto->work_address : &contatto->address;
|
|
strexp_d(&tmp, value, ';');
|
|
|
|
if (*dst != NULL)
|
|
free(*dst);
|
|
*dst = safe_malloc(sizeof(char) * (strlen(value) + 1));
|
|
strcpy(*dst, "");
|
|
for (i = 0; i < 6; i++) {
|
|
if (strcmp(tmp[i], "") != 0) {
|
|
strcat(*dst, tmp[i]);
|
|
strcat(*dst, ", ");
|
|
to_trim = 1;
|
|
}
|
|
}
|
|
if (to_trim) {
|
|
len = strlen(*dst);
|
|
(*dst)[len - 1] = '\0';
|
|
(*dst)[len - 2] = '\0';
|
|
}
|
|
}
|
|
|
|
void
|
|
convert_vcard_property_email(Contatto *contatto, const char *value, const char *parameter)
|
|
{
|
|
char **dst;
|
|
|
|
dst = strstr(parameter, "WORK") != NULL ? &contatto->work_email : &contatto->email;
|
|
|
|
if (*dst != NULL)
|
|
free(*dst);
|
|
*dst = safe_malloc(sizeof(char) * (strlen(value) + 1));
|
|
strcpy(*dst, value);
|
|
}
|
|
|
|
void
|
|
convert_vcard_property_n(Contatto *contatto, const char *value)
|
|
{
|
|
char *tmp1, *tmp2;
|
|
|
|
strcut_d(&contatto->surname, &tmp1, value, ';');
|
|
strcut_d(&contatto->name, &tmp2, tmp1, ';');
|
|
|
|
free(tmp1);
|
|
free(tmp2);
|
|
}
|
|
|
|
void
|
|
convert_vcard_property_note(Contatto *contatto, const char *value)
|
|
{
|
|
if (contatto->note != NULL)
|
|
free(contatto->note);
|
|
contatto->note = safe_malloc(sizeof(char) * (strlen(value) + 1));
|
|
strcpy(contatto->note, value);
|
|
}
|
|
|
|
void
|
|
convert_vcard_property_org(Contatto *contatto, const char *value)
|
|
{
|
|
if (contatto->organization != NULL)
|
|
free(contatto->organization);
|
|
contatto->organization = safe_malloc(sizeof(char) * (strlen(value) + 1));
|
|
strcpy(contatto->organization, value);
|
|
|
|
/* to do: separate value components */
|
|
}
|
|
|
|
void
|
|
convert_vcard_property_tel(Contatto *contatto, const char *value, const char *parameter)
|
|
{
|
|
char **dst;
|
|
|
|
if (strstr(parameter, "CELL") != NULL)
|
|
dst = strstr(parameter, "WORK") != NULL ? &contatto->work_cellphone : &contatto->cellphone;
|
|
else
|
|
dst = strstr(parameter, "WORK") != NULL ? &contatto->work_phone : &contatto->phone;
|
|
|
|
if (*dst != NULL)
|
|
free(*dst);
|
|
*dst = safe_malloc(sizeof(char) * (strlen(value) + 1));
|
|
strcpy(*dst, value);
|
|
}
|
|
|
|
Contatto *
|
|
create_contatto(void)
|
|
{
|
|
Contatto *contatto;
|
|
|
|
contatto = safe_malloc(sizeof(Contatto));
|
|
contatto->address = NULL;
|
|
contatto->birth_date = NULL;
|
|
contatto->cellphone = NULL;
|
|
contatto->email = NULL;
|
|
contatto->name = NULL;
|
|
contatto->note = NULL;
|
|
contatto->organization = NULL;
|
|
contatto->phone = NULL;
|
|
contatto->surname = NULL;
|
|
contatto->website = NULL;
|
|
contatto->work_address = NULL;
|
|
contatto->work_cellphone = NULL;
|
|
contatto->work_email = NULL;
|
|
contatto->work_phone = NULL;
|
|
contatto->work_xmpp = NULL;
|
|
contatto->xmpp = NULL;
|
|
|
|
return contatto;
|
|
}
|
|
|
|
void
|
|
free_contact(char ***contact)
|
|
{
|
|
unsigned int i = 0;
|
|
|
|
if (*contact != NULL) {
|
|
while (**contact != NULL) {
|
|
free(**contact);
|
|
**contact = NULL;
|
|
(*contact)++;
|
|
i++;
|
|
}
|
|
free(*contact - i);
|
|
}
|
|
}
|
|
|
|
void
|
|
free_contatto(Contatto *contatto)
|
|
{
|
|
|
|
if (contatto->address != NULL)
|
|
free(contatto->address);
|
|
|
|
if (contatto->birth_date != NULL)
|
|
free(contatto->birth_date);
|
|
|
|
if (contatto->cellphone != NULL)
|
|
free(contatto->cellphone);
|
|
|
|
if (contatto->email != NULL)
|
|
free(contatto->email);
|
|
|
|
if (contatto->name != NULL)
|
|
free(contatto->name);
|
|
|
|
if (contatto->note != NULL)
|
|
free(contatto->note);
|
|
|
|
if (contatto->organization != NULL)
|
|
free(contatto->organization);
|
|
|
|
if (contatto->phone != NULL)
|
|
free(contatto->phone);
|
|
|
|
if (contatto->surname != NULL)
|
|
free(contatto->surname);
|
|
|
|
if (contatto->website != NULL)
|
|
free(contatto->website);
|
|
|
|
if (contatto->work_address != NULL)
|
|
free(contatto->work_address);
|
|
|
|
if (contatto->work_cellphone != NULL)
|
|
free(contatto->work_cellphone);
|
|
|
|
if (contatto->work_email != NULL)
|
|
free(contatto->work_email);
|
|
|
|
if (contatto->work_phone != NULL)
|
|
free(contatto->work_phone);
|
|
|
|
if (contatto->work_xmpp != NULL)
|
|
free(contatto->work_xmpp);
|
|
|
|
if (contatto->xmpp != NULL)
|
|
free(contatto->xmpp);
|
|
|
|
free(contatto);
|
|
}
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
FILE *file;
|
|
char buf[FBUF_SIZE];
|
|
int alloc, c, found, l, n, read, x;
|
|
char **contact, **tmp_contact;
|
|
char *line, *part_line;
|
|
|
|
l = 0;
|
|
contact = NULL;
|
|
tmp_contact = NULL;
|
|
line = "";
|
|
part_line = "";
|
|
|
|
file = fopen(argv[1], "r");
|
|
|
|
if (file == NULL) {
|
|
fprintf(stderr, "Can't open %s.\n", argv[1]);
|
|
return 1;
|
|
}
|
|
|
|
if (fseek(file, 0, SEEK_SET) == -1) {
|
|
fprintf(stderr, "Can't go to the start of %s.\n", argv[1]);
|
|
return 1;
|
|
}
|
|
|
|
do {
|
|
read = fread(buf, 1, FBUF_SIZE, file);
|
|
for (c = 0; c < FBUF_SIZE && c < read; c++) {
|
|
found = 0;
|
|
for (n = c + 1; n < FBUF_SIZE && n < read; n++) {
|
|
if (n - 1 >= c && buf[n-1] == '\r' && buf[n] == '\n') {
|
|
found = 1;
|
|
line = safe_malloc(sizeof(char) * (n - c + strlen(part_line)));
|
|
strcpy(line, part_line);
|
|
if (strcmp(part_line, "") != 0)
|
|
free(part_line);
|
|
part_line = "";
|
|
strncat(line, buf + c, n - c - 1);
|
|
if (!strncmp(line, "BEGIN:VCARD", 11)) {
|
|
free_contact(&contact);
|
|
l = 0;
|
|
} else if (l != 0 && l == alloc) {
|
|
tmp_contact = safe_malloc(sizeof(char *) * (alloc * 2 + 1));
|
|
for (x = alloc; x <= alloc * 2; x++)
|
|
contact[x] = NULL;
|
|
memcpy(tmp_contact, contact, sizeof(char *) * alloc);
|
|
free_contact(&contact);
|
|
contact = tmp_contact;
|
|
alloc = alloc * 2;
|
|
}
|
|
if (l == 0) {
|
|
alloc = 24;
|
|
/* contact size is alloc + 1, so the last pointer is NULL */
|
|
contact = safe_malloc(sizeof(char *) * (alloc + 1));
|
|
for (x = 0; x <= alloc; x++)
|
|
contact[x] = NULL;
|
|
}
|
|
contact[l] = safe_malloc(sizeof(char) * (strlen(line) + 1));
|
|
strcpy(contact[l], line);
|
|
if (!strncmp(line, "END:VCARD", 9)) {
|
|
convert_vcard(contact);
|
|
}
|
|
free(line);
|
|
l++;
|
|
c = n;
|
|
break;
|
|
}
|
|
}
|
|
if (!found && n == FBUF_SIZE) {
|
|
strncat_d(&part_line, buf + c, n - c);
|
|
break;
|
|
}
|
|
if (!found)
|
|
break;
|
|
}
|
|
} while (!feof(file));
|
|
|
|
free_contact(&contact);
|
|
|
|
fclose(file);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void *
|
|
safe_malloc(const size_t size)
|
|
{
|
|
void *p;
|
|
|
|
p = malloc(size);
|
|
if (p == NULL) {
|
|
fprintf(stderr, "Fatal: can't allocate %lu bytes.\n", size);
|
|
exit(1);
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
void
|
|
strcut_d(char **ds1, char **ds2, const char *src, const char s)
|
|
{
|
|
char *part;
|
|
size_t ds1len, ds2len;
|
|
|
|
part = strchr(src, s);
|
|
if (part == NULL) {
|
|
*ds1 = safe_malloc(sizeof(char) * (strlen(src) + 1));
|
|
strcpy(*ds1, src);
|
|
|
|
*ds2 = safe_malloc(sizeof(char) * 2);
|
|
strcpy(*ds2, "");
|
|
} else {
|
|
ds2len = strlen(part) - 1;
|
|
*ds2 = safe_malloc(sizeof(char) * (ds2len + 1));
|
|
strcpy(*ds2, part + 1);
|
|
|
|
ds1len = strlen(src) - (ds2len + 1);
|
|
*ds1 = safe_malloc(sizeof(char) * (ds1len + 1));
|
|
strncpy(*ds1, src, ds1len);
|
|
(*ds1)[ds1len] = '\0';
|
|
}
|
|
}
|
|
|
|
void
|
|
strexp_d(char ***dst, const char *src, const char s)
|
|
{
|
|
size_t len, i;
|
|
char **tmp_dst;
|
|
char *tmp_str;
|
|
|
|
len = 0;
|
|
i = 0;
|
|
|
|
if (*dst == NULL) {
|
|
len = 3;
|
|
*dst = safe_malloc(sizeof(char *) * len);
|
|
} else {
|
|
while(**dst != NULL) {
|
|
len++;
|
|
(*dst)++;
|
|
}
|
|
*dst -= len;
|
|
i = len;
|
|
len += 3;
|
|
tmp_dst = safe_malloc(sizeof(char *) * len);
|
|
memcpy(tmp_dst, *dst, sizeof(char *) * (len - 3));
|
|
free(*dst);
|
|
*dst = tmp_dst;
|
|
|
|
}
|
|
for (i = i; i < len; i++) {
|
|
(*dst)[i] = NULL;
|
|
}
|
|
|
|
strcut_d(&(*dst)[len - 3], &(*dst)[len - 2], src, s);
|
|
|
|
if (strchr((*dst)[len - 2], s) != NULL) {
|
|
tmp_str = safe_malloc(sizeof(char) * strlen((*dst)[len - 2]));
|
|
strcpy(tmp_str, (*dst)[len - 2]);
|
|
free((*dst)[len - 2]);
|
|
(*dst)[len - 2] = NULL;
|
|
strexp_d(&(*dst), tmp_str, s);
|
|
free(tmp_str);
|
|
}
|
|
}
|
|
|
|
void
|
|
strncat_d(char **dst, const char *src, const size_t sz)
|
|
{
|
|
char *tmp;
|
|
|
|
if (*dst == NULL)
|
|
*dst = "";
|
|
|
|
tmp = safe_malloc(sizeof(char) * (sz + strlen(*dst) + 1));
|
|
|
|
strcpy(tmp, *dst);
|
|
if (strcmp(*dst, "") != 0)
|
|
free(*dst);
|
|
strncat(tmp, src, sz);
|
|
*dst = tmp;
|
|
}
|
|
|
|
void
|
|
strrmchar_d(char **str, const char r)
|
|
{
|
|
char *tmp;
|
|
size_t len, i, c;
|
|
|
|
len = strlen(*str);
|
|
tmp = safe_malloc(sizeof(char) * (len + 1));
|
|
c = 0;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
if ((*str)[i] == r)
|
|
continue;
|
|
tmp[c] = (*str)[i];
|
|
c++;
|
|
}
|
|
tmp[c] = '\0';
|
|
|
|
free(*str);
|
|
*str = safe_malloc(sizeof(char) * c);
|
|
strcpy(*str, tmp);
|
|
free(tmp);
|
|
}
|