[california/wip/731543-attendees] Component.Attendee -> Component.Person



commit dbae8c470806033a4d5920a03b0745f4816d2842
Author: Jim Nelson <jim yorba org>
Date:   Wed Nov 5 12:37:52 2014 -0800

    Component.Attendee -> Component.Person

 src/Makefile.am                       |    2 +-
 src/component/component-attendee.vala |  108 -------------------------
 src/component/component-instance.vala |   20 +++---
 src/component/component-person.vala   |  139 +++++++++++++++++++++++++++++++++
 4 files changed, 150 insertions(+), 119 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index c4d6bdf..d4dc27a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -85,13 +85,13 @@ california_VALASOURCES = \
        collection/collection-simple-iterable.vala \
        \
        component/component.vala \
-       component/component-attendee.vala \
        component/component-date-time.vala \
        component/component-details-parser.vala \
        component/component-error.vala \
        component/component-event.vala \
        component/component-icalendar.vala \
        component/component-instance.vala \
+       component/component-person.vala \
        component/component-recurrence-rule.vala \
        component/component-uid.vala \
        component/component-vtype.vala \
diff --git a/src/component/component-instance.vala b/src/component/component-instance.vala
index 1002fa6..0a12044 100644
--- a/src/component/component-instance.vala
+++ b/src/component/component-instance.vala
@@ -183,7 +183,7 @@ public abstract class Instance : BaseObject, Gee.Hashable<Instance> {
      *
      * See [[https://tools.ietf.org/html/rfc5545#section-3.8.4.1]]
      */
-    public Gee.Set<Attendee> attendees { get; private set; default = new Gee.HashSet<Attendee>(); }
+    public Gee.Set<Person> attendees { get; private set; default = new Gee.HashSet<Person>(); }
     
     /**
      * The iCal component being represented by this { link Instance}.
@@ -372,7 +372,7 @@ public abstract class Instance : BaseObject, Gee.Hashable<Instance> {
             iCal.icalproperty_kind.ATTENDEE_PROPERTY);
         while (attendee_prop != null) {
             try {
-                attendees.add(new Attendee.from_property(attendee_prop));
+                attendees.add(new Person.from_property(attendee_prop));
             } catch (ComponentError comperr) {
                 debug("Unable to parse ATTENDEE for %s: %s", to_string(), comperr.message);
             }
@@ -428,7 +428,7 @@ public abstract class Instance : BaseObject, Gee.Hashable<Instance> {
             
             case PROP_ATTENDEES:
                 remove_all_properties(iCal.icalproperty_kind.ATTENDEE_PROPERTY);
-                foreach (Attendee attendee in attendees)
+                foreach (Person attendee in attendees)
                     ical_component.add_property(attendee.as_ical_property());
             break;
             
@@ -488,8 +488,8 @@ public abstract class Instance : BaseObject, Gee.Hashable<Instance> {
      * No URI-format checking is performed here; it is up to the caller to convert and deal with
      * formatting issues.  Also note that duplicates are allowed in the attendees list.
      */
-    public void add_attendees(Gee.Collection<Attendee> to_add) {
-        Gee.Set<Attendee> copy = traverse<Attendee>(attendees).to_hash_set();
+    public void add_attendees(Gee.Collection<Person> to_add) {
+        Gee.Set<Person> copy = traverse<Person>(attendees).to_hash_set();
         copy.add_all(to_add);
         
         attendees = copy;
@@ -500,8 +500,8 @@ public abstract class Instance : BaseObject, Gee.Hashable<Instance> {
      *
      * See { link add_attendees} for notes about data validity and checking.
      */
-    public void remove_attendees(Gee.Collection<Attendee> to_remove) {
-        attendees = traverse<Attendee>(attendees)
+    public void remove_attendees(Gee.Collection<Person> to_remove) {
+        attendees = traverse<Person>(attendees)
             .filter(attendee => !to_remove.contains(attendee))
             .to_hash_set();
     }
@@ -510,7 +510,7 @@ public abstract class Instance : BaseObject, Gee.Hashable<Instance> {
      * Removes all { link attendees}.
      */
     public void clear_attendees() {
-        attendees = new Gee.HashSet<Attendee>();
+        attendees = new Gee.HashSet<Person>();
     }
     
     /**
@@ -519,10 +519,10 @@ public abstract class Instance : BaseObject, Gee.Hashable<Instance> {
      * Returns null if no attendees are associated with this { link Instance}.
      */
     public string? attendees_to_string() {
-        return traverse<Attendee>(attendees).to_string(stringify_attendee);
+        return traverse<Person>(attendees).to_string(stringify_attendee);
     }
     
-    private static string? stringify_attendee(Attendee attendee, bool is_first, bool is_last) {
+    private static string? stringify_attendee(Person attendee, bool is_first, bool is_last) {
         // A common separator for email addresses followed by an email address itself.
         return is_first ? attendee.mailbox : _(", %s").printf(attendee.mailbox);
     }
diff --git a/src/component/component-person.vala b/src/component/component-person.vala
new file mode 100644
index 0000000..e2d5404
--- /dev/null
+++ b/src/component/component-person.vala
@@ -0,0 +1,139 @@
+/* Copyright 2014 Yorba Foundation
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later).  See the COPYING file in this distribution.
+ */
+
+namespace California.Component {
+
+/**
+ * An immutable representation of an iCalendar CAL-ADDRESS (ATTENDEE, ORGANIZER, etc.)
+ *
+ * Person is not guaranteed to represent an individual per se, but it always represents an RFC822
+ * mailbox (i.e. email address), which may include a group list address, multiuser mailbox, etc.
+ *
+ * For equality purposes, only the { link mailto} is used.  All other parameters are ignored when
+ * comparing Persons.
+ *
+ * See [[https://tools.ietf.org/html/rfc5545#section-3.3.3]],
+ * [[https://tools.ietf.org/html/rfc5545#section-3.8.4.1]],
+ * [[https://tools.ietf.org/html/rfc5545#section-3.8.4.3]],
+ * [[https://tools.ietf.org/html/rfc5545#section-3.2.2]], and more.
+ */
+
+public class Person : BaseObject, Gee.Hashable<Person> {
+    /**
+     * The mailto: of the { link Person}, the only required value for the property.
+     */
+    public Soup.URI mailto { get; private set; }
+    
+    /**
+     * The CN (common name) for the { link Person}.
+     */
+    public string? common_name { get; private set; default = null; }
+    
+    /**
+     * The { link mailto} URI as a text string.
+     *
+     * @see mailbox
+     */
+    public string mailto_text { owned get { return mailto.to_string(false); } }
+    
+    /**
+     * The { link mailto} as a simple (unadorned) RFC822 mailbox (i.e. email address).
+     *
+     * This does not include the "mailto:"; scheme nor the { link common_name}, i.e.
+     * "bob example com"
+     */
+    public string mailbox { get { return mailto.path; } }
+    
+    /**
+     * The { link mailto} as a complete (adorned) RFC822 mailbox (i.e. email address) with
+     * user-readable name, if supplied.
+     *
+     * This does not include the "mailto:"; scheme but it will include the { link common_name} if
+     * present, i.e. "Bob Jones <bob example com>".
+     */
+    public string rfc822_mailbox { owned get {
+        return String.is_empty(common_name) ? "<%s>".printf(mailbox) : "%s <%s>".printf(common_name, 
mailbox);
+    } }
+    
+    private Gee.HashSet<string> parameters = new Gee.HashSet<string>(String.ci_hash, String.ci_equal);
+    
+    /**
+     * Create an { link Person} with the required { link mailto} and optional { link common_name}.
+     */
+    public Person(Soup.URI mailto, string? common_name) throws ComponentError {
+        validate_mailto(mailto);
+        
+        this.mailto = mailto;
+        this.common_name = common_name;
+    }
+    
+    internal Person.from_property(iCal.icalproperty prop) throws Error {
+        unowned iCal.icalvalue? prop_value = prop.get_value();
+        if (prop_value == null || prop_value.is_valid() == 0) {
+            throw new ComponentError.INVALID("Property of kind %s has no associated value",
+                prop.isa().to_string());
+        }
+        
+        if (prop_value.isa() != iCal.icalvalue_kind.CALADDRESS_VALUE) {
+            throw new ComponentError.INVALID("Property of kind %s has value of kind %s",
+                prop.isa().to_string(), prop_value.isa().to_string());
+        }
+        
+        string uri = prop_value.get_caladdress();
+        if (String.is_empty(uri))
+            throw new ComponentError.INVALID("Invalid Person property: no CAL-ADDRESS value");
+        
+        mailto = URI.parse(uri);
+        validate_mailto(mailto);
+        
+        // load parameters into local table
+        unowned iCal.icalparameter? param = prop.get_first_parameter(iCal.icalparameter_kind.ANY_PARAMETER);
+        while (param != null) {
+            parameters.add(param.as_ical_string());
+            
+            // parse parameter into well-known (common) property
+            switch (param.isa()) {
+                case iCal.icalparameter_kind.CN_PARAMETER:
+                    common_name = param.get_cn();
+                break;
+                
+                default:
+                    // fall-through
+                break;
+            }
+            
+            param = prop.get_next_parameter(iCal.icalparameter_kind.ANY_PARAMETER);
+        }
+    }
+    
+    private static void validate_mailto(Soup.URI uri) throws ComponentError {
+        if (uri.scheme != "mailto" || String.is_empty(uri.path))
+            throw new ComponentError.INVALID("Invalid mailto: %s", uri.to_string(false));
+    }
+    
+    internal iCal.icalproperty as_ical_property() {
+        iCal.icalproperty prop = new iCal.icalproperty.attendee(mailto_text);
+        foreach (string parameter in parameters)
+            prop.add_parameter(new iCal.icalparameter.from_string(parameter));
+        
+        return prop;
+    }
+    
+    public uint hash() {
+        return String.ci_hash(mailto_text);
+    }
+    
+    public bool equal_to(Person other) {
+        return (this != other) ? mailto.equal(other.mailto) : true;
+    }
+    
+    public override string to_string() {
+        return mailto_text;
+    }
+}
+
+}
+


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