Post-release version bump
[platform/upstream/folks.git] / folks / persona.vala
index 7733aa1..75970fd 100644 (file)
 using GLib;
 
 /**
+ * Errors which can be thrown when asynchronously setting a property of a
+ * {@link Persona} using a setter method defined on an interface such as
+ * {@link AliasDetails}.
+ *
+ * @since 0.6.2
+ */
+public errordomain Folks.PropertyError
+{
+  /**
+   * Property is not writeable for this particular object.
+   *
+   * @since 0.6.2
+   */
+  NOT_WRITEABLE,
+
+  /**
+   * Value was invalid for the property.
+   *
+   * @since 0.6.2
+   */
+  INVALID_VALUE,
+
+  /**
+   * Unknown error when setting the property.
+   *
+   * @since 0.6.2
+   */
+  UNKNOWN_ERROR
+}
+
+/**
  * Represents a "shard" of a person from a single source (a single
  * {@link Backend}), such as an XMPP contact from Telepathy or a vCard contact
  * from evolution-data-server.
@@ -30,6 +61,8 @@ using GLib;
  */
 public abstract class Folks.Persona : Object
 {
+  private weak Individual? _individual;
+
   /**
    * The internal ID used to represent the Persona for linking.
    *
@@ -52,6 +85,11 @@ public abstract class Folks.Persona : Object
    * This is the canonical way to refer to any Persona. It is guaranteed to be
    * unique within the Persona's {@link PersonaStore}.
    *
+   * A Persona's UID is immutable over the life of the Persona in the backing
+   * store, so a given UID is guaranteed to refer to the same Persona each time
+   * libfolks is used, until the Persona is permanently removed from its backing
+   * store.
+   *
    * @see Persona.build_uid
    * @see Persona.split_uid
    */
@@ -87,8 +125,8 @@ public abstract class Folks.Persona : Object
   /**
    * Whether the Persona is the user.
    *
-   * Iff the Persona represents the user – the person who owns the account in
-   * the respective backend – this is `true`.
+   * Iff the Persona represents the user (the person who owns the account in
+   * the respective backend) this is `true`.
    *
    * @since 0.3.0
    */
@@ -100,6 +138,33 @@ public abstract class Folks.Persona : Object
   public weak PersonaStore store { get; construct; }
 
   /**
+   * The {@link Individual} which contains this Persona.
+   *
+   * This may be `null`, but should only ever be so when the Persona has just
+   * been created, when its {@link PersonaStore} is being destroyed, or when
+   * it's moving between {@link Individual}s.
+   *
+   * @since 0.6.0
+   */
+  public weak Individual? individual
+    {
+      get
+        {
+          assert (this._individual == null ||
+              ((!) this._individual).personas.contains (this));
+
+          return this._individual;
+        }
+
+      internal set
+        {
+          assert (value == null || ((!) value).personas.contains (this));
+
+          this._individual = value;
+        }
+    }
+
+  /**
    * The names of the properties of this Persona which are linkable.
    *
    * If a property name is in this list, and the Persona is from a
@@ -114,9 +179,27 @@ public abstract class Folks.Persona : Object
    * This list will have no effect if the Persona's {@link PersonaStore} trust
    * level is not {@link PersonaStoreTrust.FULL}.
    *
+   * This property value is guaranteed to be constant for a given persona,
+   * but may vary between personas in the same store.
+   *
    * @since 0.1.13
    */
-  public string[] linkable_properties { get; protected set; }
+  public abstract string[] linkable_properties { get; }
+
+  /**
+   * The names of the properties of this Persona which are writeable.
+   *
+   * If a property name is in this list, setting the property should result in
+   * the updated value being stored in the backend's permanent storage (unless
+   * it gets rejected due to being invalid, or a different error occurs).
+   *
+   * It's intended that this property value will be constant for a given Persona
+   * subclass, but this isn't guaranteed; it's possible that Persona subclasses
+   * may vary the value of this property at run time.
+   *
+   * @since 0.6.0
+   */
+  public abstract string[] writeable_properties { get; }
 
   /**
    * Callback into the aggregator to manipulate a link mapping.
@@ -133,7 +216,7 @@ public abstract class Folks.Persona : Object
    */
   public delegate void LinkablePropertyCallback (string link);
 
-  /* FIXME: This code should move to the IMable interface as a concrete
+  /* FIXME: This code should move to the ImDetails interface as a concrete
    * method of the interface. However, that depends on bgo#624842 */
   /**
    * Produce one or more mapping strings for the given property's value.
@@ -161,14 +244,14 @@ public abstract class Folks.Persona : Object
       assert_not_reached ();
     }
 
-  private static string escape_uid_component (string component)
+  private static string _escape_uid_component (string component)
     {
       /* Escape colons with backslashes */
       string escaped = component.replace ("\\", "\\\\");
       return escaped.replace (":", "\\:");
     }
 
-  private static string unescape_uid_component (string component)
+  private static string _unescape_uid_component (string component)
     {
       /* Unescape colons and backslashes */
       string unescaped = component.replace ("\\:", ":");
@@ -190,9 +273,9 @@ public abstract class Folks.Persona : Object
   public static string build_uid (string backend_name,
       string persona_store_id, string persona_id)
     {
-      return "%s:%s:%s".printf (Persona.escape_uid_component (backend_name),
-                                Persona.escape_uid_component (persona_store_id),
-                                Persona.escape_uid_component (persona_id));
+      return "%s:%s:%s".printf (Persona._escape_uid_component (backend_name),
+          Persona._escape_uid_component (persona_store_id),
+          Persona._escape_uid_component (persona_id));
     }
 
   /**
@@ -214,7 +297,7 @@ public abstract class Folks.Persona : Object
       assert (uid.validate ());
 
       size_t backend_name_length = 0, persona_store_id_length = 0;
-      bool escaped = false;
+      var escaped = false;
       for (unowned string i = uid; i.get_char () != '\0'; i = i.next_char ())
         {
           if (i.get_char () == '\\')
@@ -231,12 +314,12 @@ public abstract class Folks.Persona : Object
 
       assert (backend_name_length != 0 && persona_store_id_length != 0);
 
-      backend_name = Persona.unescape_uid_component (
-          uid.ndup (backend_name_length));
-      persona_store_id = Persona.unescape_uid_component (
-          ((string) ((char*) uid + backend_name_length + 1)).ndup (
-              persona_store_id_length));
-      persona_id = Persona.unescape_uid_component (
+      backend_name = Persona._unescape_uid_component (
+          uid.substring (0, (long) backend_name_length));
+      persona_store_id = Persona._unescape_uid_component (
+          ((string) ((char*) uid + backend_name_length + 1)).substring (0,
+              (long) persona_store_id_length));
+      persona_id = Persona._unescape_uid_component (
           ((string) ((char*) uid + backend_name_length +
               persona_store_id_length + 2)));
     }