[Bedework-commit] calendarapi r717 - in trunk: calCore/resources/hbms calFacade/src/org/bedework/calfacade calFacade/src/org/bedework/calfacade/exc calsvc/src/org/bedework/calsvc calsvci/src/org/bedework/calsvci

svnadmin at bedework.org svnadmin at bedework.org
Thu Oct 2 09:52:36 EDT 2008


Author: douglm
Date: 2008-10-02 09:52:33 -0400 (Thu, 02 Oct 2008)
New Revision: 717

Added:
   trunk/calFacade/src/org/bedework/calfacade/exc/ValidationError.java
Modified:
   trunk/calCore/resources/hbms/Event.hbm.xml
   trunk/calFacade/src/org/bedework/calfacade/BwContact.java
   trunk/calFacade/src/org/bedework/calfacade/BwEvent.java
   trunk/calFacade/src/org/bedework/calfacade/BwLocation.java
   trunk/calsvc/src/org/bedework/calsvc/AutoScheduler.java
   trunk/calsvc/src/org/bedework/calsvc/Calendars.java
   trunk/calsvc/src/org/bedework/calsvc/Events.java
   trunk/calsvc/src/org/bedework/calsvc/Scheduling.java
   trunk/calsvci/src/org/bedework/calsvci/EventsI.java
   trunk/calsvci/src/org/bedework/calsvci/SchedulingI.java
Log:
Changes to support implicit scheduling operations as defined in CalDAV scheduling draft 05

Bedework trunk is still a bit broken at this stage but sending of invitations appears to be working.

Replying is another matter...

Modified: trunk/calCore/resources/hbms/Event.hbm.xml
===================================================================
--- trunk/calCore/resources/hbms/Event.hbm.xml	2008-10-01 03:33:10 UTC (rev 716)
+++ trunk/calCore/resources/hbms/Event.hbm.xml	2008-10-02 13:52:33 UTC (rev 717)
@@ -329,8 +329,20 @@
       <property name="value" column="bw_reltoval" type="string" length="500" />
     </component>
 
-    <property name="scheduleState"  column="schedule_state" type="integer" />
+    <property name="scheduleState"
+              column="schedule_state"
+              type="integer" />
 
+    <property name="organizerSchedulingObject"
+              column="bw_org_scheduleobj"
+              type="boolean" not-null="true"
+              index="bw_idx_orgsobj" />
+
+    <property name="attendeeSchedulingObject"
+              column="bw_att_scheduleobj"
+              type="boolean" not-null="true"
+              index="bw_idx_attsobj" />
+
     <list name="xproperties" table="bw_event_xprops"
          cascade="all-delete-orphan" >
       <cache usage="read-write"/>

Modified: trunk/calFacade/src/org/bedework/calfacade/BwContact.java
===================================================================
--- trunk/calFacade/src/org/bedework/calfacade/BwContact.java	2008-10-01 03:33:10 UTC (rev 716)
+++ trunk/calFacade/src/org/bedework/calfacade/BwContact.java	2008-10-02 13:52:33 UTC (rev 717)
@@ -251,4 +251,19 @@
     return sb.toString();
   }
 
+  public Object clone() {
+    BwContact sp = new BwContact();
+
+    sp.setOwner((BwUser)getOwner().clone());
+    sp.setPublick(getPublick());
+    sp.setCreator((BwUser)getCreator().clone());
+    sp.setUid(getUid());
+    sp.setAccess(getAccess());
+    sp.setName((BwString)getName().clone());
+    sp.setPhone(getPhone());
+    sp.setEmail(getEmail());
+    sp.setLink(getLink());
+
+    return sp;
+  }
 }

Modified: trunk/calFacade/src/org/bedework/calfacade/BwEvent.java
===================================================================
--- trunk/calFacade/src/org/bedework/calfacade/BwEvent.java	2008-10-01 03:33:10 UTC (rev 716)
+++ trunk/calFacade/src/org/bedework/calfacade/BwEvent.java	2008-10-02 13:52:33 UTC (rev 717)
@@ -521,12 +521,8 @@
    */
   private Set<BwCategory> categories = null;
 
-  /** This may or may not be set to populate fully
-   */
   private Set<BwContact> contacts;
 
-  /** This may or may not be set to populate fully
-   */
   private BwLocation location;
 
   private BwOrganizer organizer;
@@ -644,6 +640,12 @@
   public static final String requestStatusNoAccess =
            "4.2;No Access";
 
+  private boolean organizerSchedulingObject;
+
+  private boolean attendeeSchedulingObject;
+
+  /* -------------- End of (CalDAV) scheduling information ----------------- */
+
   private BwRelatedTo relatedTo;
 
   /** Collection of BwXproperty
@@ -691,6 +693,8 @@
    */
   private Collection<BwEventAnnotation> overrides;
 
+  private boolean incSequence;
+
   /** Constructor
    */
   protected BwEvent() {
@@ -1115,6 +1119,45 @@
     return scheduleState;
   }
 
+
+  /** True if this is a valid organizer scheduling object. (See CalDAV
+   * scheduling specification). This can be set false (and will be on copy) to
+   * supress sending of invitations, e.g. for a draft.
+   *
+   * <p>When the event is added this flag will be set true if the appropriate
+   * conditions are satisfied.
+   *
+   * @param val
+   */
+  @Immutable
+  public void setOrganizerSchedulingObject(boolean val) {
+    organizerSchedulingObject = val;
+  }
+
+  /**
+   * @return boolean
+   */
+  public boolean getOrganizerSchedulingObject() {
+    return organizerSchedulingObject;
+  }
+
+  /** True if this is a valid attendee scheduling object.
+   * (See CalDAV scheduling specification)
+   *
+   * @param val
+   */
+  @Immutable
+  public void setAttendeeSchedulingObject(boolean val) {
+    attendeeSchedulingObject = val;
+  }
+
+  /**
+   * @return boolean
+   */
+  public boolean getAttendeeSchedulingObject() {
+    return attendeeSchedulingObject;
+  }
+
   /** Set the relatedTo property
    *
    * @param val    BwRelatedTo relatedTo property
@@ -2753,6 +2796,30 @@
   }
 
   /* ====================================================================
+   *                   Non-db methods
+   * ==================================================================== */
+
+  /** Set the incSequence flag
+   *
+   * @param val
+   */
+  @NoProxy
+  @NoDump
+  public void setIncSequence(boolean val) {
+    incSequence = val;
+  }
+
+  /** Get the uids
+   *
+   * @return Set<String>   uids
+   */
+  @NoProxy
+  @NoDump
+  public boolean getIncSequence() {
+    return incSequence;
+  }
+
+  /* ====================================================================
    *                   Convenience methods
    * ==================================================================== */
 
@@ -2777,10 +2844,6 @@
     return overrides;
   }
 
-  /* ====================================================================
-   *                   Convenience methods
-   * ==================================================================== */
-
   /** Return all timezone ids this event uses. This is used when an event is
    * added by another user to ensure that the target user has a copy of user
    * specific timezones.

Modified: trunk/calFacade/src/org/bedework/calfacade/BwLocation.java
===================================================================
--- trunk/calFacade/src/org/bedework/calfacade/BwLocation.java	2008-10-01 03:33:10 UTC (rev 716)
+++ trunk/calFacade/src/org/bedework/calfacade/BwLocation.java	2008-10-02 13:52:33 UTC (rev 717)
@@ -280,4 +280,20 @@
 
     return sb.toString();
   }
+
+  public Object clone() {
+    BwLocation loc = new BwLocation();
+
+    super.copyTo(loc);
+    loc.setUid(getUid());
+    if (getAddress() != null) {
+      loc.setAddress((BwString)getAddress().clone());
+    }
+    if (getSubaddress() != null) {
+      loc.setSubaddress((BwString)getSubaddress().clone());
+    }
+    loc.setLink(getLink());
+
+    return loc;
+  }
 }

Added: trunk/calFacade/src/org/bedework/calfacade/exc/ValidationError.java
===================================================================
--- trunk/calFacade/src/org/bedework/calfacade/exc/ValidationError.java	                        (rev 0)
+++ trunk/calFacade/src/org/bedework/calfacade/exc/ValidationError.java	2008-10-02 13:52:33 UTC (rev 717)
@@ -0,0 +1,279 @@
+/* **********************************************************************
+    Copyright 2006 Rensselaer Polytechnic Institute. All worldwide rights reserved.
+
+    Redistribution and use of this distribution in source and binary forms,
+    with or without modification, are permitted provided that:
+       The above copyright notice and this permission notice appear in all
+        copies and supporting documentation;
+
+        The name, identifiers, and trademarks of Rensselaer Polytechnic
+        Institute are not used in advertising or publicity without the
+        express prior written permission of Rensselaer Polytechnic Institute;
+
+    DISCLAIMER: The software is distributed" AS IS" without any express or
+    implied warranty, including but not limited to, any implied warranties
+    of merchantability or fitness for a particular purpose or any warrant)'
+    of non-infringement of any current or pending patent rights. The authors
+    of the software make no representations about the suitability of this
+    software for any particular purpose. The entire risk as to the quality
+    and performance of the software is with the user. Should the software
+    prove defective, the user assumes the cost of all necessary servicing,
+    repair or correction. In particular, neither Rensselaer Polytechnic
+    Institute, nor the authors of the software are liable for any indirect,
+    special, consequential, or incidental damages related to the software,
+    to the maximum extent the law permits.
+*/
+package org.bedework.calfacade.exc;
+
+import java.io.Serializable;
+
+/**
+ * Define error property codes emitted by validation code. Suggested English Language
+ * is supplied in the comment for clarification only.
+ *
+ * @author Mike Douglass
+ *
+ */
+public class ValidationError implements Serializable {
+  /** Prefix for all these errors */
+  public static final String prefix = "org.bedework.validation.error.";
+
+  /** Cannot change schedule methode. */
+  public static final String cannotChangeMethod = prefix + "cannot.change.method";
+
+  /** Your information is incorrect: please supply exactly one attendee. */
+  public static final String expectOneAttendee = prefix + "expectoneattendee";
+
+  /** Error: in submissions calendar. */
+  public static final String inSubmissionsCalendar = prefix + "insubmissionscalendar";
+
+  /** Error: bad how. */
+  public static final String invalidAccessHow = prefix + "invalid.how";
+
+  /** Error: bad who type (user or group). */
+  public static final String invalidAccessWhoType = prefix + "invalid.whotype";
+
+  /** The attendee uri is invalid. */
+  public static final String invalidAttendee = prefix + "invalid.attendee";
+
+  /** Bad or out-of-range date.. */
+  public static final String invalidDate = prefix + "invalid.date";
+
+  /** <em>Invalid duration</em> - you may not have a zero-length duration
+  for an all day event. */
+  public static final String invalidDuration = prefix + "invalid.duration";
+
+  /** The <em>entity type</em> is invalid. */
+  public static final String invalidEntityType = prefix + "invalid.entitytype";
+
+  /** The <em>end date type</em> is invalid. */
+  public static final String invalidEndtype = prefix + "invalid.endtype";
+
+  /** The organizer uri is invalid. */
+  public static final String invalidOrganizer = prefix + "invalid.organizer";
+
+  /** Error: invalid auto cancel preference. */
+  public static final String invalidPrefAutoCancel = prefix + "invalid.invalidprefautocancel";
+
+  /** Error: invalid auto process response preference. */
+  public static final String invalidPrefAutoProcess = prefix + "invalid.invalidprefautoprocess";
+
+  /** Error: invalid date range end type preference. */
+  public static final String invalidPrefEndType = prefix + "invalid.prefendtype";
+
+  /** Error: invalid user mode preference. */
+  public static final String invalidPrefUserMode = prefix + "invalid.prefusermode";
+
+  /** Error: invalid workday end. */
+  public static final String invalidPrefWorkDayEnd = prefix + "invalid.prefworkdayend";
+
+  /** Error: invalid working days: start after end */
+  public static final String invalidPrefWorkDays = prefix + "invalid.prefworkdays";
+
+  /** Error: invalid workday start. */
+  public static final String invalidPrefWorkDayStart = prefix + "invalid.prefworkdaystart";
+
+  /** The recipient uri is invalid. */
+  public static final String invalidRecipient = prefix + "invalid.recipient";
+
+  /** Error: bad value for recurrence count */
+  public static final String invalidRecurCount = prefix + "invalid.recurcount";
+
+  /** Error: Cannot specify count and until for recurrence */
+  public static final String invalidRecurCountAndUntil = prefix + "invalid.recurcountanduntil";
+
+  /** Error: bad value for recurrence interval */
+  public static final String invalidRecurInterval = prefix + "invalid.recurinterval";
+
+  /** Error: bad value for recurrence rule */
+  public static final String invalidRecurRule = prefix + "invalid.recurrule";
+
+  /** Error: bad value for recurrence until */
+  public static final String invalidRecurUntil = prefix + "invalid.recuruntil";
+
+  /** Error: bad scheduling data. */
+  public static final String invalidSchedData = prefix + "invalid.scheddata";
+
+  /** Error: bad scheduling method (should be request or publish). */
+  public static final String invalidSchedMethod = prefix + "invalid.schedmethod";
+
+  /** Error: bad scheduling part status . */
+  public static final String invalidSchedPartStatus = prefix + "invalid.schedpartstatus";
+
+  /** Error: bad scheduling method (should be reply). */
+  public static final String invalidSchedReplyMethod = prefix + "invalid.schedreplymethod";
+
+  /** Error: bad scheduling method (should be request). */
+  public static final String invalidSchedRequestMethod = prefix + "invalid.schedrequestmethod";
+
+  /** Error: bad scheduling method (should be COUNTER, REFRESH, REPLY). */
+  public static final String invalidSchedRespondMethod = prefix + "invalid.schedrespondmethod";
+
+  /** Error: Invalid status. */
+  public static final String invalidStatus = prefix + "invalid.status";
+
+  /** Error: Invalid transparency. */
+  public static final String invalidTransparency = prefix + "invalid.transparency";
+
+  /** Error: Invalid user. */
+  public static final String invalidUser = prefix + "invalid.user";
+
+  /** Error: Invalid xprop. */
+  public static final String invalidXprop = prefix + "invalid.xprop";
+
+  /** Error: missing how.*/
+  public static final String missingAccessHow = prefix + "missinghow";
+
+  /** Error: missing who (principal name).*/
+  public static final String missingAccessWho = prefix + "missingwho";
+
+  /** Your information is incomplete: please supply an address. */
+  public static final String missingAddress = prefix + "missingaddress";
+
+  /** Your information is incomplete: please supply a calendar. */
+  public static final String missingCalendar = prefix + "missingcalendar";
+
+  /** Your information is incomplete: please supply a calendar path. */
+  public static final String missingCalendarPath = prefix + "missingcalendarpath";
+
+  /** Your information is incomplete: please supply a root calendar path. */
+  public static final String missingCalsuiteCalendar = prefix + "missingcalsuitecalendar";
+
+  /** Your information is incomplete: please supply a category keyword. */
+  public static final String missingCategoryKeyword = prefix + "missingcategorykeyword";
+
+  /** Your information is incomplete: please supply a contact. */
+  public static final String missingContact = prefix + "missingcontact";
+
+  /** You must enter a contact <em>name</em>. */
+  public static final String missingContactName = prefix + "missingcontactname";
+
+  /** Your information is incomplete: please supply a description. */
+  public static final String missingDescription = prefix + "missingdescription";
+
+  /** Your information is incomplete: please supply an event owner. */
+  public static final String missingEventOwner = prefix + "missingeventowner";
+
+  /** Your information is incomplete: please supply a filter definition. */
+  public static final String missingFilterDef = prefix + "missingfilterdef";
+
+  /** Your information is incomplete: please supply a group name. */
+  public static final String missingGroupName = prefix + "missinggroupname";
+
+  /** Your information is incomplete: please supply a group owner. */
+  public static final String missingGroupOwner = prefix + "missinggroupowner";
+
+  /** Your information is incomplete: please supply a location. */
+  public static final String missingLocation = prefix + "missinglocation";
+
+  /** Your information is incomplete: please supply a name. */
+  public static final String missingName = prefix + "missingname";
+
+  /** Your event is missing the originator */
+  public static final String missingOriginator = prefix + "missingoriginator";
+
+  /** Your event is missing the organizer */
+  public static final String missingOrganizer = prefix + "missingorganizer";
+
+  /** Cannot change this into a scheduling message */
+  public static final String invalidSchedulingObject = prefix + "invalidschedulingobject";
+
+  /** You must supply a recipient. */
+  public static final String missingRecipients = prefix + "missingrecipients";
+
+  /** Your information is incomplete: please supply a subscription id. */
+  public static final String missingSubscriptionid = prefix + "missingsubscriptionid";
+
+  /** Your information is incomplete: please supply a title. */
+  public static final String missingTitle = prefix + "missingtitle";
+
+  /** Your information is incomplete: please supply a uri for the subscription. */
+  public static final String missingSubUri = prefix + "missingsuburi";
+
+  /** Error: not in submissions calendar. */
+  public static final String notSubmissionsCalendar = prefix + "notsubmissionscalendar";
+
+  /** The <em>end date</em> occurs before the <em>start date</em>. */
+  public static final String startAfterEnd = prefix + "startafterend";
+
+  /** Your description is too long.  Please limit your entry to
+      characters.  You may also wish to
+      point the event entry at a supplemental web page by entering a <em>URL</em>. */
+  public static final String tooLongDescription = prefix + "toolong.description";
+
+  /** Your name is too long.  Please limit your entry to  */
+  public static final String tooLongName = prefix + "toolong.name";
+
+  /** Your summary is too long.  Please limit your entry to
+      characters.  You may also wish to
+      point the event entry at a supplemental web page by entering a <em>URL</em>. */
+  public static final String tooLongSummary = prefix + "toolong.summary";
+
+  private String errorCode;
+
+  private String extra;
+
+  /**
+   * @param errorCode
+   */
+  public ValidationError(String errorCode) {
+    this(errorCode, null);
+  }
+
+  /**
+   * @param errorCode
+   * @param extra
+   */
+  public ValidationError(String errorCode, String extra) {
+    this.errorCode = errorCode;
+    this.extra = extra;
+  }
+
+  /**
+   * @param val
+   */
+  public void setErrorCode(String val) {
+    errorCode = val;
+  }
+
+  /**
+   * @return String
+   */
+  public String getErrorCode() {
+    return errorCode;
+  }
+
+  /**
+   * @param val
+   */
+  public void setExtra(String val) {
+    extra = val;
+  }
+
+  /**
+   * @return String
+   */
+  public String getExtra() {
+    return extra;
+  }
+}

Modified: trunk/calsvc/src/org/bedework/calsvc/AutoScheduler.java
===================================================================
--- trunk/calsvc/src/org/bedework/calsvc/AutoScheduler.java	2008-10-01 03:33:10 UTC (rev 716)
+++ trunk/calsvc/src/org/bedework/calsvc/AutoScheduler.java	2008-10-02 13:52:33 UTC (rev 717)
@@ -184,7 +184,7 @@
     }
 
     return sched.processCancel(ei, scheduleAutoCancelAction,
-                               sched.getMeetingCalendars(ei.getEvent()));
+                               sched.getMeetingCalendar(ei.getEvent()));
   }
 
   private ScheduleResult processRequest(CalSvcI svci,
@@ -232,7 +232,7 @@
                                  false,
                                  // Use preferred calendar
                                  svci.getCalendarsHandler().getPreferred(), // newCal
-                                 sched.getMeetingCalendars(ev));
+                                 sched.getMeetingCalendar(ev));
   }
 
   private ScheduleResult processReply(CalSvcI svci,
@@ -263,7 +263,7 @@
       }
     }
 
-    return sched.processResponse(ei, sched.getMeetingCalendars(ev));
+    return sched.processResponse(ei, sched.getMeetingCalendar(ev));
   }
 
   private ScheduleResult processRefresh(CalSvcI svci,
@@ -285,15 +285,15 @@
 
     BwAttendee att = atts.iterator().next();
 
-    /* We can only do this if there is one copy */
+    /* We can only do this if there is an active copy */
 
-    Collection<BwCalendar> cals = sched.getMeetingCalendars(ev);
+    BwCalendar cal = sched.getMeetingCalendar(ev);
 
-    if ((cals == null) || (cals.size() != 1)) {
+    if (cal == null) {
       return null;
     }
 
-    EventInfo calEi = getEvent(svci, cals.iterator().next(), ev.getUid(),
+    EventInfo calEi = getEvent(svci, cal, ev.getUid(),
                                ev.getRecurrenceId());
     if (calEi == null) {
       return null;

Modified: trunk/calsvc/src/org/bedework/calsvc/Calendars.java
===================================================================
--- trunk/calsvc/src/org/bedework/calsvc/Calendars.java	2008-10-01 03:33:10 UTC (rev 716)
+++ trunk/calsvc/src/org/bedework/calsvc/Calendars.java	2008-10-02 13:52:33 UTC (rev 717)
@@ -499,7 +499,9 @@
 
         if (ei.getNewEvent()) {
           try {
-            UpdateResult eur = getSvc().getEventsHandler().add(val, ei, false);
+            UpdateResult eur = getSvc().getEventsHandler().add(val, ei,
+                                                               true, false,
+                                                               false);
 
             /*
                 AddEventResult aer = new AddEventResult(ev,

Modified: trunk/calsvc/src/org/bedework/calsvc/Events.java
===================================================================
--- trunk/calsvc/src/org/bedework/calsvc/Events.java	2008-10-01 03:33:10 UTC (rev 716)
+++ trunk/calsvc/src/org/bedework/calsvc/Events.java	2008-10-02 13:52:33 UTC (rev 717)
@@ -30,6 +30,7 @@
 import org.bedework.calcorei.CoreCalendarsI.GetSpecialCalendarResult;
 import org.bedework.calcorei.CoreEventsI.InternalEventKey;
 import org.bedework.calcorei.CoreEventsI.UpdateEventResult;
+import org.bedework.calfacade.BwAttendee;
 import org.bedework.calfacade.BwCalendar;
 import org.bedework.calfacade.BwContact;
 import org.bedework.calfacade.BwDateTime;
@@ -37,10 +38,13 @@
 import org.bedework.calfacade.BwEventAnnotation;
 import org.bedework.calfacade.BwEventProxy;
 import org.bedework.calfacade.BwLocation;
+import org.bedework.calfacade.BwOrganizer;
 import org.bedework.calfacade.BwUser;
 import org.bedework.calfacade.RecurringRetrievalMode;
+import org.bedework.calfacade.ScheduleResult;
 import org.bedework.calfacade.RecurringRetrievalMode.Rmode;
 import org.bedework.calfacade.exc.CalFacadeAccessException;
+import org.bedework.calfacade.exc.CalFacadeBadRequest;
 import org.bedework.calfacade.exc.CalFacadeDupNameException;
 import org.bedework.calfacade.exc.CalFacadeException;
 import org.bedework.calfacade.filter.BwFilter;
@@ -50,6 +54,7 @@
 import org.bedework.calsvci.EventProperties;
 import org.bedework.calsvci.EventsI;
 import org.bedework.calsvci.EventProperties.EnsureEntityExistsResult;
+import org.bedework.icalendar.Icalendar;
 
 import edu.rpi.cmt.access.PrivilegeDefs;
 
@@ -162,12 +167,104 @@
   }
 
   /* (non-Javadoc)
-   * @see org.bedework.calsvci.EventsI#add(org.bedework.calfacade.BwCalendar, org.bedework.calfacade.svc.EventInfo, boolean)
+   * @see org.bedework.calsvci.EventsI#add(org.bedework.calfacade.BwCalendar, org.bedework.calfacade.svc.EventInfo, boolean, boolean, boolean)
    */
   public UpdateResult add(BwCalendar cal,
                           EventInfo ei,
+                          boolean noInvites,
+                          boolean scheduling,
                           boolean rollbackOnError) throws CalFacadeException {
-    return add(cal, ei, false, rollbackOnError);
+    if (cal == null) {
+      throw new CalFacadeException(CalFacadeException.noEventCalendar);
+    }
+
+    UpdateResult updResult = new UpdateResult();
+    BwEvent event = ei.getEvent();
+
+    validate(event);
+
+    if (event.getOrganizerSchedulingObject() ||
+        event.getAttendeeSchedulingObject()) {
+      event.setScheduleMethod(Icalendar.methodTypeRequest);
+
+      updResult.schedulingResult = doSchedule(ei, event.getScheduleMethod(),
+                                              true,
+                                              noInvites,
+                                              null);
+    }
+
+    Collection<BwEventProxy> overrides = ei.getOverrideProxies();
+    BwEventProxy proxy = null;
+    BwEvent override = null;
+
+    if (event instanceof BwEventProxy) {
+      proxy = (BwEventProxy)event;
+      override = proxy.getRef();
+      setupSharableEntity(override, getUser());
+    } else {
+      setupSharableEntity(event, getUser());
+    }
+
+    if (!cal.getOwner().equals(getUser())) {
+      /* This event is being added to another users calendar. Ensure we add any
+       * timezones the target user does not already own.
+       */
+
+      /*      CalTimezones ctz = getTimezones();
+
+        for (String tzid: event.getTimeZoneIds()) {
+
+        }*/
+    }
+
+    updateEntities(updResult, event);
+
+    /* If no calendar has been assigned for this event set it to the default
+     * calendar for non-public events or reject it for public events.
+     */
+
+    if (cal == null) {
+      if (event.getPublick()) {
+        throw new CalFacadeException("No calendar assigned");
+      }
+
+      cal = getSvc().getCalendarsHandler().getPreferred();
+    }
+
+    if (!cal.getCalendarCollection()) {
+      throw new CalFacadeAccessException();
+    }
+
+    event.setCalendar(cal);
+    /* All Overrides go in same calendar */
+
+    if (overrides != null) {
+      for (BwEventProxy ovei: overrides) {
+        ovei.getRef().setCalendar(cal);
+      }
+    }
+
+    event.setDtstamps();
+
+    assignGuid(event);
+
+    UpdateEventResult uer;
+
+    if (proxy != null) {
+      uer = getCal().addEvent(override, overrides, scheduling, rollbackOnError);
+    } else {
+      uer = getCal().addEvent(event, overrides, scheduling, rollbackOnError);
+    }
+
+    updResult.failedOverrides = uer.failedOverrides;
+
+    if (isPublicAdmin()) {
+      /* Mail event to any subscribers */
+    }
+
+    getSvc().getIndexingHandler().add(event);
+
+    return updResult;
   }
 
   /* (non-Javadoc)
@@ -242,7 +339,7 @@
     proxy.setOwner(getUser());
     proxy.setDeleted(true);
     proxy.setCalendar(cal);
-    add(cal, new EventInfo(proxy), false);
+    add(cal, new EventInfo(proxy), true, false, false);
   }
 
   /* (non-Javadoc)
@@ -294,20 +391,11 @@
         //deleteEvent(destEi.getEvent(), true);
       }
 
-      BwEvent newEvent = (BwEvent)from.clone();
-      newEvent.setName(name);
-      EventInfo newEi = new EventInfo(newEvent);
-
-      if (overrides != null) {
-        for (BwEventProxy proxy: overrides) {
-          newEi.addOverride(new EventInfo(proxy.clone(newEvent, newEvent)));
-        }
-      }
-
       if (!copy) {
         // Moving the event.
 
         if (!sameCal) {
+          /* Not sure why I was doing a delete+add
           delete(from, false, false); // Delete unreffed
 
           if (destEi != null) {
@@ -315,6 +403,9 @@
           }
 
           add(to, newEi, true);
+          */
+          from.setCalendar(to);
+          update(from, overrides, null);
         } else {
           // Just changing name
           from.setName(name);
@@ -323,6 +414,16 @@
       } else {
         // Copying the event.
 
+        BwEvent newEvent = (BwEvent)from.clone();
+        newEvent.setName(name);
+        EventInfo newEi = new EventInfo(newEvent);
+
+        if (overrides != null) {
+          for (BwEventProxy proxy: overrides) {
+            newEi.addOverride(new EventInfo(proxy.clone(newEvent, newEvent)));
+          }
+        }
+
         if (sameCal && newGuidOK) {
           // Assign a new guid
           newEvent.setUid(null);
@@ -333,7 +434,7 @@
           delete(destEi.getEvent(), false, false); // Delete unreffed
         }
 
-        add(to, newEi, true);
+        add(to, newEi, true, false, true);
       }
 
       if (destEi != null) {
@@ -392,93 +493,6 @@
     }
   }
 
-  UpdateResult add(BwCalendar cal,
-                   EventInfo ei,
-                   boolean scheduling,
-                   boolean rollbackOnError) throws CalFacadeException {
-    if (cal == null) {
-      throw new CalFacadeException(CalFacadeException.noEventCalendar);
-    }
-
-    UpdateResult updResult = new UpdateResult();
-    BwEvent event = ei.getEvent();
-
-    validate(event);
-
-    Collection<BwEventProxy> overrides = ei.getOverrideProxies();
-    BwEventProxy proxy = null;
-    BwEvent override = null;
-
-    if (event instanceof BwEventProxy) {
-      proxy = (BwEventProxy)event;
-      override = proxy.getRef();
-      setupSharableEntity(override, getUser());
-    } else {
-      setupSharableEntity(event, getUser());
-    }
-
-    if (!cal.getOwner().equals(getUser())) {
-      /* This event is being added to another users calendar. Ensure we add any
-       * timezones the target user does not already own.
-       */
-
-/*      CalTimezones ctz = getTimezones();
-
-      for (String tzid: event.getTimeZoneIds()) {
-
-      }*/
-    }
-
-    updateEntities(updResult, event);
-
-    /* If no calendar has been assigned for this event set it to the default
-     * calendar for non-public events or reject it for public events.
-     */
-
-    if (cal == null) {
-      if (event.getPublick()) {
-        throw new CalFacadeException("No calendar assigned");
-      }
-
-      cal = getSvc().getCalendarsHandler().getPreferred();
-    }
-
-    if (!cal.getCalendarCollection()) {
-      throw new CalFacadeAccessException();
-    }
-
-    event.setCalendar(cal);
-    /* All Overrides go in same calendar */
-
-    if (overrides != null) {
-      for (BwEventProxy ovei: overrides) {
-        ovei.getRef().setCalendar(cal);
-      }
-    }
-
-    event.setDtstamps();
-
-    assignGuid(event);
-
-    UpdateEventResult uer;
-
-    if (proxy != null) {
-      uer = getCal().addEvent(override, overrides, scheduling, rollbackOnError);
-    } else {
-      uer = getCal().addEvent(event, overrides, scheduling, rollbackOnError);
-    }
-
-    updResult.failedOverrides = uer.failedOverrides;
-
-    if (isPublicAdmin()) {
-      /* Mail event to any subscribers */
-    }
-
-    getSvc().getIndexingHandler().add(event);
-
-    return updResult;
-  }
-
   /** Return all keys or all with a lastmod greater than or equal to that supplied.
    *
    * <p>The lastmod allows us to redo the search after we have updated timezones
@@ -605,6 +619,25 @@
       throw new CalFacadeException(CalFacadeException.missingEventProperty,
                                    "recurring");
     }
+
+    BwOrganizer org = ev.getOrganizer();
+    String account = getSvc().getUser().getAccount();
+
+    if ((org != null) &&
+        getSvc().getDirectories().caladdrToUser(org.getOrganizerUri()).equals(account)) {
+      ev.setOrganizerSchedulingObject(true);
+    } else {
+      Collection<BwAttendee> atts = ev.getAttendees();
+
+      if ((atts != null) && !atts.isEmpty()) {
+        for (BwAttendee att: atts) {
+          if (getSvc().getDirectories().caladdrToUser(att.getAttendeeUri()).equals(account)) {
+            ev.setAttendeeSchedulingObject(true);
+            break;
+          }
+        }
+      }
+    }
   }
 
   private EventInfo postProcess(CoreEventInfo cei)
@@ -705,4 +738,141 @@
 
     return false;
   }
+
+  /** For adding the event we already have the scheduling method set. If we are
+   * updating the event then the action depends upon the new and old methods.
+   *
+   * <p>If we already cancelled the event then we do no scheduling. (What if we
+   * want to resend?)
+   *
+   * <p>If we want to refresh we just resend it.
+   *
+   * <p>If we want to cancel we send cancels.
+   *
+   * @param ei
+   * @param schedMethod - method caller asked for - only for updates. Event has
+   *                      the previous method.
+   * @param adding
+   * @param noInvites - suppresses the sending of invitations. Does NOT suppress the
+   *               sending of CANCEL to disinvited attendees
+   * @param deletedAttendees
+   * @return ScheduleResult or null for no scheduling action.
+   * @throws CalFacadeException
+   */
+  private ScheduleResult doSchedule(EventInfo ei,
+                                    int schedMethod,
+                                    boolean adding,
+                                    boolean noInvites,
+                                    Collection<BwAttendee> deletedAttendees)
+          throws CalFacadeException {
+    ScheduleResult sr = null;
+    BwEvent ev = ei.getEvent();
+
+    int meth = ev.getScheduleMethod();
+    if ((meth == Icalendar.methodTypeNone) ||   // Not a scheduling event
+        (meth == Icalendar.methodTypeCancel)) { /* We already canceled this one */
+      return null;
+    }
+
+    if (!ev.getOrganizerSchedulingObject() &&
+        !ev.getAttendeeSchedulingObject()) {
+      // Not a scheduling event
+      return null;
+    }
+
+    boolean reconfirm = false;
+
+    if (ei.getReplyAttendeeURI() != null) {
+      // Doing a reconfirm or REFRESH
+      reconfirm = true;
+    } else if (schedMethod == Icalendar.methodTypeRefresh) {
+      schedMethod = Icalendar.methodTypeRequest;
+      reconfirm = true;
+    }
+
+    if (ev.getOrganizer() == null) {
+      throw new CalFacadeBadRequest(CalFacadeException.missingEventProperty);
+    }
+
+    // Ensure we have an originator for ischedule
+
+    if (ev.getOriginator() == null) {
+      ev.setOriginator(ev.getOrganizer().getOrganizerUri());
+    }
+
+    if (schedMethod == Icalendar.methodTypeCancel) {
+      ev.setScheduleMethod(schedMethod);
+    } else if (schedMethod == Icalendar.methodTypeRequest) {
+      if (reconfirm) {
+        ev.setIncSequence(true);
+      }
+
+      if (!adding &&
+          (ev.getScheduleMethod() != Icalendar.methodTypeRequest)) {
+        /* Reset some fields? */
+        ev.setSequence(0);
+        ev.setIncSequence(false);
+      }
+
+      ev.setScheduleMethod(schedMethod);
+    } else if (schedMethod == Icalendar.methodTypePublish) {
+      if (!adding &&
+          (ev.getScheduleMethod() != Icalendar.methodTypePublish)) {
+        /* Reset some fields? */
+        ev.setSequence(0);
+        ev.setIncSequence(false);
+      }
+
+      ev.setScheduleMethod(schedMethod);
+    } else if (reconfirm) {
+      ev.setIncSequence(true);
+    }
+
+    if (ev.getIncSequence()) {
+      ev.setSequence(ev.getSequence() + 1);
+      ev.updateDtstamp();
+      ev.setIncSequence(false);
+    }
+
+    if (!noInvites) {
+      sr = getSvc().getScheduler().schedule(ei, ei.getReplyAttendeeURI(), true);
+    }
+
+    if (!adding && !CalFacadeUtil.isEmpty(deletedAttendees)) {
+      /* Send cancel to removed attendees */
+      for (BwAttendee att: deletedAttendees) {
+        BwEvent cncl = (BwEvent)ev.clone();
+
+        cncl.setAttendees(null);
+        cncl.addAttendee(att);
+
+        cncl.setRecipients(null);
+        cncl.addRecipient(att.getAttendeeUri());
+
+        cncl.setScheduleMethod(Icalendar.methodTypeCancel);
+        cncl.setOrganizerSchedulingObject(true);
+
+        ei.setEvent(cncl);
+
+        ScheduleResult cnclr = getSvc().getScheduler().schedule(ei, null, true);
+        if (debug) {
+          trace(cnclr.toString());
+        }
+      }
+    }
+
+    if (ei.getInboxEventName() != null) {
+      // Delete the given event from the inbox.
+      BwCalendar inbox = getSvc().getCalendarsHandler().getSpecial(BwCalendar.calTypeInbox, true);
+      RecurringRetrievalMode rrm =
+        new RecurringRetrievalMode(Rmode.overrides);
+      EventInfo inboxei = get(inbox, ei.getInboxEventName(), rrm);
+
+      if (inboxei != null) {
+        delete(inboxei.getEvent(), true, true); // Delete unreffed
+      }
+    }
+
+    return sr;
+  }
 }

Modified: trunk/calsvc/src/org/bedework/calsvc/Scheduling.java
===================================================================
--- trunk/calsvc/src/org/bedework/calsvc/Scheduling.java	2008-10-01 03:33:10 UTC (rev 716)
+++ trunk/calsvc/src/org/bedework/calsvc/Scheduling.java	2008-10-02 13:52:33 UTC (rev 717)
@@ -270,7 +270,7 @@
   }
 
   /* (non-Javadoc)
-   * @see org.bedework.calsvci.SchedulingI#attendeeRespond(org.bedework.calfacade.BwEvent, org.bedework.calfacade.BwCalendar, java.lang.String, java.lang.String, java.lang.String, org.bedework.calfacade.BwCalendar, java.lang.String, boolean)
+   * @see org.bedework.calsvci.SchedulingI#attendeeRespond(org.bedework.calfacade.svc.EventInfo, java.lang.String, java.lang.String, java.lang.String, java.lang.String, boolean, org.bedework.calfacade.BwCalendar, org.bedework.calfacade.BwCalendar)
    */
   public ScheduleResult attendeeRespond(EventInfo ei,
                                         String delegate,
@@ -279,7 +279,7 @@
                                         String comment,
                                         boolean rsvp,
                                         BwCalendar newCal,
-                                        Collection<BwCalendar> eventCals) throws CalFacadeException {
+                                        BwCalendar eventCal) throws CalFacadeException {
     ScheduleResult sr = new ScheduleResult();
     BwEvent ev = ei.getEvent();
     BwEventProxy proxy = null;
@@ -340,13 +340,6 @@
       outEv.addComment(null, comment);
     }
 
-    //String cuAddr = svci.getDirectories().userToCaladdr(cu.getAccount());
-    //BwAttendee att = outEv.findAttendee(cuAddr);
-    //if (att == null) {
-    //  sr.errorCode = CalFacadeException.schedulingUnknownAttendee;
-    //  return sr;
-    //}
-
     outEv.setRecipients(new TreeSet<String>());
     outEv.addRecipient(outEv.getOriginator());
     outEv.setOriginator(att.getAttendeeUri());
@@ -462,7 +455,7 @@
     sr = scheduleResponse(outEi);
     outEv.setScheduleState(BwEvent.scheduleStateProcessed);
 
-    if (!updateScheduleCalendar(newCal, eventCals, ei, att, sr, 0)) {
+    if (!updateScheduleCalendar(newCal, eventCal, ei, att, sr, 0)) {
       return sr;
     }
 
@@ -508,10 +501,10 @@
   }
 
   /* (non-Javadoc)
-   * @see org.bedework.calsvci.SchedulingI#processResponse(org.bedework.calfacade.BwEvent, org.bedework.calfacade.BwCalendar)
+   * @see org.bedework.calsvci.SchedulingI#processResponse(org.bedework.calfacade.svc.EventInfo, org.bedework.calfacade.BwCalendar)
    */
   public ScheduleResult processResponse(EventInfo ei,
-                                        Collection<BwCalendar> eventCals) throws CalFacadeException {
+                                        BwCalendar eventCal) throws CalFacadeException {
     ScheduleResult sr = new ScheduleResult();
     BwEvent ev = ei.getEvent();
 
@@ -546,7 +539,7 @@
       return sr;
     }
 
-    if (!updateScheduleCalendar(null, eventCals, ei, att, sr, 0)) {
+    if (!updateScheduleCalendar(null, eventCal, ei, att, sr, 0)) {
       return sr;
     }
 
@@ -556,12 +549,9 @@
     return sr;
   }
 
-  /* (non-Javadoc)
-   * @see org.bedework.calsvci.SchedulingI#processCancel(org.bedework.calfacade.BwEvent, int, java.util.Collection)
-   */
   public ScheduleResult processCancel(EventInfo ei,
                                      int action,
-                                     Collection<BwCalendar> eventCals) throws CalFacadeException {
+                                     BwCalendar eventCal) throws CalFacadeException {
     ScheduleResult sr = new ScheduleResult();
     BwEvent ev = ei.getEvent();
     BwCalendar inbox = ev.getCalendar();
@@ -581,7 +571,7 @@
       return sr;
     }
 
-    if (!updateScheduleCalendar(null, eventCals, ei, null, sr, action)) {
+    if (!updateScheduleCalendar(null, eventCal, ei, null, sr, action)) {
       return sr;
     }
 
@@ -952,22 +942,38 @@
   }
 
   /* (non-Javadoc)
-   * @see org.bedework.calsvci.SchedulingI#getMeetingCalendars(org.bedework.calfacade.BwEvent)
+   * @see org.bedework.calsvci.SchedulingI#getMeetingCalendar(org.bedework.calfacade.BwEvent)
    */
-  public Collection<BwCalendar> getMeetingCalendars(BwEvent ev) throws CalFacadeException {
-    Collection<BwCalendar> cals = getSvc().getEventsHandler().findCalendars(ev.getUid(),
-                                                                            null);
-                                                     //ev.getRecurrenceId());
+  public BwCalendar getMeetingCalendar(BwEvent ev) throws CalFacadeException {
+    RecurringRetrievalMode rrm = new RecurringRetrievalMode(RecurringRetrievalMode.Rmode.masterOnly);
 
-    ArrayList<BwCalendar> evCals = new ArrayList<BwCalendar>();
+    Collection<EventInfo> evs = getSvc().getEventsHandler().get(null,
+                                                                ev.getUid(),
+                                                                null,
+                                                                rrm);
 
-    for (BwCalendar cal: cals) {
-      if (cal.getCalType() == BwCalendar.calTypeSchedulingCollection) {
-        evCals.add(cal);
+    if ((evs == null) || (evs.isEmpty())) {
+      return null;
+    }
+
+    /* Return the active meeting calendar */
+
+    for (EventInfo ei: evs) {
+      BwEvent e = ei.getEvent();
+      if (e.getOrganizerSchedulingObject() || e.getAttendeeSchedulingObject()) {
+        // These chacks should not be needed
+        BwCalendar evCal = e.getCalendar();
+
+        if (evCal.getCalType() != BwCalendar.calTypeSchedulingCollection) {
+          warn("Active meeting in invalid collection: " + evCal);
+        } else {
+          return evCal;
+        }
       }
     }
 
-    return evCals;
+    // Not found.
+    return null;
   }
 
   /* (non-Javadoc)
@@ -1157,8 +1163,18 @@
                                     ScheduleResult sr) throws CalFacadeException {
     Collection<String> recipients = event.getRecipients();
     if ((recipients == null) || recipients.isEmpty()) {
-      sr.errorCode = CalFacadeException.schedulingNoRecipients;
-      return false;
+      /* Set them up from the recipients. */
+      for (BwAttendee att: event.getAttendees()) {
+        String uri = att.getAttendeeUri();
+
+        if (uri.toLowerCase().startsWith("mailto:")) {
+          uri = uri.substring(7);
+        }
+
+        event.addRecipient(uri);
+      }
+      //sr.errorCode = CalFacadeException.schedulingNoRecipients;
+      //return false;
     }
 
     setupSharableEntity(event, getUser());
@@ -1501,7 +1517,7 @@
 
     ev.setScheduleState(BwEvent.scheduleStateNotProcessed);
 
-    ((Events)getSvc().getEventsHandler()).add(ui.inbox, ei, true, false);
+    ((Events)getSvc().getEventsHandler()).add(ui.inbox, ei, true, true, false);
   }
 
   /*
@@ -1635,6 +1651,7 @@
       loc = (BwLocation)loc.clone();
       loc.setOwner(owner);
       loc.setCreator(owner);
+      loc.initUid();
       newEv.setLocation(loc);
     }
 
@@ -1643,6 +1660,7 @@
       contact = (BwContact)contact.clone();
       contact.setOwner(owner);
       contact.setCreator(owner);
+      contact.initUid();
       newEv.setContact(contact);
     }
 
@@ -1671,14 +1689,12 @@
     return newEv;
   }
 
-  /* Add the event to newcal or update the copies in eventCals
+  /* Add the event to newcal or update the copy in eventCal
    *
-   * action is for cancels only
-   *
    * reply is true if we are processing a reply from an attendee
    */
   private boolean updateScheduleCalendar(BwCalendar newCal,
-                                         Collection<BwCalendar> eventCals,
+                                         BwCalendar eventCal,
                                          EventInfo ei,
                                          BwAttendee att,
                                          ScheduleResult sr,
@@ -1697,7 +1713,7 @@
       }
 
       try {
-        getSvc().getEventsHandler().add(newCal, calEi, false);
+        getSvc().getEventsHandler().add(newCal, calEi, true, false, false);
       } catch (CalFacadeException cfe) {
         if (CalFacadeException.duplicateGuid.equals(cfe.getMessage())) {
           sr.errorCode = CalFacadeException.schedulingDuplicateUid;
@@ -1711,96 +1727,87 @@
       return true;
     }
 
-    if ((eventCals == null) || eventCals.isEmpty()) {
+    if (eventCal == null) {
+      // Bad request?
       return true;
     }
 
-    /* Update the copies in the given calendars. Ignore the inbox copy.
+    /* Update the copy in the given calendar. Ignore the inbox copy.
      */
 
     // DORECUR is this right?
     RecurringRetrievalMode rrm = new RecurringRetrievalMode(Rmode.overrides);
 
-    Collection<EventInfo> evs = new TreeSet<EventInfo>();
     BwEvent ev = ei.getEvent();
 
-    for (BwCalendar eventCal: eventCals) {
-      evs.addAll(getSvc().getEventsHandler().get(eventCal, ev.getUid(),
-                               ev.getRecurrenceId(), rrm));
-    }
+    Collection<EventInfo> evs = getSvc().getEventsHandler().get(eventCal, ev.getUid(),
+                               ev.getRecurrenceId(), rrm);
 
-    if (evs.size() == 0) {
+    if (evs.size() != 1) {
       sr.errorCode = CalFacadeException.schedulingUnknownEvent;
 
       return true;
     }
 
-    for (EventInfo calEi: evs) {
-      BwEvent calEv = calEi.getEvent();
+    BwEvent calEv = evs.iterator().next().getEvent();
 
-      if (ev.equals(calEv) || // The inbox event
-         (calEv.getCalendar().getCalType() != BwCalendar.calTypeSchedulingCollection)) {
-        continue;
-      }
+    if (ev.getScheduleMethod() == Icalendar.methodTypeReply) {
+      /* Update the participation status from the incoming attendee */
 
-      if (ev.getScheduleMethod() == Icalendar.methodTypeReply) {
-        /* Update the participation status from the incoming attendee */
-
-        BwAttendee outAtt = calEv.findAttendee(att.getAttendeeUri());
-        if (outAtt == null) {
-          if (debug) {
-            trace("Not an attendee of " + calEv);
-          }
-          sr.errorCode = CalFacadeException.schedulingUnknownAttendee;
-          sr.extraInfo = att.getAttendeeUri();
-          return false;
+      BwAttendee outAtt = calEv.findAttendee(att.getAttendeeUri());
+      if (outAtt == null) {
+        if (debug) {
+          trace("Not an attendee of " + calEv);
         }
+        sr.errorCode = CalFacadeException.schedulingUnknownAttendee;
+        sr.extraInfo = att.getAttendeeUri();
+        return false;
+      }
 
-        //att.copyTo(outAtt);
-        // Replace or we update all recurring instances.
-        calEv.removeAttendee(att);
-        calEv.addAttendee((BwAttendee)att.clone());
-      } else if (ev.getScheduleMethod() == Icalendar.methodTypeRequest) {
-        // We are the attendee - update our copy
-        // XXX We need some way of determining what changes were made - a
-        // change list?
-        calEv.updateFrom(ev);
+      //att.copyTo(outAtt);
+      // Replace or we update all recurring instances.
+      calEv.removeAttendee(att);
+      calEv.addAttendee((BwAttendee)att.clone());
+    } else if (ev.getScheduleMethod() == Icalendar.methodTypeRequest) {
+      // We are the attendee - update our copy
+      // XXX We need some way of determining what changes were made - a
+      // change list?
+      calEv.updateFrom(ev);
 
-        CalFacadeUtil.updateCollection(ev.getAttendees(), calEv.getAttendees());
+      CalFacadeUtil.updateCollection(ev.getAttendees(), calEv.getAttendees());
 
-        /*
+      /*
         for (BwAttendee calAtt: calEv.getAttendees()) {
           if (calAtt.equals(att)) {
             att.copyTo(calAtt);
             break;
           }
         }*/
-        if (calEv.getAttendees().contains(att)) {
-          calEv.removeAttendee(att);
-          calEv.addAttendee((BwAttendee)att.clone());
-        }
-      } else if (ev.getScheduleMethod() == Icalendar.methodTypeCancel) {
-        if (action == BwPreferences.scheduleAutoCancelDelete) {
-          getSvc().getEventsHandler().delete(calEv, true, true); // Delete unreffed
-        } else if (action == BwPreferences.scheduleAutoCancelSetStatus) {
-          calEv.setStatus(BwEvent.statusCancelled);
-          getSvc().getEventsHandler().update(calEv, null, null);
-        } else {
-          sr.errorCode = CalFacadeException.schedulingBadAction;
-          return false;
-        }
+      if (calEv.getAttendees().contains(att)) {
+        calEv.removeAttendee(att);
+        calEv.addAttendee((BwAttendee)att.clone());
+      }
+    } else if (ev.getScheduleMethod() == Icalendar.methodTypeCancel) {
+      if (action == BwPreferences.scheduleAutoCancelDelete) {
+        getSvc().getEventsHandler().delete(calEv, true, true); // Delete unreffed
+      } else if (action == BwPreferences.scheduleAutoCancelSetStatus) {
+        calEv.setStatus(BwEvent.statusCancelled);
+        getSvc().getEventsHandler().update(calEv, null, null);
       } else {
+        sr.errorCode = CalFacadeException.schedulingBadAction;
+        return false;
       }
+    } else {
+    }
 
-      // XXX Ensure no name change
-      if (calEv instanceof BwEventProxy) {
-        BwEventProxy pr = (BwEventProxy)calEv;
+    // XXX Ensure no name change
+    if (calEv instanceof BwEventProxy) {
+      BwEventProxy pr = (BwEventProxy)calEv;
 
-        BwEventAnnotation ann = pr.getRef();
-        ann.setName(null);
-      }
-      getSvc().getEventsHandler().update(calEv, null, null);
+      BwEventAnnotation ann = pr.getRef();
+      ann.setName(null);
     }
+    getSvc().getEventsHandler().update(calEv, null, null);
 
     return true;
   }
@@ -1816,7 +1823,8 @@
     /* Make up a unique name for the event. */
     event.setName("Out-" + CalFacadeUtil.getUid() + ".ics");
 
-    /*UpdateResult eur =*/ getSvc().getEventsHandler().add(outBox, outEi, false);
+    /*UpdateResult eur =*/ getSvc().getEventsHandler().add(outBox, outEi,
+                                                           true, false, false);
   //} else {
     // Keep a record in the Outbox
     //event.setScheduleState(BwEvent.scheduleStateExternalDone);

Modified: trunk/calsvci/src/org/bedework/calsvci/EventsI.java
===================================================================
--- trunk/calsvci/src/org/bedework/calsvci/EventsI.java	2008-10-01 03:33:10 UTC (rev 716)
+++ trunk/calsvci/src/org/bedework/calsvci/EventsI.java	2008-10-02 13:52:33 UTC (rev 717)
@@ -30,6 +30,7 @@
 import org.bedework.calfacade.BwEvent;
 import org.bedework.calfacade.BwEventProxy;
 import org.bedework.calfacade.RecurringRetrievalMode;
+import org.bedework.calfacade.ScheduleResult;
 import org.bedework.calfacade.exc.CalFacadeException;
 import org.bedework.calfacade.filter.BwFilter;
 import org.bedework.calfacade.svc.EventInfo;
@@ -182,36 +183,48 @@
 
     /** null or overrides that didn't get added */
     public Collection<BwEventProxy> failedOverrides;
+
+    /** Non-null if the object we added was a scheduling object and
+     * resulted in some scheduling operations.
+     */
+    public ScheduleResult schedulingResult;
   }
 
-  /** Add an event and ensure its location and sponsor exist.
+  /** Add an event and ensure its location and contact exist.
    *
    * <p>For public events some calendar implementors choose to allow the
-   * dynamic creation of locations and sponsors. For each of those, if we have
+   * dynamic creation of locations and contacts. For each of those, if we have
    * an id, then the object represents a preexisting database item.
    *
    * <p>Otherwise the client has provided information which will be used to
-   * locate an already existing location or sponsor. Failing that we use the
+   * locate an already existing location or contact. Failing that we use the
    * information to create a new entry.
    *
-   * <p>For user clients, we generally assume no sponsor and the location is
+   * <p>For user clients, we generally assume no contact and the location is
    * optional. However, both conditions are enforced at the application level.
    *
    * <p>On return the event object will have been updated. In addition the
-   * location and sponsor may have been updated.
+   * location and contact may have been updated.
    *
+   * <p>If this is a scheduling event and noInvites is set to false then
+   * invitations wil be sent out to the attendees.
+   *
    * <p>The event to be added may be a reference to another event. In this case
    * a number of fields should have been copied from that event. Other fields
    * will come from the target.
    *
    * @param cal          BwCalendar defining recipient calendar
    * @param ei           EventInfo object to be added
+   * @param noInvites    True for don't send invitations.
+   * @param scheduling   True if this is for an incoming scheduling request
    * @param rollbackOnError
    * @return UpdateResult Counts of changes.
    * @throws CalFacadeException
    */
   public UpdateResult add(BwCalendar cal,
                           EventInfo ei,
+                          boolean noInvites,
+                          boolean scheduling,
                           boolean rollbackOnError) throws CalFacadeException;
 
   /** Update an event.

Modified: trunk/calsvci/src/org/bedework/calsvci/SchedulingI.java
===================================================================
--- trunk/calsvci/src/org/bedework/calsvci/SchedulingI.java	2008-10-01 03:33:10 UTC (rev 716)
+++ trunk/calsvci/src/org/bedework/calsvci/SchedulingI.java	2008-10-02 13:52:33 UTC (rev 717)
@@ -94,7 +94,7 @@
    * @param comment  String comment from attendee
    * @param rsvp   true if user wants to be notified
    * @param newCal  calendar to place event in or null
-   * @param eventCals - if non-null where we have a copy or copies of the meeting
+   * @param eventCal - if non-null where we already have the meeting stored
    * @return   ScheduleResult
    * @throws CalFacadeException
    */
@@ -105,7 +105,7 @@
                                         String comment,
                                         boolean rsvp,
                                         BwCalendar newCal,
-                                        Collection<BwCalendar> eventCals) throws CalFacadeException;
+                                        BwCalendar eventCal) throws CalFacadeException;
 
   /** An attendee wishes to update a meeting, e.g. they wish to change their
    * participation status.
@@ -118,31 +118,31 @@
 
   /** Handle replies to scheduling requests - that is the schedule
    * method was REPLY. We, as an organizer (or their delegate) are going to
-   * use the reply to update the original invitation and any copies.
+   * use the reply to update the original invitation.
    *
    * @param ei - the incoming event in the inbox
-   * @param eventCals - if non-null where we have a copy or copies of the meeting
+   * @param eventCal - if non-null where we have a copy or copies of the meeting
    * @return ScheduleResult showing how things went.
    * @throws CalFacadeException
    */
   public ScheduleResult processResponse(EventInfo ei,
-                                        Collection<BwCalendar> eventCals) throws CalFacadeException;
+                                        BwCalendar eventCal) throws CalFacadeException;
 
-  /** The organizer has cancelled the meeting - or taken us (the attendee) off
+  /** The organizer has canceled the meeting - or taken us (the attendee) off
    * the list.
    *
    * <p>We will look for the event in the users calendar(s) and either remove it
-   * or set the status to cancelled.
+   * or set the status to canceled.
    *
    * @param ei            EventInfo object with method=CANCEL
    * @param action        Value from BwPreferences
-   * @param eventCals - if non-null where we have a copy or copies of the meeting
+   * @param eventCal - if non-null where we have a copy of the meeting
    * @return ScheduleResult
    * @throws CalFacadeException
    */
   public ScheduleResult processCancel(EventInfo ei,
                                       int action,
-                                      Collection<BwCalendar> eventCals) throws CalFacadeException;
+                                      BwCalendar eventCal) throws CalFacadeException;
 
   /** Respond to a scheduling request. The event object must have the organizer
    * and a single attendee and possibly recipient set according to itip + caldav.
@@ -366,14 +366,14 @@
                                                 BwDateTime end,
                                                 BwDuration granularity) throws CalFacadeException;
 
-  /** Return this users calendars containing copies of the meetings with the
+  /** Return the users calendar collection containing the active meeting with the
    * same uid as that given.
    *
    * @param ev
-   * @return possibly empty Collection of calendars excluding the inbox
+   * @return possibly null calendar collection
    * @throws CalFacadeException
    */
-  public Collection<BwCalendar> getMeetingCalendars(BwEvent ev) throws CalFacadeException;
+  public BwCalendar getMeetingCalendar(BwEvent ev) throws CalFacadeException;
 
   /** Find the attendee in this event which corresponds to the current user
    *



More information about the Bedework-commit mailing list