2 * Copyright (C) 2011 Collabora Ltd.
3 * Copyright (C) 2011 Philip Withnall
5 * This library is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 2.1 of the License, or
8 * (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this library. If not, see <http://www.gnu.org/licenses/>.
19 * Marco Barisione <marco.barisione@collabora.co.uk>
20 * Raul Gutierrez Segales <raul.gutierrez.segales@collabora.co.uk>
21 * Philip Withnall <philip@tecnocode.co.uk>
28 * Object representing a phone number that can have some parameters associated
31 * See {@link Folks.AbstractFieldDetails} for details on common parameter names
36 public class Folks.PhoneFieldDetails : AbstractFieldDetails<string>
38 private const string[] _extension_chars = { "p", "P", "w", "W", "x", "X" };
39 private const string[] _common_delimiters = { ",", ".", "(", ")", "-", " ",
41 private const string[] _valid_digits = { "#", "*", "0", "1", "2", "3", "4",
42 "5", "6", "7", "8", "9" };
48 public override string id
50 get { return this._id; }
51 set { this._id = (value != null ? value : ""); }
55 * Create a new PhoneFieldDetails.
57 * @param value the value of the field, which should be a non-empty phone
58 * number (no particular format is mandated)
59 * @param parameters initial parameters. See
60 * {@link AbstractFieldDetails.parameters}. A `null` value is equivalent to a
61 * empty map of parameters.
63 * @return a new PhoneFieldDetails
67 public PhoneFieldDetails (string value,
68 MultiMap<string, string>? parameters = null)
72 warning ("Empty phone number passed to PhoneFieldDetails.");
76 parameters: parameters);
84 public override bool equal (AbstractFieldDetails<string> that)
86 return base.equal (that);
92 public override bool values_equal (AbstractFieldDetails<string> that)
94 var _that_fd = that as PhoneFieldDetails;
97 PhoneFieldDetails that_fd = (!) _that_fd;
99 var n1 = this._drop_extension (this.get_normalised ());
100 var n2 = this._drop_extension (that_fd.get_normalised ());
102 /* Based on http://blog.barisione.org/2010-06/handling-phone-numbers/ */
103 if (n1.length >= 7 && n2.length >= 7)
105 var n1_reduced = n1.slice (-7, n1.length);
106 var n2_reduced = n2.slice (-7, n2.length);
108 debug ("[PhoneDetails.equal] Comparing %s with %s",
109 n1_reduced, n2_reduced);
111 return n1_reduced == n2_reduced;
122 public override uint hash ()
128 * Return this object's normalised phone number.
130 * Typical normalisations:
132 * - `1-800-123-4567` → `18001234567`
133 * - `+1-800-123-4567` → `18001234567`
134 * - `+1-800-123-4567P123` → `18001234567P123`
136 * @return the normalised form of `number`
140 public string get_normalised ()
142 string normalised_number = "";
144 for (int i = 0; i < this.value.length; i++)
146 var digit = this.value.slice (i, i + 1);
148 if (i == 0 && digit == "+")
150 /* we drop the initial + */
153 else if (digit in this._extension_chars ||
154 digit in this._valid_digits)
156 /* lets keep valid digits */
157 normalised_number += digit;
159 else if (digit in this._common_delimiters)
165 debug ("[PhoneDetails.get_normalised] unknown digit: %s", digit);
169 return normalised_number.up ();
173 * Returns the given number without its extension (if any).
175 * @param number the phone number to process
176 * @return the number without its extension; if the number didn't have an
177 * extension in the first place, the number is returned unmodified
181 internal static string _drop_extension (string number)
183 for (var i = 0; i < PhoneFieldDetails._extension_chars.length; i++)
185 if (number.index_of (PhoneFieldDetails._extension_chars[i]) >= 0)
187 return number.split (PhoneFieldDetails._extension_chars[i])[0];
196 * Interface for classes that can provide a phone number, such as
197 * {@link Persona} and {@link Individual}.
201 public interface Folks.PhoneDetails : Object
204 * The phone numbers of the contact.
206 * A list of phone numbers associated to the contact.
210 public abstract Set<PhoneFieldDetails> phone_numbers { get; set; }
213 * Change the contact's phone numbers.
215 * It's preferred to call this rather than setting
216 * {@link PhoneDetails.phone_numbers} directly, as this method gives error
217 * notification and will only return once the phone numbers have been written
218 * to the relevant backing store (or the operation's failed).
220 * @param phone_numbers the set of phone numbers
221 * @throws PropertyError if setting the phone numbers failed
224 public virtual async void change_phone_numbers (
225 Set<PhoneFieldDetails> phone_numbers) throws PropertyError
227 /* Default implementation. */
228 throw new PropertyError.NOT_WRITEABLE (
229 _("Phone numbers are not writeable on this contact."));