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. All the personas belonging to one physical person
- * are aggregated to form a single {@link Individual} representing that person.
+ * from evolution-data-server.
+ *
+ * All the personas belonging to one physical person are aggregated to form a
+ * single {@link Individual} representing that person.
*/
public abstract class Folks.Persona : Object
{
+ private weak Individual? _individual;
+
/**
* The internal ID used to represent the Persona for linking.
*
* 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
*/
public string display_id { get; construct; }
/**
+ * 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`.
+ *
+ * @since 0.3.0
+ */
+ public bool is_user { get; construct; }
+
+ /**
* The {@link PersonaStore} which contains this Persona.
*/
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
* 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.
* linkable-property-to-individual mapping it wants to add or remove in the
* aggregator.
*
+ * @param link the mapping string to be added to the
+ * {@link IndividualAggregator}
* @since 0.1.13
*/
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.
* added to the {@link IndividualAggregator}'s link map, related to the
* {@link Individual} instance which contains this {@link Persona}.
*
+ * @param prop_name the name of the linkable property to use, which must be
+ * listed in {@link Persona.linkable_properties}
+ * @param callback a callback to execute for each of the mapping strings
+ * generated by this property
* @see Persona.linkable_properties
* @since 0.1.13
*/
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 ("\\:", ":");
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));
}
/**
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 () == '\\')
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)));
}