//////////////////////////////////////////////////////////////////////
// DATETIME Elements are specified as follows:
//
//
// <s DATETIME> means:
//
// <s d="YYYYMMDD['T'HHMMSS[Z]]" [tz="timezone_identifier"]>
//
//    YYYY - 4 digit year
//    MM   - 2 digit month
//    DD   - 2 digit day
//  Optionally:
//    'T' the literal char "T" then
//    HH - 2 digit hour (00-23)
//    MM - 2 digit minute (00-59)
//    SS - 2 digit second (00-59)
//    ...and finally an optional "Z" meaning that the time is UTC,
//    otherwise the tz="TIMEZONE" param MUST be specified with the DATETIME
//
// e.g:
//     20050612  June 12, 2005
//     20050315T18302305Z  March 15, 2005 6:30:23.05 PM UTC
//
//
// tz="java timezone identifier" (see list at bottom of this file!)
//
//
// NOTE: if DATETIME has a time component (after the 'T') then it must either be specified
// in UTC (has a trailing 'Z') or else the tz= MUST be specified!!!
//

//////////////////////////////////////////////////////////////////////
// "DURATION" element  (specified-duration)
//
//  <dur [neg="1|0"] [w="weeks"] [d="days"] [h="hours"] [m="mins"] [s="secs"]>
//
// Special note: if WEEKS are specified, NO OTHER OFFSET MAY BE
// SPECIFIED (weeks must be alone, per RFC2445)
//


//////////////////////////////////////////////////////////////////////
//
// CREATEAPPOINTMENT
// -----------------
//    This is the API to create a new Appointment, optionally  sending out
//  meeting Invitations to other people.
//
<CreateAppointmentRequest>
  <m f="{flags}" l="{folder}">  // See soap.txt for complete list of attrs on <m>
     [<e .../>*]  // users to send request to
     <su>{subject}</su>

     <inv [uid="uid-for-create"]>  // optional: client can request the UID to use
       [                            // Time zone components define the time zones referenced in the
                                    // rest of the <inv>, for start/end times and recurrence rules.
                                    // Time zones defined in the LDAP server don't need to be defined
                                    // here, but all custom time zones must be defined before being
                                    // referenced.
       <tz
           id="timezonename"        // this name is referenced in various DATETIME data in the rest of <inv>
           stdoff="<minutes>"       // offset from UTC in standard time; local = UTC + offset
           [dayoff="<minutes>"]     // offset from UTC in daylight time; present only if DST is used
       >
           [                        // If daylight savings time is not used, <standard> and <daylight> must be
                                    // omitted.  If DST is used, both <standard> and <daylight> must be present.
           <standard                // time/rule for transitioning from daylight time to standard time
                                    // Either specify week/wkday combo, or mday.
               [
               week="<number>"        // week number; 1=first, 2=second, 3=third, 4=fourth, -1=last
               wkday="<number>"       // day of week; 1=Sunday, 2=Monday, etc.
               ]
               mon="<number>"         // month; 1=January, 2=February, etc.
               [mday="<number>"]      // day of month (1..31)
               hour="<number>"        // transition hour (0..23)
               min="<number>"         // transition minute (0..59)
               sec="<number>"         // transition second; 0..59, usually 0
           />
           <daylight                // time/rule for transitioning from standard time to daylight time
               [
               week="<number>"
               wkday="<number>"
               ]
               mon="<number>"
               [mday="<number>"]
               hour="<number>"
               min="<number>"
               sec="<number>"
           />
           ]?
       </tz>
       ]*  // always present in responses; optional in requests if all TZs used
           // in <inv> are defined in LDAP
       [
       <comp
            [status="TENT|CONF|CANC|NEED|COMP|INPR|WAITING|DEFERRED"]
                            // TENTative, CONFirmed, CANCelled, COMPleted,
                            // INPRocess, WAITING, DEFERRED
                            // Waiting and Deferred are custom values not found
                            // in iCalendar spec.
            [fb="F|B|T|O"]  // free-busy status:
                               Free, Busy (default), busy-Tentative, OutOfOffice (busy-unavailable)
            fba="F|B|T|O" // the "actual" free-busy status of this invite (ie what the client should display) -- this is synthesized taking into account our Attendee's PartStat, the Opacity of the appointment, its Status, etc...
            [transp="O|T"]  // transparency: Opaque (default) or Transparent
            [allDay="1|0"]
            [name="NAME"]
            [loc="LOCATION"]
            [isOrg="0|1"]		// Am I the organizer?  (default = 0)
            [seq="num"]         // sequence number (default = 0)
            [priority="num"]    // priority (0 - 9; default = 0)
            [percentComplete="num (integer)"]  // percent complete for VTODO (0 - 100; default = 0)
            [completed="yyyyMMddThhmmssZ"]  // VTODO COMPLETED DATE-TIME
        >

           [<replies>
              [<reply d="TIMESTAMP_OF_REPLY"
                      at="foo@bar.com"
                      ptst="AC|DE|TE|NE"
                      rangeType="1"
                      recurId="YYMMDD[THHMMSS[Z]]"
                      tz="timezonename"/>]*
           </replies>] // one or more replies which we have sent out
           
           <s DATETIME> // Start date-time (required)

           (
              <e DATETIME> // End date-time
              OR
              <dur DURATION>   //<dur [neg="1|0"] [w="weeks"] [d="days"] [h="hours"] [m="mins"] [s="secs"]>  
           )   // one is required

//           [ <desc>DESCRIPTION</desc> ]? // Will use message FRAGMENT if not specified

           // organizer
           <or a="address"         // email address (without "MAILTO:")
               d="friendly name"   // CN in iCalendar
               [sentBy="sent-by"]  // SENT-BY
               [dir="dir"]         // DIR
               [lang="language"]   // LANGUAGE (e.g. "en-US")
           />
           // attendee(s)
           <at a="address"                  // email address (without "MAILTO:")
               d="friendly name"            // CN in iCalendar
               [sentBy="sent-by"]           // SENT-BY
               [dir="dir"]                  // DIR
               [lang="language"]            // LANGUAGE (e.g. "en-US")
               role="ROLE"                  // ROLE
               ptst="participation status"  // PARTSTAT
               [rsvp="0|1"]                 // RSVP
               [cutype="CUTYPE"]            // CUTYPE
               [member="MEMBER"]            // MEMBER
               [delTo="delegated to"]       // DELEGATED-FROM
               [delFrom="delegated from"]   // DELEGATED-TO
           />*
             // role = CHAir, REQuired, OPTional, NON-participant (ie informational)
             // ptst (ParTSTat - participation status) = "NE"eds-action, "TE"ntative, "AC"cept, "DE"clined,
             // "DG" (delegated), "CO"mpleted (todo), "IN"-process (todo),
             // "WA"iting (custom value only for todo), "DF" (deferred; custom value only for todo)
             // cutype (calendar user type) = INDividual, GROup, RESource, ROOm, UNKnown
             // sentBy, member, delTo and delFrom values are email addresses

           [ <alarm rel-start="RELATIVE_TIME_POSITIVE_MEANS_BEFORE"/> ]*

           [
             <recur>  // see below
                [ <add|exclude>
                    [ <rule freq="FREQ"
                         // FREQ: SEC,MIN,HOU,DAI,WEE,MON,YEA

                      [
                        <until d="YYYYMMDD[ThhmmssZ]/> // UNTIL *MUST* be Date value or DateTime in UTC w/ trailing 'Z' 
                               OR
                        <count num="COUNT"/> // count of instances to generate
                      ]? // optional UNTIL or COUNT param

                      
                      [  // each of the following can occur at most once
                        <interval ival="COUNT"/>                  // COUNT: positive integer
                        <bysecond seclist="second[,second...]"/>  // second: 0 to 59
                        <byminute minlist="minute[,minute...]"/>  // minute: 0 to 59
                        <byhour hrlist="hour[,hour...]"/>         // hour: 0 to 23
                        <byday>
                          <wkday [ordwk="[[+]|-]num"] day="WEEKDAY"/>  // num: 1 to 53, WEEKDAY: SU,MO,TU,WE,TH,FR,SA
                          [<wkday>...]
                        </byday>
                            // e.g. <byday>
                            //        <wkday day="MO"/>
                            //        <wkday ordwk="3" day="TU"/>
                            //        <wkday ordwk="+4" day="WE"/>
                            //        <wkday ordwk="-1" day="SU"/>
                            //      </byday>
                            //
                            // means every Monday of the year,
                            // plus Tuesday of 3rd week of the year,
                            // plus Wednesday of 4th week,
                            // plus Sunday of last week of the year.
                        <bymonthday modaylist="[[+]|-]num[,...]"/>   // num: 1 to 31
                            // e.g. <bymonthday modaylist="1,+2,-7"/>
                            // means first day of the month, plus the 2nd day of the month,
                            // plus the 7th from last day of the month.
                        <byyearday yrdaylist="[[+]|-]num[,...]"/>    // num: 1 to 366
                            // e.g. <byyearday yrdaylist="1,+2,-1"/>
                            // means January 1st, January 2nd, and December 31st.
                        <byweekno wklist="[[+]|-]num[,...]"/>   // num: 1 to 53
                            // e.g. <byweekno wklist="1,+2,-1"/>
                            // means first week, 2nd week, and last week of the year.
                        <bymonth molist="month[,month...]"/>      // month: 1 to 12
                        <bysetpos poslist="[[+]|-]num[,...]"/>    // poslist: 1 to 366
                            // <bysetpos> MUST only be used in conjunction with another
                            // <byXXX> element.
                        <wkst day="WEEKDAY"/>  // WEEKDAY: SU,MO,TU,WE,TH,FR,SA
                      ]*
                      [
                        <x-name name="NAME" value="VALUE"/>  // custom fields
                      ]*
                    </rule>]*

					// RDATE/EXDATE
                    [ <dates [tz="TZID"]>
                        // Start DATE-TIME only.  Instance has same duration as
                        // the default duration.
                        // RDATE[;VALUE=DATE-TIME][;TZID=...]:val,val,val,...
                        <dtval>
                          <s d="YYYYMMDDThhmmss[Z]"/>
                        </dtval>*
                      </dates>
                    ]*
                    [ <dates [tz="TZID"]>
                        // Start DATE only. (all-day)  Instance has same
                        // duration as the default duration.
                        // RDATE;VALUE=DATE[;TZID=...]:val,val,val,...
                        <dtval>
                          <s d="YYYYMMDD"/>
                        </dtval>*
                      </dates>
                    ]*
                    [ <dates [tz="TZID"]>
                        // Start date/time and either end date/time or duration.
                        // Only DATE-TIME format is allowed for start/end.
                        // This format is allowed in <add> only, but not in
                        // <exclude>.
                        // RDATE;VALUE=PERIOD[;TZID=...]:val,val,val,...
                        <dtval>
                          <s d="YYYYMMDDThhmmss[Z]"/>
                          <e d="YYYYMMDDThhmmss[Z]"/> OR <dur ...>
                        </dtval>*
                      </dates>
                    ]*
                  </add|/exclude>

                  ////////////
                  //
                  // These next two (<except> and <cancel>) are only valid for APIs that deal with the
                  // entire appointment such as SetAppointment and GetAppointment: they are IGNORED by
                  // other APIs. 
                  [
                    <except recurId="INSTANCE_START_SECS_GMT" rangeType="RANGETYPE">
                      <add|exclude>
                        ...SAME AS ABOVE...
                      </add|/exclude>      
                    </except>
                  ]*
                  [
                    <cancel recurId="INSTANCE_START_SECS_GMT" rangeType="RANGETYPE"/>
                  ]*
                ]*
             </recur>
           ]
           [
             // non-standard properties (see RFC2445 section 4.8.8.1)
             // e.g.
             // iCalendar:
             //
             //   X-FOO-HELLO;X-FOO-WORLD=world:hello
             //
             // SOAP:
             //
             //   <xprop name="X-FOO-HELLO" value="hello">
             //     <xparam name="X-FOO-WORLD" value="world"/>
             //   </xprop>
             <xprop name="x-name" [value="text"]>
               [<xparam name="x-name" [value="text"]/>]*
             </xprop>
           ]*
        </comp>
        ]+     
     </inv>
     <mp>...</mp>
     [<content (url="{url}")>...</content>]
   </m>
</CreateAppointmentRequest>


// CREATING EXCEPTIONS
// --------------------
//
// Just like CreateAppointment, except that instead of specifying a target FOLDER, you
// specify an existing PID and component-number
//
// *** If id= and comp= are set, then you are creating an EXCEPTION:
//
//   The default invite for the appointment MUST have a recurrence rule....
//      otherwise you should just be using ModifyAppointment!
//
//   EXCEPTION_ID is start-time for the particular instance you are overriding
//     EXCEPTION_ID MUST be some instance that matches the default-invite for
//     the appointment...that is, it MUST NOT BE the start time of the exception!
//
//   **The above is important**   So let me explain:
//
//   Given an appointment, happens every Wednesday @ 9am, with an exception that moves
//      it to 10am on 6/22
//
//   So our instances for June, 2005  are:
//       6/1 9am
//       6/8 9am
//       6/15 9am
//       6/22 10am (an existing EXCEPTION)
//       6/29 9am
//
//  So, if a user clicks on the 6/22 10am appointment and wants to modify it, you MUST NOT
//  try to use <CreateAppointmentException s="6/22 10am"> to modify it!
//  You MUST use ModifyAppointmentException instead!!!
//
//  On the other hand, if a user clicks on the 6/15 9am appointment and wants to modify it,
//  then this is the right API to use.
//
<CreateAppointmentException [id="ID_DEFAULT_INVITE" comp="COMP_DEFAULT_INVITE"] >
  <m f="{flags}" l="{folder}">
     ...
     <inv [uid="uid-for-create"]>  // optional: client can request the UID to use
       [
         <exceptId DATETIME> // EXCEPTION_ID -- this is the DateTime of some instance in the default appointment
         ...
      </inv>
   </m>
</CreateAppointmentException>
         




----------------------
RECURRENCE SPECIFIERS!

 <recur> holds a recurence.  Note that the initial instance is NOT specified by <recur>, it is implied
    by the s= and (e=|dur=) parameters.  The initial instance may NOT be modified by an <exclude> parameter
    inside a <recur>
 <add>      - dates or rules which ADD instances.  ADDs are evaluated before EXCLUDEs
 <exclude>  - dates or rules which EXCLUDE instances.  
 <date>     - an SDATE that is added or excluded.  D+DATE values may ONLY be used if this is an all-day-event!
 <rule>     - a RULE for specifying added/exluded instances
 <freq>     - "SEC","MIN","HOU","DAI","WEE","MON","YEA" - event happens every INTERVAL Seconds/Minutes/Hours/etc.
 <ival>     - Default is 1.  Number of (secs/mins/hours/etc)  between occurences.
 <until>    - INCLUSIVE date to stop (ie if there is a recurrence on that date, it IS added to list
 <count>    - number of occurences to be generated by this rule
 <bymonth>,<byweekno>.... --- TODO 
----------------------

<CreateAppointmentResponse calItemId="APPOINTMENT-ID" invId="invite-message-id"/>


//////////////////////////////////////////////////////////////////////
//
// Directly set status of an entire appointment.  This API is intended
// for mailbox Migration (ie migrating a mailbox onto this server) and
// is not used by normal mail clients.
//
//   need to specifiy folder for appointment
//
//   need way to add message WITHOUT processing it for calendar parts.
//   need to generate and patch-in the iCalendar for the <inv> but w/o
//   actually processing the <inv> as a new request
//
//   TODO: need way to link message to appointment after the fact
//
//
<SetAppointmentRequest [l="folder_to_create_in"] [f="flags"] [t="tags"]>
  <default
      ptst="NE|AC|TE|DE|DG|CO|IN"  // my participation status
  >
     <m [aid="{uploaded-MIME-body-ID}"] > ...see CreateAppointmentRequest...
**************
ONE OF:        
   1) XML <inv> format from CreateAppointment 
        <inv>
          <comp>
            ...
            <exceptId DATETIME> // EXCEPTION_ID -- this is the DateTime of some instance in the default appointment
            ...
          </comp>
        </inv>
        <mp ct="content type">
          meeting notes parts
        </mp>
OR
   2) Raw MimeMessage import:
       <mp ct="content type">
         <content>
           RAW RFC822 MESSAGE (XML-encoded)  ***MUST CONTAIN A text/calendar PART***  
         </content>
       </mp>
OR
   3) Raw MimeMessage uploaded as attachment ID (see AddMsgRequest in soap.txt)
*************
     </m>
  </default>
  [<except
      ptst="NE|AC|TE|DE|DG|CO|IN"  // my participation status
   >
     <m> Same as under <default> above  
        ...
        **1 of the 3 forms above**
     </m>
  </except>]*
  [<cancel>
     <m> Same as under <default> above  
        ...
        **1 of the 3 forms above**
        
        If using <inv> form, these elements and attributes must be present:

        <inv>
		  [<tz>...</tz>]*
          <comp
                uid="{UID}"
                seq="{sequence}"  // must be incremented from original sequence
                [name="{name}]
                [allDay="{allDay}"]>
            <exceptId ...>  // RECURRENCE-ID
            <s ...>         // DTSTART
            <or ...>        // ORGANIZER
            <at ...>+       // ATTENDEEs
          </comp>
        </inv>
        <mp ct="content type">meeting notes parts</mp>
        
        All others are ignored.
     </m>
  </cancel>]*
</SetAppointmentRequest>

<SetAppointmentResponse calItemId="appointment_id">
  <default id="invId_of_default_invite/>
  [<except recurId="recurrence_id_of_exception"
  id="invId_of_exception/>]*
</SetAppointmentResponse>  

   
//////////////////////////////////////////////////////////////////////
//
// GetApptSummaries
//
// 
<GetApptSummariesRequest s="RANGE_START_MSECS_GMT" e="RANGE_END_MSECS_GMT" [l="{folder-id}"]/>

  -- folder-id: optional folder to constrain requests to; otherwise, searches all folders but trash and spam

<GetApptSummariesResponse>
 ( <appt id="appointment_mail_item_id"
      [fba="F|B|T|U"]
      [transp="O|T"]
      status="TENT|CONF|CANC"
      ptst="NE|TE|AC|DE|DG"
      [allDay="1"]             // if set, this is an "all day" appointment
      [otherAtt="1"]           // if set, this appointment has other attendees
      [alarm="1"] [recur="1"]
      [name="NAME"] [loc="LOCATION"] 
      invId="default_invite_mail_item_id" compNum="default_invite_component_number"
      isOrg="default_am_i_organizer_flag"
      [priority="num"]
      [percentComplete="num"]
      [d="duration"]  // default duration
      [f="flags"]
      [t="tags"]
   >
   <fr>FRAGMENT</fr>
      
      ( <inst
          [s="START_SECS_GMT"]
          [tzo="ms"]  // offset from GMT in milliseconds for start time in the
                    // time zone of the instance; this is useful because the
                    // instance time zone may not be the same as the time zone
                    // of the requesting client; when rendering an all-day
                    // appointment, the client must shift the appointment by
                    // the difference between the instance time zone and its
                    // local time zone to determine the correct date to render
                    // the all-day block
          [ex="1"]
          [ANY CHANGED PARAMETERS]
        >
          [<f>FRAGMENT IF DIFFERENT FROM DEFAULT</f>]
          [<dur DURATION>] // duration this instance if not same as default
          [<isOrg>] // isOrg flag if not same as default
          [<otherAtt>] // otherAtt flag if not same as default
        </inst>
      )+
        
   </apt> )*
</GetApptSummariesResponse>

   -- fba: actual free-busy status: Free, Busy, busy-Tentative, busy-Unavailable (a.k.a. OutOfOffice)
           While free-busy status is simply a property of an event that
           is set during creation/update, "actual" free-busy status is the true
           free-busy state that depends on appt/invite free-busy, event scheduling
           status (confirmed vs. tentative vs. cancel), and more importantly, the
           attendee's participation status.  For example, actual free-busy is
           busy-Tentative for an event with Busy free-busy value until the attendee
           has acted on the invite.
   -- transp: transparency: Opaque, Transparent
   -- status: status of event: TENTative, CONFirmed or CANCelled
   -- ptst: **your** participation status: NEeds-action, TEntative, ACcept, DEclined, DG (delegated)
   -- get the summary of appointments for a specified time period...
   -- otherAtt: 1 if there are other attendees to the meeting
   -- alarm: 1 if there are some alarms
   -- recur: 1 if this is a recurring appointment
   -- id is mail_item id of APPOINTMENT object
   -- invId is mail_item id of invite message with detailed information
   -- comp is component number (invite # within the message)
   -- parameters in the apptSum are "defaults" -- are same in instance unless specified
   

//////////////////////////////////////////////////////////////////////
//
// GetFreeBusyRequest
//
// (f)ree (b)usy busy-(t)entative busy-(u)navailable or (n)o-data elements
//
<GetFreeBusyRequest s="RANGE_START_MSECS_GMT" e="RANGE_END_MSECS_GMT" [uid="id,..."]/>
<GetFreeBusyResponse>
  <usr id="id">
    <f s="START_MSECS_GMT" e="END_MSECS_GMT"/>*
    <b s="START_MSECS_GMT" e="END_MSECS_GMT"/>*
    <t s="START_MSECS_GMT" e="END_MSECS_GMT"/>*
    <u s="START_MSECS_GMT" e="END_MSECS_GMT"/>* // a.k.a. out of office
    <n s="START_MSECS_GMT" e="END_MSECS_GMT"/>* // could not retreive data for that user
  </usr>  
<GetFreeBusyResponse>

      



//////////////////////////////////////////////////////////////////////
//
// CancelAppointment(DEFAULT-INVITE-ID, COMPONENT-NUMBER)
//
// NOTE: If canceling an exception, the original instance (ie the one the exception was "excepting") WILL NOT
// be restored when you cancel this exception.
//
// if <inst> is set, then this cancels just the specified instance or range of instances,
// otherwise it cancels the entire appointment.  If <inst> is not set, then id MUST refer to the default
// invite for the appointment.
//
<CancelAppointmentRequest id="ID_OF_DEFAULT_INVITE" comp="COMPONENT_NUM_DEFAULT_INVITE">
   [<tz ...>]  // definition for TZID referenced by DATETIME in <inst>
   [<inst [range="THISANDFUTURE|THISANDPRIOR"] DATETTIME/>]?
   [ <m>
       [<e.../>*] // users to send update to
       [<su>{subject of cancellation mail}</su>]
       <mp>...</mp>
     </m> ]
</CancelAppointmentRequest>

<CancelAppointmentResponse>....


//////////////////////////////////////////////////////////////////////
//
// GetMsgResponse 
//
// CALENDAR PART for Invite messages
//
<GetMsgResponse> // mesage with invite
  <m id="{message-id}" f="{flags}" t="{tags}" s="{size}" d="{date}" l="{folder}">
     [<e .../>*]  // optional users to send request to
     <su>{subject}</su>
     <f>{fragment}</f>

     <inv type="appt|task">
       [
       <comp status="TENT|CONF|CANC"
       		fb="F|B|T|U"
       		fba="F|B|T|U" // Your current status -- what is returned in FreeBusy for you TODO
       		transp="O|T"
            [ex="1|0]  // 1 if this Invite is an Exception
            [allDay="1|0"] [name="NAME"]
            [loc="LOCATION"]
            [rsvp="1|0"] // rsvp - 1 if response requested, 0 if no response requested
            [calItemId="mail-item-id-of-appointment"] 
            [updatedMsgId="id" updatedCompNum="compNum"] // if these are set, then this invite has been
                                                      // invalidated because a new update was received that
                                                      // takes precedence over it
                                                      //
                                                      // id=0, compnum=0 is a SPECIAL CASE: it means "we don't know
                                                      // what invite overrides this one, but we do know this one is
                                                      // not referenced.  This can happen if this is a
                                                      // recurrence-exception and default-invite is modified in a way
                                                      // that invalidates this one...or it can happen if there is an
                                                      // out-of-order message delivery (the exception invite is received
                                                      // before the initial invite) or if the Appointment object doesn't
                                                      // exist (ie it was deleted) or various other times...
                                                      // 
                                                      
            [isOrg="1"] // 1 if you are the Organizer of this event
            >
           <s DATETIME> // Start date-time (required)

           (
              <e DATETIME> // End date-time
              OR
              <dur DURATION>
           )   
           <or d="friendly name" url="address"> // organizer
           <at d="friendly name" url="address" role="ROLE" ptst="status"" [cutype="CUTYPE"]/>* // attendee
             // role = CHAir, REQuired, OPTional, NON-participant (ie informational)
             // ptst = NEeds-action, TEntative, ACcept, DEclined, DG (delegated), COmpleted (todo), IN-process (todo)
             // cutype (calendar user type) = INDividual, GROup, RESource, ROOm, UNKnown
           <alarm rel-start="RELATIVE_MSECS_MINUS_MEANS_AFTER_START"/>*
           [
             <recur>
                RECURRENCE PART
             </recur>  
           ]
       </comp>


       ]+
     </inv>
     <mp>...</mp>
     [<content (url="{url}")>...</content>]
   </m>
</GetMsgResponse>


//////////////////////////////////////////////////////////////////////
//
// ModifyAppointment
//
// Modify an appointment, or if the appointment is a recurrence then modify the "default"
// invites: that is, all instances that do not have exceptions
//
// If the appointment has a <recur>, then the following caveats are worth mentioning:
//        
//   -- If any of: START, DURATION, END or RECUR change, then all exceptions are implicitly canceled!
//
// This call MAY NOT change the target folder of the appointment -- because ModifyAppointment
// only works on a single Invite, and since all of the Invites in a specific Appointment must
// be in the same Folder, the folder may not be changed with this API.  To move Appointments
// between folders you should use the ItemActionRequest API with op="move"
// 
//
<ModifyAppointmentRequest id="INVITE_ID_OF_DEFAULT_INVITE" comp="COMPONENT_NUM_DEFAULT_INVITE">
   rest is SAME as CreateAppointmentRequest except THE TARGET FOLDER IS IGNORED (see above)
</ModifyAppointmentRequest>

<ModifyAppointmentResponse calItemId="appointment-id" invId="invite-message-id/>



//////////////////////////////////////////////////////////////////////
//
// CreateAppointmentException (invId, compNum, instanceid)
//
//   The default invite for the appointment MUST have a recurrence rule....
//      otherwise you should just be using ModifyAppointment!
//
//   EXCEPTION_ID is start-time for the particular instance you are overriding
//     EXCEPTION_ID MUST be some instance that matches the default-invite for
//     the appointment...that is, it MUST NOT BE the start time of the exception!
//
//   **The above is important**   So let me explain:
//
//   Given an appointment, happens every Wednesday @ 9am, with an exception that moves
//      it to 10am on 6/22
//
//   So our instances for June, 2005  are:
//       6/1 9am
//       6/8 9am
//       6/15 9am
//       6/22 10am (an existing EXCEPTION)
//       6/29 9am
//
//  So, if a user clicks on the 6/22 10am appointment and wants to modify it, you MUST NOT
//  try to use <CreateAppointmentException s="6/22 10am"> to modify it!
//  You MUST use ModifyAppointmentException instead!!!
//
//  On the other hand, if a user clicks on the 6/15 9am appointment and wants to modify it,
//  then this is the right API to use.
//
<CreateAppointmentExceptionRequest id="ID_DEFAULT_INVITE" comp="COMP_DEFAULT_INVITE">

  Just like CreateAppointmentRequest above:
  <m f="{flags}" l="{folder}">
    ...
    <inv>
      ...
      <exceptId DATETIME> // EXCEPTION_ID -- this is the DateTime of some instance in the default appointment
      ...
    </inv>
  </m>  
   
</CreateAppointmentExceptionRequest>

<CreateAppointmentExceptionResponse>...


//////////////////////////////////////////////////////////////////////
//
// ExpandRecur
//
// Expand a Recur rule over a set of dates -- not sure if this is useful,
// but might be useful to the UI if it wants to show occurences???
//
<ExpandRecurRequest s="RANGE_START_MSEC_GMT" e="RANGE_END_MSEC_GMT">
   <recur>
      ***see CreateAppointment for <recur> details***
    </recur>
</ExpandRecurRequest>

<ExpandRecurResponse>
  <inst s="MSECS_GMT">*
</ExpandRecurResponse>



//////////////////////////////////////////////////////////////////////
//
// Retrieve the unparsed (but XML-encoded (&quot) iCalendar data for an Invite
//
// This is intended for interfacing with 3rd party programs
//
<GetICalRequest [id="invMsgId"] [s="RANGE_START_MSECS_GMT" e="RANGE_END_MSECS_GMT" l="{folder}"/>

    -- if id is specified, gets iCalendar representation for one
       Invite
       
    -- if id is not specified, then start/end MUST be, Calendar data
       is returned for entire specified range

<GetICalResponse>               
   <ical>
      ICALENDAR DATA
   </ical>
</GetICalResponse>               



//////////////////////////////////////////////////////////////////////
//
// SendInviteReply
//
//
<SendInviteReplyRequest id="mail_item_id" compNum="comp_num"
  verb="VERB" [updateOrganizer="1|0"]>
  [<tz ...>]  // definition for TZID referenced by DATETIME in <exceptId>
  [<exceptId DATETIME>]? // reply to just one instance of the specified Invite (default is all instances)
  [<m>...</m>]
</SendInviteReplyRequest>  

  id             : unique ID of the invite (and component therein) you are replying to
  comp           : component number of the invite
  verb           : ACCEPT, COMPLETED, DECLINE, DELEGATED, TENTATIVE  (Completed/Delegated are NOT supported as of 9/12/2005)
  m              : embedded message, if the user wants to send a custom update message.
                   The client is responsible for setting the message recipient list in
                   this case (which should include Organizer, if the client wants to tell
                   the organizer about this response)
  updateOrganizer: yes by default, if no then only make the update locally.  This parameter
                   has no effect if an <m> element is present.
  
<SendInviteReplyResponse status="STATUS"/>

   status: OK, OLD (a newer invite exists for that appointment), ALREADY-REPLIED, FAIL   (other failure)


//////////////////////////////////////////////////////////////////////
//
// GetAppointment
//
// Returns the metadata info for each Invite that makes up this appointment.
//
// The content (original email) for each invite is stored within the Appointment itself in
// a big multipart/digest containing each invite in the appointment as a sub-mimepart --
// it can be retreived from the content servlet:
//
//       http://servername/service/content/get?id=<calItemId>
//
//
// The content for a single Invite can be requested from the content servlet (or from <GetMsg>)
// Individual  The client can ALSO request just the content for each individual invite using a
// compound item-id request:
//       http://servername/service/content/get?id="calItemId-invite_mail_item_id"
//       <GetMsgRequest><m id="calItemId-invite_mail_item_id"
//
//      
// IMPORTANT NOTE: DO NOT use the raw invite-mail-item-id to fetch the content: it might work
// sometimes, however the invite is a standard mail-message it can be deleted by the user at
// any time!
//
<GetAppointmentRequest id="appointment_id" [sync="1"]/>

<GetAppointmentResponse>
  <appt uid="UID" id="appointment_id" [f="{flags}"] [t="{tags}"] s="{size}" d="{date}" l="{folder}">
    [<inv id="invite-original-mail-item-id" compNum="component-number" seq="num">
      [<replies>
        [<reply d="TIMESTAMP_OF_REPLY"
                at="foo@bar.com"
                ptst="AC|DE|TE|NE"
                rangeType="1"
                recurId="YYMMDD[THHMMSS[Z]]"
                tz="timezonename"/>]*
      </replies>] // one or more replies which we have sent out
      ...
        ---See <inv> part of GetMsgResponse---
      ...    
    </inv>]+
  </appt>
</GetAppointmentResponse>

  if sync="1" present, return modified date (md) on appointment.

-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------

NOTES NOTES (not part of soap proto)



Internal Server-Side Calendar Data Model
----------------------------------------

An INVITE is an email message with an iCal attachment.  An INVITE has
a mail_item_id, which uniquely identifies it, and a UID which identifies
the APPOINTMENT it is about....plus other normal iCal data.  An Invite
has a START and END time -- which corresponds to the range of time
where this invite is relevant.

   Some sample invites:
   
      INVITE sent on 3/1 with id=5 UID=1234 for an event happening every Monday
      with subject "Gorilla Discussion" (START=3/1, END=none)
      
      INVITE with id=7 UID=1234 for an exception on 3/21
      for the "Left-Handed Gorilla Discussion" (START=3/21 END=3/21)
 

   
An APPOINTMENT consists of one or more INVITES in the same series --
ie that have the same UID. From the appointment you can get the INSTANCES
which are the start/end times of each occurence.  

   Sample Appointment:
       APPOINTMENT UID=1234 (two INVITES above)
          ...Instances on every monday with name "Gorilla Discussion"
          EXCEPT for the 21st, where we talk about lefties instead.


An INSTANCE is simply a start-end time and a pointer to an INVITE
which has detailed information about the meeting (description, etc)

   Instances:
       3/1 "Gorilla Discussion" id=5
       3/14 "Gorilla Discussion" id=5
       3/21 "Left-Handed Gorilla Discussion" id=7
	


       
TIMEZONES:
----------------
Each iCalendar object can define custom time zone names.  For our own web
client, there is a list of well-known time zones.  These are stored in
LDAP.  See conf/ldap/zimbra.ldif for their definition.  The time zone ID
is the cn attribute.




TASKS:
----------------
For every <DoAction>AppointmentRequest, there is <DoAction>TaskRequest, and
corresponding responses.  For GetApptSummariesRequest, there is
GetTaskSummariesRequest.  GetCalendarItemsSummariesRequest is there for
retrieving both appointments and tasks in one shot.

Wherever <appt> element shows up, the corresponding task request/response will
use <task> element.

<appt> element uses apptID for backward compatibility reason.  New code should
ignore apptID and use calItemID instead.  <task> element uses calItemID only.
