2 * Copyright (C) 2010 Collabora Ltd.
4 * This library is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation, either version 2.1 of the License, or
7 * (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
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/>.
18 * Philip Withnall <philip.withnall@collabora.co.uk>
24 using Folks.Backends.Kf;
27 * A persona subclass which represents a single persona from a simple key file.
31 public class Folks.Backends.Kf.Persona : Folks.Persona,
36 private HashMultiMap<string, ImFieldDetails> _im_addresses;
37 private HashMultiMap<string, WebServiceFieldDetails> _web_service_addresses;
38 private string _alias = ""; /* must not be null */
39 private const string[] _linkable_properties =
42 "web-service-addresses"
44 private const string[] _writeable_properties =
48 "web-service-addresses"
54 public override string[] linkable_properties
56 get { return this._linkable_properties; }
64 public override string[] writeable_properties
66 get { return this._writeable_properties; }
74 [CCode (notify = false)]
77 get { return this._alias; }
78 set { this.change_alias.begin (value); }
86 public async void change_alias (string alias) throws PropertyError
88 /* Deal with badly-behaved callers. */
94 if (this._alias == alias)
99 debug ("Setting alias of Kf.Persona '%s' to '%s'.", this.uid, alias);
101 unowned KeyFile key_file = ((Kf.PersonaStore) this.store).get_key_file ();
102 key_file.set_string (this.display_id, "__alias", alias);
103 yield ((Kf.PersonaStore) this.store).save_key_file ();
106 this.notify_property ("alias");
112 [CCode (notify = false)]
113 public MultiMap<string, ImFieldDetails> im_addresses
115 get { return this._im_addresses; }
116 set { this.change_im_addresses.begin (value); }
124 public async void change_im_addresses (
125 MultiMap<string, ImFieldDetails> im_addresses) throws PropertyError
127 unowned KeyFile key_file = ((Kf.PersonaStore) this.store).get_key_file ();
129 /* Remove the current IM addresses from the key file */
130 foreach (var protocol1 in this._im_addresses.get_keys ())
134 key_file.remove_key (this.display_id, protocol1);
136 catch (KeyFileError e1)
138 /* Ignore the error, since it's just a group or key not found
143 /* Add the new IM addresses to the key file and build a normalised
144 * table of them to set as the new property value */
145 var new_im_addresses = new HashMultiMap<string, ImFieldDetails> (
147 AbstractFieldDetails<string>.hash_static,
148 AbstractFieldDetails<string>.equal_static);
150 foreach (var protocol2 in im_addresses.get_keys ())
152 var addresses = im_addresses.get (protocol2);
153 var normalised_addresses = new HashSet<string> ();
155 foreach (var im_fd in addresses)
157 string normalised_address;
160 normalised_address = ImDetails.normalise_im_address (
161 im_fd.value, protocol2);
163 catch (ImDetailsError e2)
165 throw new PropertyError.INVALID_VALUE (
166 /* Translators: this is an error message for if the user
167 * provides an invalid IM address. The first parameter is
168 * an IM address (e.g. “foo@jabber.org”), the second is
169 * the name of a protocol (e.g. “jabber”) and the third is
170 * an error message. */
171 _("Invalid IM address ‘%s’ for protocol ‘%s’: %s"),
172 im_fd.value, protocol2, e2.message);
175 normalised_addresses.add (normalised_address);
176 var new_im_fd = new ImFieldDetails (normalised_address);
177 new_im_addresses.set (protocol2, new_im_fd);
180 string[] addrs = (string[]) normalised_addresses.to_array ();
181 addrs.length = normalised_addresses.size;
183 key_file.set_string_list (this.display_id, protocol2, addrs);
186 /* Get the PersonaStore to save the key file */
187 yield ((Kf.PersonaStore) this.store).save_key_file ();
189 this._im_addresses = new_im_addresses;
190 this.notify_property ("im-addresses");
196 [CCode (notify = false)]
197 public MultiMap<string, WebServiceFieldDetails> web_service_addresses
199 get { return this._web_service_addresses; }
200 set { this.change_web_service_addresses.begin (value); }
208 public async void change_web_service_addresses (
209 MultiMap<string, WebServiceFieldDetails> web_service_addresses)
212 unowned KeyFile key_file = ((Kf.PersonaStore) this.store).get_key_file ();
214 /* Remove the current web service addresses from the key file */
215 foreach (var web_service1 in this._web_service_addresses.get_keys ())
219 key_file.remove_key (this.display_id,
220 "web-service." + web_service1);
222 catch (KeyFileError e)
224 /* Ignore the error, since it's just a group or key not found
229 /* Add the new web service addresses to the key file and build a
230 * table of them to set as the new property value */
231 var new_web_service_addresses =
232 new HashMultiMap<string, WebServiceFieldDetails> (
234 AbstractFieldDetails<string>.hash_static,
235 AbstractFieldDetails<string>.equal_static);
237 foreach (var web_service2 in web_service_addresses.get_keys ())
239 var ws_fds = web_service_addresses.get (web_service2);
241 string[] addrs = new string[0];
242 foreach (var ws_fd1 in ws_fds)
243 addrs += ws_fd1.value;
245 key_file.set_string_list (this.display_id,
246 "web-service." + web_service2, addrs);
248 foreach (var ws_fd2 in ws_fds)
249 new_web_service_addresses.set (web_service2, ws_fd2);
252 /* Get the PersonaStore to save the key file */
253 yield ((Kf.PersonaStore) this.store).save_key_file ();
255 this._web_service_addresses = new_web_service_addresses;
256 this.notify_property ("web-service-addresses");
260 * Create a new persona.
262 * Create a new persona for the {@link PersonaStore} `store`, representing
263 * the Persona given by the group `uid` in the key file `key_file`.
265 public Persona (string id, Folks.PersonaStore store)
267 var iid = store.id + ":" + id;
268 var uid = this.build_uid ("key-file", store.id, id);
270 Object (display_id: id,
279 debug ("Adding key-file Persona '%s' (IID '%s', group '%s')", this.uid,
280 this.iid, this.display_id);
282 this._im_addresses = new HashMultiMap<string, ImFieldDetails> (
283 null, null, AbstractFieldDetails<string>.hash_static,
284 AbstractFieldDetails<string>.equal_static);
285 this._web_service_addresses =
286 new HashMultiMap<string, WebServiceFieldDetails> (
288 AbstractFieldDetails<string>.hash_static,
289 AbstractFieldDetails<string>.equal_static);
291 /* Load the IM addresses from the key file */
292 unowned KeyFile key_file = ((Kf.PersonaStore) this.store).get_key_file ();
296 var keys = key_file.get_keys (this.display_id);
297 foreach (unowned string key in keys)
300 if (key == "__alias")
302 this._alias = key_file.get_string (this.display_id, key);
304 if (this._alias == null)
309 debug (" Loaded alias '%s'.", this._alias);
313 /* Web service addresses */
314 var decomposed_key = key.split(".", 2);
315 if (decomposed_key.length == 2 &&
316 decomposed_key[0] == "web-service")
318 unowned string web_service = decomposed_key[1];
319 var web_service_addresses = key_file.get_string_list (
320 this.display_id, web_service);
322 foreach (var web_service_address in web_service_addresses)
324 this._web_service_addresses.set (web_service,
325 new WebServiceFieldDetails (web_service_address));
332 unowned string protocol = key;
333 var im_addresses = key_file.get_string_list (
334 this.display_id, protocol);
336 foreach (var im_address in im_addresses)
341 address = ImDetails.normalise_im_address (im_address,
344 catch (ImDetailsError e)
346 /* Warn of and ignore any invalid IM addresses */
351 var im_fd = new ImFieldDetails (address);
352 this._im_addresses.set (protocol, im_fd);
356 catch (KeyFileError e)
358 /* We get a GROUP_NOT_FOUND exception if we're creating a new
359 * Persona, since it doesn't yet exist in the key file. We shouldn't
360 * get any other exceptions, since we're iterating through a list of
361 * keys we've just retrieved. */
362 if (!(e is KeyFileError.GROUP_NOT_FOUND))
364 /* Translators: the parameter is an error message. */
365 warning (_("Couldn't load data from key file: %s"), e.message);
373 public override void linkable_property_to_links (string prop_name,
374 Folks.Persona.LinkablePropertyCallback callback)
376 if (prop_name == "im-addresses")
378 foreach (var protocol in this._im_addresses.get_keys ())
380 var im_addresses = this._im_addresses.get (protocol);
382 foreach (var im_fd in im_addresses)
383 callback (protocol + ":" + im_fd.value);
386 else if (prop_name == "web-service-addresses")
388 foreach (var web_service in this.web_service_addresses.get_keys ())
390 var web_service_addresses =
391 this._web_service_addresses.get (web_service);
393 foreach (var ws_fd in web_service_addresses)
394 callback (web_service + ":" + ws_fd.value);
400 base.linkable_property_to_links (prop_name, callback);