1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2012,2013 Intel Corporation
4  *
5  * This library is free software: you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation.
8  *
9  * This library is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
12  * for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this library. If not, see <http://www.gnu.org/licenses/>.
16  *
17  * Authors: Mathias Hasselmann <mathias@openismus.com>
18  */
19 
20 #include "evolution-data-server-config.h"
21 
22 #include "e-phone-number.h"
23 
24 #include <glib/gi18n-lib.h>
25 
26 #include "e-phone-number-private.h"
27 
G_DEFINE_BOXED_TYPE(EPhoneNumber,e_phone_number,e_phone_number_copy,e_phone_number_free)28 G_DEFINE_BOXED_TYPE (
29 	EPhoneNumber, e_phone_number,
30 	e_phone_number_copy, e_phone_number_free)
31 
32 G_DEFINE_QUARK (e-phone-number-error-quark, e_phone_number_error)
33 
34 static const gchar *
35 e_phone_number_error_to_string (EPhoneNumberError code)
36 {
37 	switch (code) {
38 	case E_PHONE_NUMBER_ERROR_NOT_IMPLEMENTED:
39 		return _("The library was built without phone number support.");
40 	case E_PHONE_NUMBER_ERROR_UNKNOWN:
41 		return _("The phone number parser reported a yet unknown error code.");
42 	case E_PHONE_NUMBER_ERROR_NOT_A_NUMBER:
43 		return _("Not a phone number");
44 	case E_PHONE_NUMBER_ERROR_INVALID_COUNTRY_CODE:
45 		return _("Invalid country calling code");
46 	case E_PHONE_NUMBER_ERROR_TOO_SHORT_AFTER_IDD:
47 		return _("Remaining text after the country calling code is too short for a phone number");
48 	case E_PHONE_NUMBER_ERROR_TOO_SHORT:
49 		return _("Text is too short for a phone number");
50 	case E_PHONE_NUMBER_ERROR_TOO_LONG:
51 		return _("Text is too long for a phone number");
52 	}
53 
54 	return _("Unknown error");
55 }
56 
57 void
_e_phone_number_set_error(GError ** error,EPhoneNumberError code)58 _e_phone_number_set_error (GError **error,
59                            EPhoneNumberError code)
60 {
61 	const gchar *message = e_phone_number_error_to_string (code);
62 	g_set_error_literal (error, E_PHONE_NUMBER_ERROR, code, message);
63 }
64 
65 /**
66  * e_phone_number_is_supported:
67  *
68  * Checks if phone number support is available. It is recommended to call this
69  * function before using any of the phone-utils functions to ensure that the
70  * required functionality is available, and to pick alternative mechanisms if
71  * needed.
72  *
73  * Returns: %TRUE if phone number support is available.
74  *
75  * Since: 3.8
76  **/
77 gboolean
e_phone_number_is_supported(void)78 e_phone_number_is_supported (void)
79 {
80 #ifdef ENABLE_PHONENUMBER
81 
82 	return TRUE;
83 
84 #else /* ENABLE_PHONENUMBER */
85 
86 	return FALSE;
87 
88 #endif /* ENABLE_PHONENUMBER */
89 }
90 
91 /**
92  * e_phone_number_get_country_code_for_region:
93  * @region_code: (nullable): a two-letter country code, a locale name, or
94  * %NULL
95  * @error: a #GError to set an error, if any
96  *
97  * Retrieves the preferred country calling code for @region_code,
98  * e.g. 358 for "fi" or 1 for "en_US@UTF-8".
99  *
100  * If %NULL is passed for @region_code the default region as returned by
101  * e_phone_number_get_default_region() is used.
102  *
103  * Returns: a valid country calling code, or zero if an unknown region
104  * code was passed.
105  *
106  * Since: 3.8
107  */
108 gint
e_phone_number_get_country_code_for_region(const gchar * region_code,GError ** error)109 e_phone_number_get_country_code_for_region (const gchar *region_code,
110                                             GError **error)
111 {
112 #ifdef ENABLE_PHONENUMBER
113 
114 	return _e_phone_number_cxx_get_country_code_for_region (region_code);
115 
116 #else /* ENABLE_PHONENUMBER */
117 
118 	_e_phone_number_set_error (error, E_PHONE_NUMBER_ERROR_NOT_IMPLEMENTED);
119 	return 0;
120 
121 #endif /* ENABLE_PHONENUMBER */
122 }
123 
124 /**
125  * e_phone_number_get_default_region:
126  * @error: a #GError to set an error, if any
127  *
128  * Retrieves the current two-letter country code that's used by default for
129  * parsing phone numbers in e_phone_number_from_string(). It can be useful
130  * to store this number before parsing a bigger number of phone numbers.
131  *
132  * The result of this functions depends on the current setup of the
133  * %LC_ADDRESS category: If that category provides a reasonable value
134  * for %_NL_ADDRESS_COUNTRY_AB2 this value is returned. Otherwise the
135  * locale name configured for %LC_ADDRESS is parsed.
136  *
137  * Returns: a newly allocated string containing the
138  * current locale's two-letter code for phone number parsing.
139  *
140  * Since: 3.8
141  */
142 gchar *
e_phone_number_get_default_region(GError ** error)143 e_phone_number_get_default_region (GError **error)
144 {
145 #ifdef ENABLE_PHONENUMBER
146 
147 	return _e_phone_number_cxx_get_default_region ();
148 
149 #else /* ENABLE_PHONENUMBER */
150 
151 	_e_phone_number_set_error (error, E_PHONE_NUMBER_ERROR_NOT_IMPLEMENTED);
152 	return NULL;
153 
154 #endif /* ENABLE_PHONENUMBER */
155 }
156 
157 /**
158  * e_phone_number_from_string:
159  * @phone_number: the phone number to parse
160  * @region_code: (nullable): a two-letter country code, or %NULL
161  * @error: a #GError to set an error, if any
162  *
163  * Parses the string passed in @phone_number. Note that no validation is
164  * performed whether the recognized phone number is valid for a particular
165  * region.
166  *
167  * The two-letter country code passed in @region_code only is used if the
168  * @phone_number is not written in international format. The application's
169  * default region as returned by e_phone_number_get_default_region() is used
170  * if @region_code is %NULL.
171  *
172  * If the number is guaranteed to start with a '+' followed by the country
173  * calling code, then "ZZ" can be passed for @region_code.
174  *
175  * Returns: (transfer full): a new EPhoneNumber instance on success,
176  * or %NULL on error. Call e_phone_number_free() to release this instance.
177  *
178  * Since: 3.8
179  **/
180 EPhoneNumber *
e_phone_number_from_string(const gchar * phone_number,const gchar * region_code,GError ** error)181 e_phone_number_from_string (const gchar *phone_number,
182                             const gchar *region_code,
183                             GError **error)
184 {
185 #ifdef ENABLE_PHONENUMBER
186 
187 	return _e_phone_number_cxx_from_string (phone_number, region_code, error);
188 
189 #else /* ENABLE_PHONENUMBER */
190 
191 	_e_phone_number_set_error (error, E_PHONE_NUMBER_ERROR_NOT_IMPLEMENTED);
192 	return NULL;
193 
194 #endif /* ENABLE_PHONENUMBER */
195 }
196 
197 /**
198  * e_phone_number_to_string:
199  * @phone_number: the phone number to format
200  * @format: the phone number format to apply
201  *
202  * Describes the @phone_number according to the rules applying to @format.
203  *
204  * Returns: (transfer full): A formatted string for @phone_number.
205  *
206  * Since: 3.8
207  **/
208 gchar *
e_phone_number_to_string(const EPhoneNumber * phone_number,EPhoneNumberFormat format)209 e_phone_number_to_string (const EPhoneNumber *phone_number,
210                           EPhoneNumberFormat format)
211 {
212 #ifdef ENABLE_PHONENUMBER
213 
214 	return _e_phone_number_cxx_to_string (phone_number, format);
215 
216 #else /* ENABLE_PHONENUMBER */
217 
218 	/* The EPhoneNumber instance must be invalid. We'd also bail out with
219 	 * a warning if phone numbers are supported. Any code triggering this
220 	 * is broken and should be fixed. */
221 	g_warning ("%s: The library was built without phone number support.", G_STRFUNC);
222 	return NULL;
223 
224 #endif /* ENABLE_PHONENUMBER */
225 }
226 
227 /**
228  * e_phone_number_get_country_code:
229  * @phone_number: the phone number to query
230  * @source: (nullable): an optional location for storing the phone number's origin, or %NULL
231  *
232  * Queries the @phone_number's country calling code and optionally stores the country
233  * calling code's origin in @source. For instance when parsing "+1-617-5423789" this
234  * function would return one and assing E_PHONE_NUMBER_COUNTRY_FROM_FQTN to @source.
235  *
236  * Returns: A valid country calling code, or zero if no code is known.
237  *
238  * Since: 3.8
239  **/
240 gint
e_phone_number_get_country_code(const EPhoneNumber * phone_number,EPhoneNumberCountrySource * source)241 e_phone_number_get_country_code (const EPhoneNumber *phone_number,
242                                  EPhoneNumberCountrySource *source)
243 {
244 #ifdef ENABLE_PHONENUMBER
245 
246 	return _e_phone_number_cxx_get_country_code (phone_number, source);
247 
248 #else /* ENABLE_PHONENUMBER */
249 
250 	/* The EPhoneNumber instance must be invalid. We'd also bail out with
251 	 * a warning if phone numbers are supported. Any code triggering this
252 	 * is broken and should be fixed. */
253 	g_warning ("%s: The library was built without phone number support.", G_STRFUNC);
254 	return 0;
255 
256 #endif /* ENABLE_PHONENUMBER */
257 }
258 
259 /**
260  * e_phone_number_get_national_number:
261  * @phone_number: the phone number to query
262  *
263  * Queries the national portion of @phone_number without any call-out
264  * prefixes. For instance when parsing "+1-617-5423789" this function would
265  * return the string "6175423789".
266  *
267  * Returns: (transfer full): The national portion of @phone_number.
268  *
269  * Since: 3.8
270  **/
271 gchar *
e_phone_number_get_national_number(const EPhoneNumber * phone_number)272 e_phone_number_get_national_number (const EPhoneNumber *phone_number)
273 {
274 #ifdef ENABLE_PHONENUMBER
275 
276 	return _e_phone_number_cxx_get_national_number (phone_number);
277 
278 #else /* ENABLE_PHONENUMBER */
279 
280 	/* The EPhoneNumber instance must be invalid. We'd also bail out with
281 	 * a warning if phone numbers are supported. Any code triggering this
282 	 * is broken and should be fixed. */
283 	g_warning ("%s: The library was built without phone number support.", G_STRFUNC);
284 	return NULL;
285 
286 #endif /* ENABLE_PHONENUMBER */
287 }
288 
289 /**
290  * e_phone_number_compare:
291  * @first_number: the first EPhoneNumber to compare
292  * @second_number: the second EPhoneNumber to compare
293  *
294  * Compares two phone numbers.
295  *
296  * Returns: The quality of matching for the two phone numbers.
297  *
298  * Since: 3.8
299  **/
300 EPhoneNumberMatch
e_phone_number_compare(const EPhoneNumber * first_number,const EPhoneNumber * second_number)301 e_phone_number_compare (const EPhoneNumber *first_number,
302                         const EPhoneNumber *second_number)
303 {
304 #ifdef ENABLE_PHONENUMBER
305 
306 	return _e_phone_number_cxx_compare (first_number, second_number);
307 
308 #else /* ENABLE_PHONENUMBER */
309 
310 	/* The EPhoneNumber instance must be invalid. We'd also bail out with
311 	 * a warning if phone numbers are supported. Any code triggering this
312 	 * is broken and should be fixed. */
313 	g_warning ("%s: The library was built without phone number support.", G_STRFUNC);
314 	return E_PHONE_NUMBER_MATCH_NONE;
315 
316 #endif /* ENABLE_PHONENUMBER */
317 }
318 
319 /**
320  * e_phone_number_compare_strings:
321  * @first_number: the first EPhoneNumber to compare
322  * @second_number: the second EPhoneNumber to compare
323  * @error: a #GError to set an error, if any
324  *
325  * Compares two phone numbers.
326  *
327  * Returns: The quality of matching for the two phone numbers.
328  *
329  * Since: 3.8
330  **/
331 EPhoneNumberMatch
e_phone_number_compare_strings(const gchar * first_number,const gchar * second_number,GError ** error)332 e_phone_number_compare_strings (const gchar *first_number,
333                                 const gchar *second_number,
334                                 GError **error)
335 {
336 	return e_phone_number_compare_strings_with_region (
337 		first_number, second_number, NULL, error);
338 }
339 
340 /**
341  * e_phone_number_compare_strings_with_region:
342  * @first_number: the first EPhoneNumber to compare
343  * @second_number: the second EPhoneNumber to compare
344  * @region_code: (nullable): a two-letter country code, or %NULL
345  * @error: a #GError to set an error, if any
346  *
347  * Compares two phone numbers within the context of @region_code.
348  *
349  * Returns: The quality of matching for the two phone numbers.
350  *
351  * Since: 3.8
352  **/
353 EPhoneNumberMatch
e_phone_number_compare_strings_with_region(const gchar * first_number,const gchar * second_number,const gchar * region_code,GError ** error)354 e_phone_number_compare_strings_with_region (const gchar *first_number,
355                                             const gchar *second_number,
356                                             const gchar *region_code,
357                                             GError **error)
358 {
359 #ifdef ENABLE_PHONENUMBER
360 
361 	return _e_phone_number_cxx_compare_strings (
362 		first_number, second_number, region_code, error);
363 
364 #else /* ENABLE_PHONENUMBER */
365 
366 	_e_phone_number_set_error (error, E_PHONE_NUMBER_ERROR_NOT_IMPLEMENTED);
367 	return E_PHONE_NUMBER_MATCH_NONE;
368 
369 #endif /* ENABLE_PHONENUMBER */
370 }
371 
372 /**
373  * e_phone_number_copy:
374  * @phone_number: the EPhoneNumber to copy
375  *
376  * Makes a copy of @phone_number.
377  *
378  * Returns: (transfer full): A newly allocated EPhoneNumber instance.
379  * Call e_phone_number_free() to release this instance.
380  *
381  * Since: 3.8
382  **/
383 EPhoneNumber *
e_phone_number_copy(const EPhoneNumber * phone_number)384 e_phone_number_copy (const EPhoneNumber *phone_number)
385 {
386 #ifdef ENABLE_PHONENUMBER
387 
388 	return _e_phone_number_cxx_copy (phone_number);
389 
390 #else /* ENABLE_PHONENUMBER */
391 
392 	/* Without phonenumber support there are no instances.
393 	 * Any non-NULL value is a programming error in this setup. */
394 	g_warn_if_fail (phone_number == NULL);
395 	return NULL;
396 
397 #endif /* ENABLE_PHONENUMBER */
398 }
399 
400 /**
401  * e_phone_number_free:
402  * @phone_number: the EPhoneNumber to free
403  *
404  * Released the memory occupied by @phone_number.
405  *
406  * Since: 3.8
407  **/
408 void
e_phone_number_free(EPhoneNumber * phone_number)409 e_phone_number_free (EPhoneNumber *phone_number)
410 {
411 #ifdef ENABLE_PHONENUMBER
412 
413 	_e_phone_number_cxx_free (phone_number);
414 
415 #else /* ENABLE_PHONENUMBER */
416 
417 	/* Without phonenumber support there are no instances.
418 	 * Any non-NULL value is a programming error in this setup. */
419 	g_warn_if_fail (phone_number == NULL);
420 
421 #endif /* ENABLE_PHONENUMBER */
422 }
423