This commit is contained in:
Matteo Bini 2024-03-19 15:51:31 +01:00
commit 3ccf5d377d
3 changed files with 635 additions and 0 deletions

50
Makefile Normal file
View File

@ -0,0 +1,50 @@
BIN = vcf2cnt
VERSION = 1.0
PREFIX = /usr/local
INCS =
LIBS =
CPPFLAGS_VCF2CNT = -DVERSION=\"${VERSION}\" ${CPPFLAGS}
# debug
#CFLAGS_VCF2CNT = -ggdb -ansi -pedantic ${INCS} ${CPPFLAGS_VCF2CNT} ${CLAGS}
CFLAGS_VCF2CNT = -Os -ansi -pedantic ${INCS} ${CPPFLAGS_VCF2CNT} ${CFLAGS}
LDFLAGS_VCF2CNT = ${LIBS} ${LDFLAGS}
SRC = vcf2cnt.c
OBJ = ${SRC:.c=.o}
all: options vcf2cnt
options:
@echo vcf2cnt build options:
@echo "CFLAGS = ${CFLAGS_VCF2CNT}"
@echo "LDFLAGS = ${LDFLAGS_VCF2CNT}"
@echo "CC = ${CC}"
.c.o:
${CC} ${CFLAGS_VCF2CNT} -c $< -o $@
${BIN}: ${OBJ}
${CC} -o ${BIN} ${OBJ} ${LDFLAGS_VCF2CNT}
clean:
rm -f ${BIN} ${BIN}-${VERSION}.tar.gz *.o
dist: clean
mkdir ${BIN}-${VERSION}
cp -R ${SRC} LICENSE Makefile README ${BIN}-${VERSION}
tar -cf ${BIN}-${VERSION}.tar ${BIN}-${VERSION}
gzip ${BIN}-${VERSION}.tar
rm -fr ${BIN}-${VERSION}
install: ${BIN}
mkdir -p ${DESTDIR}${PREFIX}/bin
cp -f ${BIN} ${DESTDIR}${PREFIX}/bin
chmod 755 ${DESTDIR}${PREFIX}/bin/${BIN}
uninstall:
rm -f ${DESTDIR}${PREFIX}/bin/${BIN}
.PHONY: all options clean dist install uninstall

40
cnt2vcf Executable file
View File

@ -0,0 +1,40 @@
#!/bin/sh
set -e
read -p 'Nome: ' name
read -p 'Cognome: ' surname
read -p 'Cellulare: ' cellphone
read -p 'Indirizzo: ' address
read -p 'Email: ' email
read -p 'Telefono: ' phone
read -p 'XMPP: ' xmpp
read -p 'Note: ' note
printf 'BEGIN:VCARD\r\n'
printf 'VERSION:4.0\r\n'
printf 'N:%s;%s;;;\r\n' "$surname" "$name"
printf 'FN:%s %s\r\n' "$name" "$surname"
if [ -n "$cellphone" ]; then
printf 'TEL;TYPE=CELL:%s\r\n' "$cellphone"
fi
if [ -n "$email" ]; then
printf 'EMAIL;TYPE=HOME:%s\r\n' "$email"
fi
if [ -n "$phone" ]; then
printf 'TEL;TYPE=HOME:%s\r\n' "$phone"
fi
if [ -n "$xmpp" ]; then
printf 'IMPP;TYPE=HOME:xmpp:%s\r\n' "$xmpp"
fi
if [ -n "$note" ]; then
printf 'NOTE:%s\r\n' "$(echo "$note" | sed 's/\\/\\\\/g;s/,/\\,/g')"
fi
printf 'END:VCARD\r\n'

545
vcf2cnt.c Normal file
View File

@ -0,0 +1,545 @@
#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, &parameter, 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);
}