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 unowned GLib.KeyFile _key_file;
37 private HashMultiMap<string, ImFieldDetails> _im_addresses;
38 private HashMultiMap<string, WebServiceFieldDetails> _web_service_addresses;
39 private string _alias;
40 private const string[] _linkable_properties =
43 "web-service-addresses"
45 private const string[] _writeable_properties =
49 "web-service-addresses"
55 public override string[] linkable_properties
57 get { return this._linkable_properties; }
65 public override string[] writeable_properties
67 get { return this._writeable_properties; }
75 [CCode (notify = false)]
78 get { return this._alias; }
79 set { this.change_alias.begin (value); }
87 public async void change_alias (string alias) throws PropertyError
89 if (this._alias == alias)
94 debug ("Setting alias of Kf.Persona '%s' to '%s'.", this.uid, alias);
96 this._key_file.set_string (this.display_id, "__alias", alias);
97 yield ((Kf.PersonaStore) this.store).save_key_file ();
100 this.notify_property ("alias");
106 [CCode (notify = false)]
107 public MultiMap<string, ImFieldDetails> im_addresses
109 get { return this._im_addresses; }
110 set { this.change_im_addresses.begin (value); }
118 public async void change_im_addresses (
119 MultiMap<string, ImFieldDetails> im_addresses) throws PropertyError
121 /* Remove the current IM addresses from the key file */
122 foreach (var protocol1 in this._im_addresses.get_keys ())
126 this._key_file.remove_key (this.display_id, protocol1);
128 catch (KeyFileError e1)
130 /* Ignore the error, since it's just a group or key not found
135 /* Add the new IM addresses to the key file and build a normalised
136 * table of them to set as the new property value */
137 var new_im_addresses = new HashMultiMap<string, ImFieldDetails> (
139 (GLib.HashFunc) ImFieldDetails.hash,
140 (GLib.EqualFunc) ImFieldDetails.equal);
142 foreach (var protocol2 in im_addresses.get_keys ())
144 var addresses = im_addresses.get (protocol2);
145 var normalised_addresses = new HashSet<string> ();
147 foreach (var im_fd in addresses)
149 string normalised_address;
152 normalised_address = ImDetails.normalise_im_address (
153 im_fd.value, protocol2);
155 catch (ImDetailsError e2)
157 throw new PropertyError.INVALID_VALUE (
158 /* Translators: this is an error message for if the user
159 * provides an invalid IM address. The first parameter is
160 * an IM address (e.g. “foo@jabber.org”), the second is
161 * the name of a protocol (e.g. “jabber”) and the third is
162 * an error message. */
163 _("Invalid IM address ‘%s’ for protocol ‘%s’: %s"),
164 im_fd.value, protocol2, e2.message);
167 normalised_addresses.add (normalised_address);
168 var new_im_fd = new ImFieldDetails (normalised_address);
169 new_im_addresses.set (protocol2, new_im_fd);
172 string[] addrs = (string[]) normalised_addresses.to_array ();
173 addrs.length = normalised_addresses.size;
175 this._key_file.set_string_list (this.display_id, protocol2, addrs);
178 /* Get the PersonaStore to save the key file */
179 yield ((Kf.PersonaStore) this.store).save_key_file ();
181 this._im_addresses = new_im_addresses;
182 this.notify_property ("im-addresses");
188 [CCode (notify = false)]
189 public MultiMap<string, WebServiceFieldDetails> web_service_addresses
191 get { return this._web_service_addresses; }
192 set { this.change_web_service_addresses.begin (value); }
200 public async void change_web_service_addresses (
201 MultiMap<string, WebServiceFieldDetails> web_service_addresses)
204 /* Remove the current web service addresses from the key file */
205 foreach (var web_service1 in this._web_service_addresses.get_keys ())
209 this._key_file.remove_key (this.display_id,
210 "web-service." + web_service1);
212 catch (KeyFileError e)
214 /* Ignore the error, since it's just a group or key not found
219 /* Add the new web service addresses to the key file and build a
220 * table of them to set as the new property value */
221 var new_web_service_addresses =
222 new HashMultiMap<string, WebServiceFieldDetails> (
224 (GLib.HashFunc) WebServiceFieldDetails.hash,
225 (GLib.EqualFunc) WebServiceFieldDetails.equal);
227 foreach (var web_service2 in web_service_addresses.get_keys ())
229 var ws_fds = web_service_addresses.get (web_service2);
231 string[] addrs = new string[0];
232 foreach (var ws_fd1 in ws_fds)
233 addrs += ws_fd1.value;
235 this._key_file.set_string_list (this.display_id,
236 "web-service." + web_service2, addrs);
238 foreach (var ws_fd2 in ws_fds)
239 new_web_service_addresses.set (web_service2, ws_fd2);
242 /* Get the PersonaStore to save the key file */
243 yield ((Kf.PersonaStore) this.store).save_key_file ();
245 this._web_service_addresses = new_web_service_addresses;
246 this.notify_property ("web-service-addresses");
250 * Create a new persona.
252 * Create a new persona for the {@link PersonaStore} `store`, representing
253 * the Persona given by the group `uid` in the key file `key_file`.
255 public Persona (KeyFile key_file, string id, Folks.PersonaStore store)
257 var iid = store.id + ":" + id;
258 var uid = this.build_uid ("key-file", store.id, id);
260 Object (display_id: id,
266 debug ("Adding key-file Persona '%s' (IID '%s', group '%s')", uid, iid,
269 this._key_file = key_file;
270 this._im_addresses = new HashMultiMap<string, ImFieldDetails> (
271 null, null, ImFieldDetails.hash, (EqualFunc) ImFieldDetails.equal);
272 this._web_service_addresses =
273 new HashMultiMap<string, WebServiceFieldDetails> (
275 (GLib.HashFunc) WebServiceFieldDetails.hash,
276 (GLib.EqualFunc) WebServiceFieldDetails.equal);
278 /* Load the IM addresses from the key file */
281 var keys = this._key_file.get_keys (this.display_id);
282 foreach (unowned string key in keys)
285 if (key == "__alias")
287 this._alias = this._key_file.get_string (this.display_id,
289 debug (" Loaded alias '%s'.", this._alias);
293 /* Web service addresses */
294 var decomposed_key = key.split(".", 2);
295 if (decomposed_key.length == 2 &&
296 decomposed_key[0] == "web-service")
298 unowned string web_service = decomposed_key[1];
299 var web_service_addresses = this._key_file.get_string_list (
300 this.display_id, web_service);
302 foreach (var web_service_address in web_service_addresses)
304 this._web_service_addresses.set (web_service,
305 new WebServiceFieldDetails (web_service_address));
312 unowned string protocol = key;
313 var im_addresses = this._key_file.get_string_list (
314 this.display_id, protocol);
316 foreach (var im_address in im_addresses)
321 address = ImDetails.normalise_im_address (im_address,
324 catch (ImDetailsError e)
326 /* Warn of and ignore any invalid IM addresses */
331 var im_fd = new ImFieldDetails (address);
332 this._im_addresses.set (protocol, im_fd);
336 catch (KeyFileError e)
338 /* We get a GROUP_NOT_FOUND exception if we're creating a new
339 * Persona, since it doesn't yet exist in the key file. We shouldn't
340 * get any other exceptions, since we're iterating through a list of
341 * keys we've just retrieved. */
342 if (!(e is KeyFileError.GROUP_NOT_FOUND))
344 /* Translators: the parameter is an error message. */
345 warning (_("Couldn't load data from key file: %s"), e.message);
353 public override void linkable_property_to_links (string prop_name,
354 Folks.Persona.LinkablePropertyCallback callback)
356 if (prop_name == "im-addresses")
358 foreach (var protocol in this._im_addresses.get_keys ())
360 var im_addresses = this._im_addresses.get (protocol);
362 foreach (var im_fd in im_addresses)
363 callback (protocol + ":" + im_fd.value);
366 else if (prop_name == "web-service-addresses")
368 foreach (var web_service in this.web_service_addresses.get_keys ())
370 var web_service_addresses =
371 this._web_service_addresses.get (web_service);
373 foreach (var ws_fd in web_service_addresses)
374 callback (web_service + ":" + ws_fd.value);
380 base.linkable_property_to_links (prop_name, callback);