build fix: Only depend on Gee 0.8.3, since 0.8.4 isn't released yet
[platform/upstream/folks.git] / backends / key-file / kf-persona.vala
index 11622b8..2d4b2eb 100644 (file)
@@ -30,13 +30,13 @@ using Folks.Backends.Kf;
  */
 public class Folks.Backends.Kf.Persona : Folks.Persona,
     AliasDetails,
+    AntiLinkable,
     ImDetails,
     WebServiceDetails
 {
-  private unowned GLib.KeyFile _key_file;
   private HashMultiMap<string, ImFieldDetails> _im_addresses;
   private HashMultiMap<string, WebServiceFieldDetails> _web_service_addresses;
-  private string _alias;
+  private string _alias = ""; /* must not be null */
   private const string[] _linkable_properties =
     {
       "im-addresses",
@@ -46,7 +46,8 @@ public class Folks.Backends.Kf.Persona : Folks.Persona,
     {
       "alias",
       "im-addresses",
-      "web-service-addresses"
+      "web-service-addresses",
+      "anti-links"
     };
 
   /**
@@ -54,7 +55,7 @@ public class Folks.Backends.Kf.Persona : Folks.Persona,
    */
   public override string[] linkable_properties
     {
-      get { return this._linkable_properties; }
+      get { return Kf.Persona._linkable_properties; }
     }
 
   /**
@@ -64,7 +65,7 @@ public class Folks.Backends.Kf.Persona : Folks.Persona,
    */
   public override string[] writeable_properties
     {
-      get { return this._writeable_properties; }
+      get { return Kf.Persona._writeable_properties; }
     }
 
   /**
@@ -82,10 +83,16 @@ public class Folks.Backends.Kf.Persona : Folks.Persona,
   /**
    * {@inheritDoc}
    *
-   * @since UNRELEASED
+   * @since 0.6.2
    */
   public async void change_alias (string alias) throws PropertyError
     {
+      /* Deal with badly-behaved callers. */
+      if (alias == null)
+        {
+          alias = "";
+        }
+
       if (this._alias == alias)
         {
           return;
@@ -93,7 +100,8 @@ public class Folks.Backends.Kf.Persona : Folks.Persona,
 
       debug ("Setting alias of Kf.Persona '%s' to '%s'.", this.uid, alias);
 
-      this._key_file.set_string (this.display_id, "__alias", alias);
+      unowned KeyFile key_file = ((Kf.PersonaStore) this.store).get_key_file ();
+      key_file.set_string (this.display_id, "__alias", alias);
       yield ((Kf.PersonaStore) this.store).save_key_file ();
 
       this._alias = alias;
@@ -113,17 +121,19 @@ public class Folks.Backends.Kf.Persona : Folks.Persona,
   /**
    * {@inheritDoc}
    *
-   * @since UNRELEASED
+   * @since 0.6.2
    */
   public async void change_im_addresses (
       MultiMap<string, ImFieldDetails> im_addresses) throws PropertyError
     {
+      unowned KeyFile key_file = ((Kf.PersonaStore) this.store).get_key_file ();
+
       /* Remove the current IM addresses from the key file */
       foreach (var protocol1 in this._im_addresses.get_keys ())
         {
           try
             {
-              this._key_file.remove_key (this.display_id, protocol1);
+              key_file.remove_key (this.display_id, protocol1);
             }
           catch (KeyFileError e1)
             {
@@ -136,8 +146,8 @@ public class Folks.Backends.Kf.Persona : Folks.Persona,
        * table of them to set as the new property value */
       var new_im_addresses = new HashMultiMap<string, ImFieldDetails> (
           null, null,
-          (GLib.HashFunc) ImFieldDetails.hash,
-          (GLib.EqualFunc) ImFieldDetails.equal);
+          (Gee.HashDataFunc) AbstractFieldDetails<string>.hash_static,
+          (Gee.EqualDataFunc) AbstractFieldDetails<string>.equal_static);
 
       foreach (var protocol2 in im_addresses.get_keys ())
         {
@@ -172,7 +182,7 @@ public class Folks.Backends.Kf.Persona : Folks.Persona,
           string[] addrs = (string[]) normalised_addresses.to_array ();
           addrs.length = normalised_addresses.size;
 
-          this._key_file.set_string_list (this.display_id, protocol2, addrs);
+          key_file.set_string_list (this.display_id, protocol2, addrs);
         }
 
       /* Get the PersonaStore to save the key file */
@@ -185,109 +195,197 @@ public class Folks.Backends.Kf.Persona : Folks.Persona,
   /**
    * {@inheritDoc}
    */
+  [CCode (notify = false)]
   public MultiMap<string, WebServiceFieldDetails> web_service_addresses
     {
-      get
-        { return this._web_service_addresses; }
+      get { return this._web_service_addresses; }
+      set { this.change_web_service_addresses.begin (value); }
+    }
 
-      set
+  /**
+   * {@inheritDoc}
+   *
+   * @since 0.6.2
+   */
+  public async void change_web_service_addresses (
+      MultiMap<string, WebServiceFieldDetails> web_service_addresses)
+          throws PropertyError
+    {
+      unowned KeyFile key_file = ((Kf.PersonaStore) this.store).get_key_file ();
+
+      /* Remove the current web service addresses from the key file */
+      foreach (var web_service1 in this._web_service_addresses.get_keys ())
         {
-          /* Remove the current web service addresses from the key file */
-          foreach (var web_service in this._web_service_addresses.get_keys ())
+          try
             {
-              try
-                {
-                  this._key_file.remove_key (this.display_id,
-                      "web-service." + web_service);
-                }
-              catch (KeyFileError e)
-                {
-                  /* Ignore the error, since it's just a group or key not found
-                   * error. */
-                }
+              key_file.remove_key (this.display_id,
+                  "web-service." + web_service1);
             }
+          catch (KeyFileError e)
+            {
+              /* Ignore the error, since it's just a group or key not found
+               * error. */
+            }
+        }
 
-          /* Add the new web service addresses to the key file and build a
-           * table of them to set as the new property value */
-          var web_service_addresses =
-            new HashMultiMap<string, WebServiceFieldDetails> (
-                null, null,
-                (GLib.HashFunc) WebServiceFieldDetails.hash,
-                (GLib.EqualFunc) WebServiceFieldDetails.equal);
+      /* Add the new web service addresses to the key file and build a
+       * table of them to set as the new property value */
+      var new_web_service_addresses =
+        new HashMultiMap<string, WebServiceFieldDetails> (
+            null, null,
+            (Gee.HashDataFunc) AbstractFieldDetails<string>.hash_static,
+            (Gee.EqualDataFunc) AbstractFieldDetails<string>.equal_static);
 
-          foreach (var web_service in value.get_keys ())
-            {
-              var ws_fds = value.get (web_service);
+      foreach (var web_service2 in web_service_addresses.get_keys ())
+        {
+          var ws_fds = web_service_addresses.get (web_service2);
 
-              string[] addrs = new string[0];
-              foreach (var ws_fd in ws_fds)
-                addrs += ws_fd.value;
+          string[] addrs = new string[0];
+          foreach (var ws_fd1 in ws_fds)
+            addrs += ws_fd1.value;
 
-              this._key_file.set_string_list (this.display_id,
-                  "web-service." + web_service, addrs);
+          key_file.set_string_list (this.display_id,
+              "web-service." + web_service2, addrs);
 
-              foreach (var ws_fd in ws_fds)
-                web_service_addresses.set (web_service, ws_fd);
-            }
+          foreach (var ws_fd2 in ws_fds)
+            new_web_service_addresses.set (web_service2, ws_fd2);
+        }
+
+      /* Get the PersonaStore to save the key file */
+      yield ((Kf.PersonaStore) this.store).save_key_file ();
 
-          this._web_service_addresses = web_service_addresses;
+      this._web_service_addresses = new_web_service_addresses;
+      this.notify_property ("web-service-addresses");
+    }
+
+  private HashSet<string> _anti_links;
+  private Set<string> _anti_links_ro;
+
+  /**
+   * {@inheritDoc}
+   *
+   * @since 0.7.3
+   */
+  [CCode (notify = false)]
+  public Set<string> anti_links
+    {
+      get { return this._anti_links_ro; }
+      set { this.change_anti_links.begin (value); }
+    }
 
-          /* Get the PersonaStore to save the key file */
-          ((Kf.PersonaStore) this.store).save_key_file.begin ();
+  /**
+   * {@inheritDoc}
+   *
+   * @since 0.7.3
+   */
+  public async void change_anti_links (Set<string> anti_links)
+      throws PropertyError
+    {
+      if (Folks.Internal.equal_sets<string> (anti_links, this.anti_links))
+        {
+          return;
         }
+
+      unowned KeyFile key_file = ((Kf.PersonaStore) this.store).get_key_file ();
+
+      /* Skip the persona's UID; don't allow reflexive anti-links. */
+      anti_links.remove (this.uid);
+
+      key_file.set_string_list (this.display_id,
+          Kf.PersonaStore.anti_links_key_name, anti_links.to_array ());
+
+      /* Get the PersonaStore to save the key file */
+      yield ((Kf.PersonaStore) this.store).save_key_file ();
+
+      /* Update the stored anti-links. */
+      this._anti_links.clear ();
+      this._anti_links.add_all (anti_links);
+      this.notify_property ("anti-links");
     }
 
   /**
    * Create a new persona.
    *
-   * Create a new persona for the {@link PersonaStore} `store`, representing
-   * the Persona given by the group `uid` in the key file `key_file`.
+   * Create a new persona for the {@link PersonaStore} ``store``, representing
+   * the Persona given by the group ``uid`` in the key file ``key_file``.
    */
-  public Persona (KeyFile key_file, string id, Folks.PersonaStore store)
+  public Persona (string id, Folks.PersonaStore store)
     {
       var iid = store.id + ":" + id;
-      var uid = this.build_uid ("key-file", store.id, id);
+      var uid = Folks.Persona.build_uid ("key-file", store.id, id);
 
       Object (display_id: id,
               iid: iid,
               uid: uid,
               store: store,
               is_user: false);
+    }
 
-      debug ("Adding key-file Persona '%s' (IID '%s', group '%s')", uid, iid,
-          id);
+  construct
+    {
+      debug ("Adding key-file Persona '%s' (IID '%s', group '%s')", this.uid,
+          this.iid, this.display_id);
 
-      this._key_file = key_file;
       this._im_addresses = new HashMultiMap<string, ImFieldDetails> (
-          null, null, ImFieldDetails.hash, (EqualFunc) ImFieldDetails.equal);
+          null, null,
+          (Gee.HashDataFunc) AbstractFieldDetails<string>.hash_static,
+          (Gee.EqualDataFunc) AbstractFieldDetails<string>.equal_static);
       this._web_service_addresses =
         new HashMultiMap<string, WebServiceFieldDetails> (
-            null, null,
-            (GLib.HashFunc) WebServiceFieldDetails.hash,
-            (GLib.EqualFunc) WebServiceFieldDetails.equal);
+          null, null,
+          (Gee.HashDataFunc) AbstractFieldDetails<string>.hash_static,
+          (Gee.EqualDataFunc) AbstractFieldDetails<string>.equal_static);
+      this._anti_links = new HashSet<string> ();
+      this._anti_links_ro = this._anti_links.read_only_view;
 
       /* Load the IM addresses from the key file */
+      unowned KeyFile key_file = ((Kf.PersonaStore) this.store).get_key_file ();
+
       try
         {
-          var keys = this._key_file.get_keys (this.display_id);
+          var keys = key_file.get_keys (this.display_id);
           foreach (unowned string key in keys)
             {
               /* Alias */
               if (key == "__alias")
                 {
-                  this._alias = this._key_file.get_string (this.display_id,
-                      key);
+                  this._alias = key_file.get_string (this.display_id, key);
+
+                  if (this._alias == null)
+                    {
+                      this._alias = "";
+                    }
+
                   debug ("    Loaded alias '%s'.", this._alias);
                   continue;
                 }
 
+              /* Anti-links. */
+              if (key == Kf.PersonaStore.anti_links_key_name)
+                {
+                  var anti_link_array =
+                      key_file.get_string_list (this.display_id, key);
+
+                  if (anti_link_array != null)
+                    {
+                      foreach (var anti_link in anti_link_array)
+                        {
+                          this._anti_links.add (anti_link);
+                        }
+
+                      debug ("    Loaded %u anti-links.",
+                          anti_link_array.length);
+                      continue;
+                    }
+                }
+
               /* Web service addresses */
               var decomposed_key = key.split(".", 2);
               if (decomposed_key.length == 2 &&
                   decomposed_key[0] == "web-service")
                 {
                   unowned string web_service = decomposed_key[1];
-                  var web_service_addresses = this._key_file.get_string_list (
+                  var web_service_addresses = key_file.get_string_list (
                       this.display_id, web_service);
 
                   foreach (var web_service_address in web_service_addresses)
@@ -301,7 +399,7 @@ public class Folks.Backends.Kf.Persona : Folks.Persona,
 
               /* IM addresses */
               unowned string protocol = key;
-              var im_addresses = this._key_file.get_string_list (
+              var im_addresses = key_file.get_string_list (
                   this.display_id, protocol);
 
               foreach (var im_address in im_addresses)