diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | common.h | 3 | ||||
-rw-r--r-- | libcontacts.h | 42 | ||||
-rw-r--r-- | libcontacts_block_destroy.c | 10 | ||||
-rw-r--r-- | libcontacts_contact_destroy.c | 1 | ||||
-rw-r--r-- | libcontacts_format_contact.c | 26 | ||||
-rw-r--r-- | libcontacts_parse_contact.c | 43 |
7 files changed, 122 insertions, 4 deletions
@@ -7,6 +7,7 @@ include $(CONFIGFILE) OBJ =\ libcontacts_address_destroy.o\ libcontacts_birthday_destroy.o\ + libcontacts_block_destroy.o\ libcontacts_chat_destroy.o\ libcontacts_contact_destroy.o\ libcontacts_email_destroy.o\ @@ -12,6 +12,9 @@ #include <unistd.h> +#define TIME_MAX ((time_t)((1ULL << (8 * sizeof(time_t) - 1)) - 1ULL)) + + #define DESTROY_ALL(LIST, FUNC)\ do {\ void *destroy_all_temp__;\ diff --git a/libcontacts.h b/libcontacts.h index cd65bf4..4a7373f 100644 --- a/libcontacts.h +++ b/libcontacts.h @@ -17,6 +17,36 @@ enum libcontacts_gender { }; /** + * Block type for contact + */ +enum libcontacts_block_type { + LIBCONTACTS_SILENT, /* The contact is blocked blocked, the phone shall not call its owner's attention */ + LIBCONTACTS_BLOCK_OFF, /* The contact is blocked, phone shall appear as turned off */ + LIBCONTACTS_BLOCK_BUSY, /* The contact is blocked, phone shall appear as turned busy */ + LIBCONTACTS_BLOCK_IGNORE /* The contact is blocked, phone shall appear as on but with no one answering */ +}; + +/** + * Block for contact + */ +struct libcontacts_block { + /** + * The service the block is applied to, + * must be begin with a dot, except if + * it is: + * - ".call" Telephone calls + * - ".sms" SMS, MMS, and similar + * - ".global" Block everywhere (least priorities) + */ + char *service; + int explicit; /* Whether to make an explicit block if possible */ + enum libcontacts_block_type shadow_block; /* How block shall appear unless explicit */ + time_t soft_unblock; /* When (positive) to ask whether to unblock, 0 if never */ + time_t hard_unblock; /* When (positive) to unblock, 0 if never */ + char **unrecognised_data; /* Data not recognised by the library */ +}; + +/** * Organisation information for contact */ struct libcontacts_organisation { @@ -84,7 +114,7 @@ struct libcontacts_site { */ struct libcontacts_chat { char *context; /* Work account (which job?)? Personal account? … */ - char *service; /* What service is the account */ + char *service; /* What service is the account, must not begin with a dot */ char *address; /* What is the name/address/number of the account */ char **unrecognised_data; /* Data not recognised by the library */ }; @@ -107,8 +137,8 @@ struct libcontacts_contact { * The ID of the contact, used to select filename * * Must not begin with a dot, except if it is: - * ".me" - The user himself. - * ".nobody" - Unused data, such as created groups without any members. + * - ".me" The user himself. + * - ".nobody" Unused data, such as created groups without any members. * Additionally, it must not end with ~ or contain an /, * and it should be short enough for a filename */ @@ -161,6 +191,11 @@ struct libcontacts_contact { char *notes; /** + * Block information for contact + */ + struct libcontacts_block **blocks; + + /** * Organisation information for contact */ struct libcontacts_organisation **organisations; @@ -234,6 +269,7 @@ char *libcontacts_get_path(const char *, const struct passwd *); int libcontacts_parse_contact(char *, struct libcontacts_contact *); /* does not load .id, not stored in file, but is the filename */ int libcontacts_format_contact(const struct libcontacts_contact *, char **); +void libcontacts_block_destroy(struct libcontacts_block *); void libcontacts_organisation_destroy(struct libcontacts_organisation *); void libcontacts_email_destroy(struct libcontacts_email *); void libcontacts_pgpkey_destroy(struct libcontacts_pgpkey *); diff --git a/libcontacts_block_destroy.c b/libcontacts_block_destroy.c new file mode 100644 index 0000000..1298aca --- /dev/null +++ b/libcontacts_block_destroy.c @@ -0,0 +1,10 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +void +libcontacts_block_destroy(struct libcontacts_block *this) +{ + free(this->service); + DESTROY_ALL(this->unrecognised_data, free); +} diff --git a/libcontacts_contact_destroy.c b/libcontacts_contact_destroy.c index ef208d5..974473d 100644 --- a/libcontacts_contact_destroy.c +++ b/libcontacts_contact_destroy.c @@ -13,6 +13,7 @@ libcontacts_contact_destroy(struct libcontacts_contact *this) DESTROY_ALL(this->photos, free); DESTROY_ALL(this->groups, free); free(this->notes); + DESTROY_ALL(this->blocks, libcontacts_block_destroy); DESTROY_ALL(this->organisations, libcontacts_organisation_destroy); DESTROY_ALL(this->emails, libcontacts_email_destroy); DESTROY_ALL(this->pgpkeys, libcontacts_pgpkey_destroy); diff --git a/libcontacts_format_contact.c b/libcontacts_format_contact.c index 1752026..8be830e 100644 --- a/libcontacts_format_contact.c +++ b/libcontacts_format_contact.c @@ -9,6 +9,7 @@ libcontacts_format_contact(const struct libcontacts_contact *contact, char **dat size_t siz = 0; char **list, *p, *q; const char *suffix; + struct libcontacts_block **blocks, *block; struct libcontacts_organisation **organisations, *organisation; struct libcontacts_email **emails, *email; struct libcontacts_pgpkey **pgpkeys, *pgpkey; @@ -51,11 +52,34 @@ libcontacts_format_contact(const struct libcontacts_contact *contact, char **dat } } + if ((blocks = contact->blocks)) { + for (; (block = *blocks); blocks++) { + fprintf(fp, "BLOCK:\n"); + if (block->service) + fprintf(fp, "\tSRV %s\n", block->service); + if (block->explicit) + fprintf(fp, "\tEXPLICIT\n"); + if (block->soft_unblock > 0) + fprintf(fp, "\tASK %ji\n", block->soft_unblock); + if (block->hard_unblock > 0) + fprintf(fp, "\tREMOVE %ji\n", block->hard_unblock); + if (block->shadow_block == LIBCONTACTS_BLOCK_OFF) + fprintf(fp, "\tOFF\n"); + else if (block->shadow_block == LIBCONTACTS_BLOCK_BUSY) + fprintf(fp, "\tBUSY\n"); + else if (block->shadow_block == LIBCONTACTS_BLOCK_IGNORE) + fprintf(fp, "\tIGNORE\n"); + if ((list = block->unrecognised_data)) + for (; *list; list++) + fprintf(fp, "\t%s\n", *list); + } + } + if ((organisations = contact->organisations)) { for (; (organisation = *organisations); organisations++) { fprintf(fp, "ORG:\n"); if (organisation->organisation) - fprintf(fp, "\tORG %s\n", *organisation->organisation); + fprintf(fp, "\tORG %s\n", organisation->organisation); if (organisation->title) fprintf(fp, "\tTITLE %s\n", organisation->title); if ((list = organisation->unrecognised_data)) diff --git a/libcontacts_parse_contact.c b/libcontacts_parse_contact.c index da39432..a81a744 100644 --- a/libcontacts_parse_contact.c +++ b/libcontacts_parse_contact.c @@ -2,6 +2,22 @@ #include "common.h" +static time_t +gettime(const char *data) +{ + time_t ret = 0; + if (*data > '1' || '9' > *data) + return 0; + for (; isdigit(*data); data++) { + if (ret > (TIME_MAX - (*data & 15)) / 10) + return 0; + ret = ret * 10 + (*data & 15); + } + if (*data) + return 0; + return ret; +} + static char * getstr(char *data) { @@ -169,6 +185,7 @@ libcontacts_parse_contact(char *data, struct libcontacts_contact *contact) char *p, *q; size_t i; + time_t t; void *temp; int state = 0; @@ -358,6 +375,32 @@ libcontacts_parse_contact(char *data, struct libcontacts_contact *contact) } break; + } else if (!strcmp(p, "BLOCK:")) { + ADD(contact->blocks); + state = 8; + break; + case 8: + if (TEST(unindent(p), "SRV") && !contact->blocks[i]->service) { + if (!(contact->blocks[i]->service = strdup(getstr(p)))) + goto fail; + } else if (!strcmp(p, "OFF") && !contact->blocks[i]->shadow_block) { + contact->blocks[i]->shadow_block = LIBCONTACTS_BLOCK_OFF; + } else if (!strcmp(p, "BUSY") && !contact->blocks[i]->shadow_block) { + contact->blocks[i]->shadow_block = LIBCONTACTS_BLOCK_BUSY; + } else if (!strcmp(p, "IGNORE") && !contact->blocks[i]->shadow_block) { + contact->blocks[i]->shadow_block = LIBCONTACTS_BLOCK_IGNORE; + } else if (!strcmp(p, "EXPLICIT")) { + contact->blocks[i]->explicit = 1; + } else if (TEST(unindent(p), "ASK") && !contact->blocks[i]->soft_unblock && (t = gettime(p))) { + contact->blocks[i]->soft_unblock = t; + } else if (TEST(unindent(p), "REMOVE") && !contact->blocks[i]->hard_unblock && (t = gettime(p))) { + contact->blocks[i]->hard_unblock = t; + } else { + if (addstr(&contact->organisations[i]->unrecognised_data, getstr(p))) + goto fail; + } + break; + } else if (TEST(p, "BIRTH") && !contact->birthday) { contact->birthday = malloc(sizeof(*contact->birthday)); if (!contact->birthday) |