[folks] telepathy: Add support for caching vCard parameters for contacts



commit 2a88b99a143a2d38253dfe92ce0140f33b453a7d
Author: Philip Withnall <philip tecnocode co uk>
Date:   Sun Oct 16 09:24:57 2011 +0100

    telepathy: Add support for caching vCard parameters for contacts
    
    Add birthday, full name, e-mail address, phone number and URL support to the
    Telepathy object cache so that contactsâ vCards are correctly stored when
    the cache is updated.
    
    Closes: bgo#661475

 NEWS                                               |    1 +
 .../telepathy/lib/tpf-persona-store-cache.vala     |  191 +++++++++++++++++++-
 backends/telepathy/lib/tpf-persona.vala            |   34 ++++-
 3 files changed, 222 insertions(+), 4 deletions(-)
---
diff --git a/NEWS b/NEWS
index 8cd7e31..1294824 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,7 @@ Bugs fixed:
 * Bug 657602 â Telepathy backend fails to set Personas' phone numbers from
   ContactInfo
 * Bug 660937 â [regression] build failure: No package 'gee-1.0' found
+* Bug 661475 â string_strip: assertion `self != NULL' failed
 
 API changes:
 * Implement PhoneDetails on Tpf.Persona
diff --git a/backends/telepathy/lib/tpf-persona-store-cache.vala b/backends/telepathy/lib/tpf-persona-store-cache.vala
index 9123a1a..150fe5f 100644
--- a/backends/telepathy/lib/tpf-persona-store-cache.vala
+++ b/backends/telepathy/lib/tpf-persona-store-cache.vala
@@ -37,6 +37,9 @@ using Folks;
  *  # Alias (`s`)
  *  # In contact list? (`b`)
  *  # Avatar file URI (`s`)
+ *  # Birthday date as a Unix timestamp (`s`)
+ *  # Set of e-mail addresses and parameters (`a(sa(ss))`)
+ *  # Full name (`s`)
  *
  * @since 0.6.0
  */
@@ -48,7 +51,7 @@ internal class Tpf.PersonaStoreCache : Folks.ObjectCache<Tpf.Persona>
    * get_serialised_object_type(). This must be modified whenever that variant
    * type or its semantics are changed, since that would necessitate a cache
    * refresh. */
-  private static const uint8 _FILE_FORMAT_VERSION = 1;
+  private static const uint8 _FILE_FORMAT_VERSION = 2;
 
   internal PersonaStoreCache (PersonaStore store)
     {
@@ -81,6 +84,44 @@ internal class Tpf.PersonaStoreCache : Folks.ObjectCache<Tpf.Persona>
             new VariantType.maybe (VariantType.STRING) // Avatar
           });
         }
+      else if (object_version == 2 || object_version == uint8.MAX)
+        {
+          return new VariantType.tuple ({
+            VariantType.STRING, // UID
+            VariantType.STRING, // IID
+            VariantType.STRING, // ID
+            VariantType.STRING, // Protocol
+            new VariantType.array (VariantType.STRING), // Groups
+            VariantType.BOOLEAN, // Favourite?
+            VariantType.STRING, // Alias
+            VariantType.BOOLEAN, // In contact list?
+            VariantType.BOOLEAN, // Is user?
+            new VariantType.maybe (VariantType.STRING), // Avatar
+            new VariantType.maybe (VariantType.INT64), // Birthday
+            VariantType.STRING, // Full name
+            new VariantType.array (new VariantType.tuple ({
+              VariantType.STRING, // E-mail address
+              new VariantType.array (new VariantType.tuple ({
+                VariantType.STRING, // Key
+                VariantType.STRING // Value
+              })) // Parameters
+            })), // E-mail addresses
+            new VariantType.array (new VariantType.tuple ({
+              VariantType.STRING, // Phone number
+              new VariantType.array (new VariantType.tuple ({
+                VariantType.STRING, // Key
+                VariantType.STRING // Value
+              })) // Parameters
+            })), // Phone numbers
+            new VariantType.array (new VariantType.tuple ({
+              VariantType.STRING, // URL
+              new VariantType.array (new VariantType.tuple ({
+                VariantType.STRING, // Key
+                VariantType.STRING // Value
+              })) // Parameters
+            })) // URLs
+          });
+        }
 
       // Unsupported version
       return null;
@@ -91,6 +132,40 @@ internal class Tpf.PersonaStoreCache : Folks.ObjectCache<Tpf.Persona>
       return this._FILE_FORMAT_VERSION;
     }
 
+  private Variant[] serialise_abstract_field_details (
+      Set<AbstractFieldDetails<string>> field_details_set)
+    {
+      Variant[] output_variants = new Variant[field_details_set.size];
+
+      uint i = 0;
+      foreach (var afd in field_details_set)
+        {
+          Variant[] parameters = new Variant[afd.parameters.size];
+
+          uint f = 0;
+          foreach (var key in afd.parameters.get_keys ())
+            {
+              foreach (var val in afd.parameters.get (key))
+                {
+                  parameters[f] = new Variant.tuple ({
+                    new Variant.string (key), // Key
+                    new Variant.string (val) // Value
+                  });
+                }
+            }
+
+          output_variants[i] = new Variant.tuple ({
+            afd.value, // Variant value (e.g. e-mail address)
+            new Variant.array (new VariantType.tuple ({
+              VariantType.STRING, // Key
+              VariantType.STRING // Value
+            }), parameters)
+          });
+        }
+
+      return output_variants;
+    }
+
   protected override Variant serialise_object (Tpf.Persona persona)
     {
       // Sort out the groups
@@ -117,6 +192,17 @@ internal class Tpf.PersonaStoreCache : Folks.ObjectCache<Tpf.Persona>
       var avatar_variant = (avatar_file != null) ?
           new Variant.string (avatar_file.get_uri ()) : null;
 
+      // Birthday
+      var birthday_variant = (persona.birthday != null) ?
+          new Variant.int64 (persona.birthday.to_unix ()) : null;
+
+      // Sort out the e-mail addresses, phone numbers and URLs
+      var email_addresses =
+          this.serialise_abstract_field_details (persona.email_addresses);
+      var phone_numbers =
+          this.serialise_abstract_field_details (persona.phone_numbers);
+      var urls = this.serialise_abstract_field_details (persona.urls);
+
       // Serialise the persona
       return new Variant.tuple ({
         new Variant.string (persona.uid),
@@ -128,10 +214,61 @@ internal class Tpf.PersonaStoreCache : Folks.ObjectCache<Tpf.Persona>
         new Variant.string (persona.alias),
         new Variant.boolean (persona.is_in_contact_list),
         new Variant.boolean (persona.is_user),
-        new Variant.maybe (VariantType.STRING, avatar_variant)
+        new Variant.maybe (VariantType.STRING, avatar_variant),
+        new Variant.maybe (VariantType.INT64, birthday_variant),
+        new Variant.string (persona.full_name),
+        new Variant.array (new VariantType.tuple ({
+          VariantType.STRING, // E-mail address
+          new VariantType.array (new VariantType.tuple ({
+            VariantType.STRING, // Key
+            VariantType.STRING // Value
+          })) // Parameters
+        }), email_addresses),
+        new Variant.array (new VariantType.tuple ({
+          VariantType.STRING, // Phone number
+          new VariantType.array (new VariantType.tuple ({
+            VariantType.STRING, // Key
+            VariantType.STRING // Value
+          })) // Parameters
+        }), phone_numbers),
+        new Variant.array (new VariantType.tuple ({
+          VariantType.STRING, // URL
+          new VariantType.array (new VariantType.tuple ({
+            VariantType.STRING, // Key
+            VariantType.STRING // Value
+          })) // Parameters
+        }), urls)
       });
     }
 
+  private delegate void AfdDeserialisationCallback (string val,
+      HashMultiMap<string, string> parameters);
+
+  private void deserialise_abstract_field_details (Variant input_variants,
+      AfdDeserialisationCallback cb)
+    {
+      for (uint i = 0; i < input_variants.n_children (); i++)
+        {
+          var input_variant = input_variants.get_child_value (i);
+
+          var val = input_variant.get_child_value (0).get_string ();
+
+          var parameters = new HashMultiMap<string, string> ();
+          var params_variants = input_variant.get_child_value (1);
+          for (uint f = 0; f < params_variants.n_children (); f++)
+            {
+              var params_variant = params_variants.get_child_value (f);
+
+              parameters.set (
+                  params_variant.get_child_value (0).get_string (),
+                  params_variant.get_child_value (1).get_string ());
+            }
+
+          // Output
+          cb (val, parameters);
+        }
+    }
+
   protected override Tpf.Persona deserialise_object (Variant variant,
       uint8 object_version)
     {
@@ -159,9 +296,57 @@ internal class Tpf.PersonaStoreCache : Folks.ObjectCache<Tpf.Persona>
           new FileIcon (File.new_for_uri (avatar_variant.get_string ())) :
           null;
 
+      // Deserialise the birthday
+      DateTime? birthday = null;
+      if (object_version == 2)
+        {
+          var birthday_variant = variant.get_child_value (10).get_maybe ();
+          if (birthday_variant != null)
+            {
+              birthday =
+                  new DateTime.from_unix_utc (birthday_variant.get_int64 ());
+            }
+        }
+
+      var full_name = "";
+      if (object_version == 2)
+        {
+          full_name = variant.get_child_value (11).get_string();
+        }
+
+      var email_address_set = new HashSet<EmailFieldDetails> (
+          (GLib.HashFunc) EmailFieldDetails.hash,
+          (GLib.EqualFunc) EmailFieldDetails.equal);
+      var phone_number_set = new HashSet<PhoneFieldDetails> (
+          (GLib.HashFunc) PhoneFieldDetails.hash,
+          (GLib.EqualFunc) PhoneFieldDetails.equal);
+      var url_set = new HashSet<UrlFieldDetails> (
+          (GLib.HashFunc) UrlFieldDetails.hash,
+          (GLib.EqualFunc) UrlFieldDetails.equal);
+
+      if (object_version == 2)
+        {
+          this.deserialise_abstract_field_details (variant.get_child_value (12),
+              (v, p) =>
+                {
+                  email_address_set.add (new EmailFieldDetails (v, p));
+                });
+          this.deserialise_abstract_field_details (variant.get_child_value (13),
+              (v, p) =>
+                {
+                  phone_number_set.add (new PhoneFieldDetails (v, p));
+                });
+          this.deserialise_abstract_field_details (variant.get_child_value (14),
+              (v, p) =>
+                {
+                  url_set.add (new UrlFieldDetails (v, p));
+                });
+        }
+
       return new Tpf.Persona.from_cache (this._store, uid, iid, display_id,
           im_protocol, group_set, is_favourite, alias, is_in_contact_list,
-          is_user, avatar);
+          is_user, avatar, birthday, full_name, email_address_set,
+          phone_number_set, url_set);
     }
 }
 
diff --git a/backends/telepathy/lib/tpf-persona.vala b/backends/telepathy/lib/tpf-persona.vala
index 227f5ef..fd451d3 100644
--- a/backends/telepathy/lib/tpf-persona.vala
+++ b/backends/telepathy/lib/tpf-persona.vala
@@ -871,6 +871,16 @@ public class Tpf.Persona : Folks.Persona,
    * @param is_user Whether the persona is the user.
    * @param avatar The icon for the persona's cached avatar, or `null` if they
    * have no avatar.
+   * @param birthday The date/time of birth of the persona, or `null` if it's
+   * unknown.
+   * @param full_name The persona's full name, or the empty string if it's
+   * unknown.
+   * @param email_addresses A set of the persona's e-mail addresses, which may
+   * be empty (but may not be `null`).
+   * @param phone_numbers A set of the persona's phone numbers, which may be
+   * empty (but may not be `null`).
+   * @param urls A set of the persona's URLs, which may be empty (but may not be
+   * `null`).
    * @return A new { link Tpf.Persona} representing the cached persona.
    *
    * @since 0.6.0
@@ -878,7 +888,9 @@ public class Tpf.Persona : Folks.Persona,
   internal Persona.from_cache (PersonaStore store, string uid, string iid,
       string im_address, string protocol, HashSet<string> groups,
       bool is_favourite, string alias, bool is_in_contact_list, bool is_user,
-      LoadableIcon? avatar)
+      LoadableIcon? avatar, DateTime? birthday, string full_name,
+      HashSet<EmailFieldDetails> email_addresses,
+      HashSet<PhoneFieldDetails> phone_numbers, HashSet<UrlFieldDetails> urls)
     {
       Object (contact: null,
               display_id: im_address,
@@ -901,6 +913,18 @@ public class Tpf.Persona : Folks.Persona,
       this._groups = groups;
       this._groups_ro = this._groups.read_only_view;
 
+      // E-mail addresses
+      this._email_addresses = email_addresses;
+      this._email_addresses_ro = this._email_addresses.read_only_view;
+
+      // Phone numbers
+      this._phone_numbers = phone_numbers;
+      this._phone_numbers_ro = this._phone_numbers.read_only_view;
+
+      // URLs
+      this._urls = urls;
+      this._urls_ro = this._urls.read_only_view;
+
       // Other properties
       if (alias == null)
         {
@@ -908,10 +932,18 @@ public class Tpf.Persona : Folks.Persona,
           alias = "";
         }
 
+      if (full_name == null)
+        {
+          /* Deal with badly-behaved callers */
+          full_name = "";
+        }
+
       this._alias = alias;
       this._is_favourite = is_favourite;
       this.is_in_contact_list = is_in_contact_list;
       this._avatar = avatar;
+      this._birthday = birthday;
+      this._full_name = full_name;
 
       // Make the persona appear offline
       this.presence_type = PresenceType.OFFLINE;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]