aboutsummaryrefslogtreecommitdiffstats
path: root/libcontacts_same_number.c
blob: 633fc7e68cabdecaff0ea50b55863fd26389b5fa (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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;
}