From 510448fe2bde7592df8d1d83bfec9397eed1696c Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sat, 3 Apr 2021 23:51:29 +0200 Subject: Add libcontacts_same_number MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- Makefile | 1 + libcontacts.h | 1 + libcontacts_same_number.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+) create mode 100644 libcontacts_same_number.c diff --git a/Makefile b/Makefile index 8d845fe..4b61012 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ OBJ =\ libcontacts_organisation_destroy.o\ libcontacts_parse_contact.o\ libcontacts_pgpkey_destroy.o\ + libcontacts_same_number.o\ libcontacts_save_contact.o\ libcontacts_site_destroy.o diff --git a/libcontacts.h b/libcontacts.h index 77d07fe..4a2d782 100644 --- a/libcontacts.h +++ b/libcontacts.h @@ -295,6 +295,7 @@ int libcontacts_list_contacts(char ***, const struct passwd *); int libcontacts_load_contact(const char *, struct libcontacts_contact *, const struct passwd *); /* errno = 0 if malformatted */ int libcontacts_load_contacts(struct libcontacts_contact ***, const struct passwd *); int libcontacts_save_contact(struct libcontacts_contact *, const struct passwd *); +int libcontacts_same_number(const char *, const char *, const char *, const char *); 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 */ diff --git a/libcontacts_same_number.c b/libcontacts_same_number.c new file mode 100644 index 0000000..633fc7e --- /dev/null +++ b/libcontacts_same_number.c @@ -0,0 +1,123 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +static const char *digits[255] = { + ['#'] = "#", ['*'] = "*", ['+'] = "00", + ['0'] = "0", ['1'] = "1", ['2'] = "2", ['3'] = "3", ['4'] = "4", + ['5'] = "5", ['6'] = "6", ['7'] = "7", ['8'] = "8", ['9'] = "9", + ['A'] = "2", ['B'] = "2", ['C'] = "2", + ['D'] = "3", ['E'] = "3", ['F'] = "3", + ['G'] = "4", ['H'] = "4", ['I'] = "4", + ['J'] = "5", ['K'] = "5", ['L'] = "5", + ['M'] = "6", ['N'] = "6", ['O'] = "6", + ['P'] = "7", ['Q'] = "7", ['R'] = "7", ['S'] = "7", + ['T'] = "8", ['U'] = "8", ['V'] = "8", + ['W'] = "8", ['X'] = "9", ['Y'] = "9", ['Z'] = "9", + ['('] = "(", [')'] = ")" /* For skipping ranges, e.g. the 0 in +46(0)7… shall be skipped when +46 is included */ + /* Lower case letters are intentionally left out */ +}; + +static char * +canonicalise(const char *number, const char *country) +{ + size_t nlen = 0, clen = 0, skip; + const char *digit, *p; + char *ret, *r; + + for (p = number, skip = 0; *p; p++) { + digit = digits[*p & 255]; + if (digit) { + if (*digit == '(') + skip += 1; + else if (*digit == ')') + skip -= !!skip; + else + nlen += digit[1] ? 2 : 1; + } + } + + for (p = country, skip = 0; *p; p++) { + digit = digits[*p & 255]; + if (digit) { + if (*digit == '(') + skip += 1; + else if (*digit == ')') + skip -= !!skip; + else + clen += digit[1] ? 2 : 1; + } + } + + ret = malloc(nlen + clen + 3); + if (!ret) + return NULL; + + for (r = ret, p = number, skip = 0; *p; p++) { + digit = digits[*p & 255]; + if (digit) { + if (*digit == '(') { + skip += 1; + } else if (*digit == ')') { + skip -= !!skip; + } else if (!skip) { + *r++ = digit[0]; + if (digit[1]) + *r++ = digit[1]; + } + } + } + *r = '\0'; + + if (ret[0] != '0' || ret[1] == '0' || !*country) + return ret; + + memmove(&ret[clen], &ret[1], nlen); + + for (r = ret, p = country, skip = 0; *p; p++) { + digit = digits[*p & 255]; + if (digit) { + if (*digit == '(') { + skip += 1; + } else if (*digit == ')') { + skip -= !!skip; + } else if (!skip) { + *r++ = digit[0]; + if (digit[1]) + *r++ = digit[1]; + } + } + } + + if (ret[0] == '0' && ret[1] == '0') + return ret; + + memmove(&ret[2], ret, nlen + clen); + ret[0] = ret[1] = '0'; + return ret; +} + +int +libcontacts_same_number(const char *a, const char *a_country, const char *b, const char *b_country) +{ + char *a_full, *b_full; + int ret; + + if (!a || !*a || !b || !*b) { + errno = EINVAL; + return -1; + } + + a_full = canonicalise(a, a_country ? a_country : ""); + if (!a_full) + return -1; + b_full = canonicalise(b, b_country ? b_country : ""); + if (!b_full) { + free(a_full); + return -1; + } + ret = !strcmp(a_full, b_full); + free(a_full); + free(b_full); + return ret; +} -- cgit v1.2.3-70-g09d2