File folks-bnc855848-individual-crash.patch of Package folks

Fix crash when connecting to and using IRC channels.

https://bugzilla.redhat.com/show_bug.cgi?id=1031252


diff --git a/folks/individual.vala b/folks/individual.vala
index 7b3eccd..5ff00b2 100644
--- a/folks/individual.vala
+++ b/folks/individual.vala
@@ -231,12 +231,12 @@ public class Folks.Individual : Object,
    *
    * @since 0.6.0
    */
-  public string presence_status { get; set; }
+  public string presence_status { get; set; default = ""; }
 
   /**
    * {@inheritDoc}
    */
-  public string presence_message { get; set; }
+  public string presence_message { get; set; default = ""; }
 
   /**
    * {@inheritDoc}
@@ -286,8 +286,11 @@ public class Folks.Individual : Object,
    * instead. For example, if storing references to Individuals who are tagged
    * in a photo, it may be safer to store the UID of the Persona whose backend
    * provided the photo (e.g. Facebook).
+   *
+   * As a special case, the ID defaults to an empty string when the individual
+   * has no personas (i.e. if it’s just been constructed).
    */
-  public string id { get; private set; }
+  public string id { get; private set; default = ""; }
 
   /**
    * Emitted when the last of the Individual's {@link Persona}s has been
@@ -1228,14 +1231,41 @@ public class Folks.Individual : Object,
 
   private void _persona_notify_cb (Object obj, ParamSpec ps)
     {
-      assert (obj is Persona);
-      assert (ps.name == "individual" || (obj as Persona).individual == this);
+      var persona = (Persona) obj;  /* will abort on failure */
+
+      /* It should not be possible for two Individuals to be simultaneously
+       * connected to the same Persona (as _connect_to_persona() will disconnect
+       * any previous Persona.individual), but warn (rather than asserting) just
+       * in case, since this is a critical code path. */
+      if (ps.name != "individual" &&
+          persona.individual != this &&
+          persona.individual != null)
+        {
+          warning ("Notification on property ‘%s’ of Persona %p (‘%s’) where " +
+              "Persona.individual is %p but was expected to be %p.",
+              ps.name, persona, persona.uid, persona.individual, this);
+          return;
+        }
+      else if (ps.name == "individual")
+        {
+          if (persona.individual != this)
+            {
+              /* Remove the notified persona from our set of personas. */
+              var remaining_personas = new SmallSet<Persona> ();
+              remaining_personas.add_all (this._persona_set);
+              remaining_personas.remove (persona);
+
+              this._set_personas (remaining_personas, null);
+            }
+
+          return;
+        }
 
       foreach (var notifier in Individual._notifiers)
         {
           if (ps.name == notifier.property)
             {
-              notifier.notify (this, (!) (obj as Persona), ps);
+              notifier.notify (this, persona, ps);
               break;  /* assume all entries in notifiers are unique */
             }
         }
@@ -2111,8 +2141,17 @@ public class Folks.Individual : Object,
             }, emit_notification, force_update);
     }
 
+  /* Note: This causes the Persona to be stolen away from its current
+   * Individual. */
   private void _connect_to_persona (Persona persona)
     {
+      if (persona.individual != null && persona.individual != this)
+        {
+          /* Disconnect the previous Individual. This atomically avoids having
+           * two Individuals connected to the same Persona simultaneously. */
+          persona.individual._disconnect_from_persona (persona, this);
+        }
+
       persona.individual = this;
 
       /* We're interested in most, if not all, signals from a persona,
@@ -2863,6 +2902,11 @@ public class Folks.Individual : Object,
           this.id = Checksum.compute_for_string (ChecksumType.SHA1,
               ((!) chosen_persona).uid);
         }
+      else
+        {
+          /* Default if we have no personas. */
+          this.id = "";
+        }
 
       /* Update our aggregated fields and notify the changes */
       this._update_fields ();
openSUSE Build Service is sponsored by