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 ();