#include #include #include /* 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); }