
    i7                    r   d Z ddlZddlZddlZddlZddlZddlmZ ddlmZm	Z	m
Z
 ddlmZmZmZ ddlmZmZ ddlZddlmZ ddlmZmZ 	 dd	lmZmZ eeez           Zn#  Y nxY werdd
lmZ ddlmZ ddlmZmZ ddlmZ ej         dk     rddl!m"Z" nddlm"Z" ddl#m$Z$ ddl%m&Z&m'Z'm(Z(m)Z)m*Z* ddl+m,Z, ddl-m.Z.m/Z/ ddl0m1Z1m2Z2 ddl3m4Z4 ddl5m6Z6m7Z7m8Z8 ddl9m:Z: ddl;m<Z<  ej=        d          Z> G d de,          Z? G d de?          Z@ G d d e?          ZA G d! d"e?          ZB G d# d$e?          ZCdS )%a  
Calendar Objects Resources, as defined in the RFC 4791.

There are three subclasses Todo, Journal and Event.  Those mirrors objects stored on the server.  The word ``CalendarObjectResource`` is long, complicated and may be hard to understand.  When you read the word "event" in any documentation, issue discussions, etc, then most likely it should be read as "a CalendarObjectResource, like an event, a task or a journal".  Do not make the mistake of going directly to the Event-class if you want to contribute code for handling "events" - consider that the same code probably will be appicable to Joural and Todo events, if so, CalendarObjectResource is the right class!  Clear as mud?

FreeBusy is also defined as a Calendar Object Resource in the RFC, and it is a bit different .  Perhaps there should be another class layer between CalendarObjectResource and Todo/Event/Journal to indicate that the three latter are closely related, while FreeBusy is something different.

Alarms and Time zone objects does not have any class as for now.  Those are typically subcomponents of an event/task/journal component.

Users of the library should not need to construct any of those objects.  To add new content to the calendar, use ``calendar.add_event``, ``calendar.add_todo`` or ``calendar.add_journal``.  Those methods will return a CalendarObjectResource.  To update an existing object, use ``event.save()``.
    N)defaultdict)datetime	timedeltatimezone)TYPE_CHECKINGAnyOptional)ParseResultSplitResult)rrulestr)vCalAddressvText)ClassVarr	   )r      )	DAVClient)Callable	Container)Literal)      )Self)contextmanager)	DataStateIcalendarStateNoDataStateRawDataStateVobjectState)	DAVObject)cdavdav)errorvcal)errmsg)to_normal_str
to_unicodeto_wire)URL)
_quote_uidcaldavc                       e Zd ZU dZddddddZeed<   d	Zd	Zd	Z	d	Z
d	Zed	z  ed
<   dZeed<   eded	z  fd            Zej        ded	z  dd	fd            Z	 	 	 	 	 	 dyded         deez  ez  ez  d	z  ded	z  ded	z  ded	z  ded	z  dd	f fdZdzdZd{dZdee         fdZd|dedededd	fd Z	 d}	 d{d!Z 	 	 	 	 d~d"e!e         d	z  d#e"egef         d	z  d$ed%ede#ee$e         f         f
d&Z%d' Z&de'fd(Z(	 dd)ed*ed+edefd,Z)dzd+edee'         fd-Z*dzd+edefd.Z+dzd/Z,d{d0Z- ee,e-d12          Z.e.Z/d3 Z0e0Z1dzd4edd	fd5Z2defd6Z3defd7Z4dd8ed9         dd	fd:Z5dd8ed9         dd	fd;Z6dd8ed	z  dd	fd<Z7d{d=Z8dd>ed?ed	z  defd@Z9dzdAedefdBZ:dzdAedefdCZ;defdDZ<defdEZ=dd{dFZ>d|dGZ?d|dHZ@dd{dIZAdd{dJZBdK ZCddLed	z  dd	fdMZD	 	 	 	 	 	 	 ddNedOedPed	z  dQedRedSedTedefdUZEdefdVZFdW ZGdefdXZHdefdYZIdZ ZJd[ ZKd\ ZL eeKeJd]2          ZMeed<    eeLeJd^2          ZNddaZOded`         fdbZPded`         fdcZQdddZR eePeOde2          ZSdfedg<    eeQeRdh2          ZTdfedi<   dj ZUdk ZV eeVeUdl2          ZWeedm<   defdnZXdefdoZYdeZj[        fdpZ\ddqZ]e^dr             Z_e^ds             Z`ded	z  fdtZaded	z  fduZbdefdvZcdedfdwZedx Zf xZgS )CalendarObjectResourceaK  Ref RFC 4791, section 4.1, a "Calendar Object Resource" can be an
    event, a todo-item, a journal entry, or a free/busy entry

    As per the RFC, a CalendarObjectResource can at most contain one
    calendar component, with the exception of recurrence components.
    Meaning that event.data typically contains one VCALENDAR with one
    VEVENT and possibly one VTIMEZONE.

    In the case of expanded calendar date searches, each recurrence
    will (by default) wrapped in a distinct CalendarObjectResource
    object.  This is a deviation from the definition given in the RFC.
    CHILDPARENTSIBLINGFINISHTOSTART	DEPENDENT)r-   r,   r.   z
DEPENDS-ONr/   RELTYPE_REVERSE_MAPN_stateF	_borrowedreturnc                     |                                  }|:| j        r3| j        j        D ]&}|j        dv rd|v rt	          |d                   } n'|S )a/  Returns the UID of the calendar object.

        Extracts the UID from the calendar data using cheap accessors
        that avoid unnecessary parsing (issue #515, #613).
        Falls back to direct icalendar parsing if the cheap accessor fails.
        Does not trigger a load from the server.
        N)VEVENTVTODOVJOURNALUID)_get_uid_cheap_icalendar_instancesubcomponentsnamestr)selfuidcomps      X/root/projects/butler/venv/lib/python3.11/site-packages/caldav/calendarobjectresource.pyidzCalendarObjectResource.idi   sh     !!##;43;0>  9 ???ETMMd5k**CE
    valuec                     dS )zSetter exists for compatibility with parent class __init__.

        The actual UID is stored in the calendar data, not separately.
        Setting this is a no-op - modify the icalendar data directly.
        N )r?   rE   s     rB   rC   zCalendarObjectResource.id{   s	     	rD   clientr   urldataparentrC   propsc                 X   t          t          |                               |||||           |u|| _        |rn|                                 r\| j                            dd          }| j                            d|           d| _        t          | j
                  | _        dS dS dS dS )z
        CalendarObjectResource has an additional parameter for its constructor:
         * data = "...", vCal data for the event
        )rH   rI   rK   rC   rL   Nr9   )superr+   __init__rJ   _get_component_type_cheapicalendar_componentpopadd_datar   r;   r2   )	r?   rH   rI   rJ   rK   rC   rL   old_id	__class__s	           rB   rO   zCalendarObjectResource.__init__   s     	$d++44s6b 	5 	
 	
 	
 DI Gd4466 G155eTBB(,,UB777!
,T-EFF G G G GrD   c                    | j         }t          |d          r&|j        s|                    t          j                  }|                                 }|                    dd           |                    | j        d           |r4|r2d|v r.|                    d           |	                    d||z
             |	                    | j        |           dS )ac  The RFC specifies that a VEVENT/VTODO cannot have both
        dtend/due and duration, so when setting dtend/due, the duration
        field must be evicted

        WARNING: this method is likely to be deprecated and parts of
        it moved to the icalendar library.  If you decide to use it,
        please put caldav<4.0 in the requirements.
        tzinfoDURATIONNDTSTART)
rQ   hasattrrX   
astimezoner   utcget_durationrR   	_ENDPARAMrS   )r?   endmove_dtstartidurations        rB   set_endzCalendarObjectResource.set_end   s     $3!! 	/#* 	/....C$$&&	j$	dnd### 	-H 	-aEE)EE)S8^,,,	dnc"""""rD   c                     | j         t          d          | j                                         }| j                            d|                                           dS )z
        goes via self.client, finds the principal, figures out the right attendee-format and adds an
        organizer line to the event
        N%Unexpected value None for self.client	organizer)rH   
ValueError	principalrQ   rS   get_vcal_address)r?   ri   s     rB   add_organizerz$CalendarObjectResource.add_organizer   s[    
 ;DEEEK))++	 	 $$[)2L2L2N2NOOOOOrD   c                    t          j        dt          d           | j        j        }d |D             }d |D             }t          |          dk    r| gS |r%t          j        t          |          dk               g }|D ]}|                     d          }g |j        _        |r%|j        j        	                    |d	                    |j        j        	                    |           |	                    |           |S )
aY  This was used internally for processing search results.
        Library users probably don't need to care about this one.

        The logic is now handled directly in the search method.

        This method is probably used by nobody and nothing, but
        it can't be removed easily as it's exposed as part of the
        public API
        znobj.split_expanded is likely to be removed in a future version of caldav.  Feel free to protest if you need it   
stacklevelc                 F    g | ]}t          |t          j                  |S rG   
isinstance	icalendarTimezone.0xs     rB   
<listcomp>z9CalendarObjectResource.split_expanded.<locals>.<listcomp>   s*    AAAQz!Y-?@@AqAAArD   c                 F    g | ]}t          |t          j                  |S rG   rq   ru   s     rB   rx   z9CalendarObjectResource.split_expanded.<locals>.<listcomp>   s*    EEEQ:a1C#D#DEqEEErD   r   T)keep_uidr   )
warningswarnDeprecationWarningicalendar_instancer<   lenr!   assert_copyappend)r?   rb   tz_ntzretical_objobjs          rB   split_expandedz%CalendarObjectResource.split_expanded   s    	|	
 	
 	
 	
 #1AA!AAAEE!EEEs88q==6M 	)M#c((a-((( 	 	H))T)**C35C"0 D&4;;CFCCC"077AAAJJsOOOO
rD   Tstartr`   include_completedc                 :   t          j        dt          d           ddl}|                    | j        g d                              ||          }h dt          j        t          fd	|D                                   | j        }g |_
        |D ]}|s#|j        d
k    r|                    d          dv r't          j        d|v            d|vr.|                    d|                    d          j                   |                    |           dS )a  This method will transform the calendar content of the
        event and expand the calendar data from a "master copy" with
        RRULE set and into a "recurrence set" with RECURRENCE-ID set
        and no RRULE set.  The main usage is for client-side expansion
        in case the calendar server does not support server-side
        expansion.  If doing a `self.load`, the calendar
        content will be replaced with the "master copy".

        :param event: Event
        :param start: datetime
        :param end: datetime

        zlobj.expand_rrule is likely to be removed in a future version of caldav.  Feel free to protest if you need itrm   rn   r   N)r8   r7   r6   )
components>   rdaterruleexdateexrulec              3      K   | ]:}                     t          |                                                    6|V  ;d S N)
isdisjointsetkeys)rv   rw   recurrence_propertiess     rB   	<genexpr>z6CalendarObjectResource.expand_rrule.<locals>.<genexpr>  sM      aa!1F1Q1QRUVWV\V\V^V^R_R_1`1`aAaaaaaarD   r7   STATUS)	COMPLETED	CANCELLEDRECURRENCE-IDrZ   )r{   r|   r}   recurring_ical_eventsofr~   betweenr!   r   anyr<   r=   getrS   dtadd_component)	r?   r   r`   r   r   
recurringscalendar
occurrencer   s	           @rB   expand_rrulez#CalendarObjectResource.expand_rrule   so   & 	z	
 	
 	
 	
 	%$$$*--#0O0O0O . 
 

'%

 	 !G F Faaaazaaaaaa	
 	
 	
 *!#$ 	/ 	/J &Ow..NN8,,0JJJ M/Z7888j00
y0I0I0LMMM"":....	/ 	/rD   c                 P   |                                 }t          |t                    r1|j        r|j        }n@|                                p|j        d         }n|}|r| j                            |          }|r%| j        |         }|	                    | |d           | j        
                    dd          }t          |t                    r|n|g}|D ]}||k    r dS t          |          }| j                            d|d|id           |                                  dS )	zb
        Sets a relation between this object and another object (given by uid or object).
        r@   F)otherreltypeset_reversez
related-toNRELTYPET)
parametersencode)upperrr   r+   rC   r:   rQ   rK   get_object_by_uidr1   set_relationr   listr>   rS   save)	r?   r   r   r   r@   reltype_reverseexisting_relationexisting_relationsrels	            rB   r   z#CalendarObjectResource.set_relation  s_    --//e344 		;x Qh **,,P0I%0PC ;55c:: 	W #6w?OT?PUVVV 488tLL!+,=t!D!D]K\J] 	 & 	 	Cczz  #hh $$#9g*>t 	% 	
 	
 	
 			rD   reltypes	relfilterfetch_objectsignore_missingc                    ddl m} t          t                    }| j                            dg           }t          |t                    s|g}|D ]Z}|r ||          s|j                            dd          }	|r|	|vr2||	         	                    t          |                     [|r|D ]}	||	         }
t                      }| j        t          d          t          | j        |          st          d          |
D ]H}	 |	                    | j                            |                     1# t          j        $ r |s Y Ew xY w|||	<   |S )	a  
        By default, loads all objects pointed to by the RELATED-TO
        property and loads the related objects.

        It's possible to filter, either by passing a set or a list of
        acceptable relation types in reltypes, or by passing a lambda
        function in relfilter.

        TODO: Make it possible to  also check up reverse relationships

        TODO: this is partially overlapped by plann.lib._relships_by_type
        in the plann tool.  Should consolidate the code.

        TODO: should probably return some kind of object instead of a weird dict structure.
        (but due to backward compatibility requirement, such an object should behave like
        the current dict)
        r   )Calendarz
RELATED-TOr   r-   Nz%Unexpected value None for self.parentz9self.parent expected to be of type Calendar but it is not)
collectionr   r   r   rQ   r   rr   r   paramsrS   r>   rK   rh   r   r!   NotFoundError)r?   r   r   r   r   r   r   	relationsr   r   uidsreltype_setr   s                rB   get_relativesz$CalendarObjectResource.get_relativesH  s   0 	)(((((#,00rBB	)T** 	$"I 	' 	'C 3 jnnY99G G833LSXX&&&& 	+ + +7|!ee;&$%LMMM!$+x88 b$%`aaa " "C"#(E(Ec(J(JKKKK . " " "- "!" ""  +G
s   -D44E	E	c                     | j                             |          }|s!t          j        d|d| j                   d S |                    | ||           d S )NzReltype z not supported in object uid )r1   r   loggingr!   rC   r   )r?   r   r   reverse_reltypes       rB   _set_reverse_relationz,CalendarObjectResource._set_reverse_relation  se    266w?? 	MMRVRYRYZ[[[F4%88888rD   c                     | j         |         }|                    d|h          }|                                 pt          | j        d                   }|||         vr||fS dS )NF)r   r   r@   )r1   r   r:   r>   rQ   )r?   r   r   
revreltypeother_relationsmy_uids         rB   _verify_reverse_relationz/CalendarObjectResource._verify_reverse_relation  sq    -g6
--EZL-YY$$&&N#d.Fu.M*N*N444 :&&urD   verifyfixpdbc                 >   g }|s|sJ |                                  }|D ]}}||         D ]r}|rV|                     ||          }|r=|                    |           |rt                       |r|                     ||           Z|r|                     ||           s~|S )a  
        Goes through all relations and verifies that the return relation is set
        if verify is set:
            Returns a list of objects missing a reverse.
            Use public method check_reverse_relations instead
        if verify and fix is set:
            Fixup all objects missing a reverse.
            Use public method fix_reverse_relations instead.
        If fix but not verify is set:
            Assume all reverse relations are missing.
            Used internally when creating new objects.
        )r   r   r   
breakpointr   )	r?   r   r   r   r   r   r   r   foobars	            rB   _handle_reverse_relationsz0CalendarObjectResource._handle_reverse_relations  s     &&((	  	? 	?G"7+ 
? 
? 	?!::5'JJF G

6*** )&LLL G 66ugFFF ?..ug>>>
? 
rD   c                 2    |                      dd|          S )a%  
        Will verify that for all the objects we point at though
        the RELATED-TO property, the other object points back to us as
        well.

        Returns a list of tuples.  Each tuple contains an object that
        do not point back as expected, and the expected reltype
        TFr   r   r   r   r?   r   s     rB   check_reverse_relationsz.CalendarObjectResource.check_reverse_relations  s     --Tu#-NNNrD   c                 2    |                      dd|          S )a&  
        Will ensure that for all the objects we point at though
        the RELATED-TO property, the other object points back to us as
        well.

        Returns a list of tuples.  Each tuple contains an object that
        did not point back as expected, and the expected reltype
        Tr   r   r   s     rB   fix_reverse_relationsz,CalendarObjectResource.fix_reverse_relations  s     --Tt-MMMrD   c                    |                      d           | j        sdS d | j        j        D             }t          j        t          |          dk    p|            |D ]I}t          j        t          j        t          j	        t          j
        fD ]}t          ||          r|c c S Jt          j        d           dS )zReturns the icalendar subcomponent - which should be an
        Event, Journal, Todo or FreeBusy from the icalendar class

        See also https://github.com/python-caldav/caldav/issues/232
        Tonly_if_unloadedNc                 F    g | ]}t          |t          j                  |S rG   rq   ru   s     rB   rx   zCCalendarObjectResource._get_icalendar_component.<locals>.<listcomp>  s;     
 
 
a!344

 
 
rD   r   F)loadr~   r<   r!   r   r   rs   EventJournalTodoFreeBusyrr   )r?   
assert_oner   rw   cls        rB   _get_icalendar_componentz/CalendarObjectResource._get_icalendar_component  s     			4	(((& 	4
 
,:
 
 

 	c#hh!m5:~666 	 	A!"	   a$$ HHHHH 	erD   c                    | j         j        fdt          dt                              D             }t          |          dk    r|| j         j        |d         <   d S t	          j                    }|                    d| j         d                    |                    d| j         d                    |                    |           || _         d S )Nc                 T    g | ]$}t          |         t          j                  "|%S rG   rq   )rv   rb   ss     rB   rx   zCCalendarObjectResource._set_icalendar_component.<locals>.<listcomp>  s/    UUU1
1Q4AS0T0TUQUUUrD   r   r   prodidversion)r~   r<   ranger   rs   r   rS   r   )r?   rE   rb   my_instancer   s       @rB   _set_icalendar_componentz/CalendarObjectResource._set_icalendar_component  s    #1UUUUaQ((UUUq66Q;;:?D#1!A$777#,..KOOHd&=h&GHHHOOIt'>y'IJJJ%%e,,,&1D###rD   a  icalendar component - this is the simplest way to access the event/task - it will give you the first component that isn't a timezone component.  For recurrence sets, the master component will be returned.  For any non-recurring event/task/journal, there should be only one calendar component in the object.  For results from an expanded search, there should be only one calendar component in the object)docc                     | j         }d|v r|d         j        S d|v r|d         j        S d|v rd|v r|d         j        |d         j        z   S dS )a  
        A VTODO may have due or duration set.  Return or calculate due.

        WARNING: this method is likely to be deprecated and moved to
        the icalendar library.  If you decide to use it, please put
        caldav<3.0 in the requirements.
        DUEDTENDrY   rZ   N)rQ   r   r?   rb   s     rB   get_duezCalendarObjectResource.get_due  sd     $A::U8;\\W:= 1__aY<?Qz]%5554rD   no_default_parametersc                 
   ddl m} t          ||          r|                                }n4t          |t                    r|}nt          |t
                    rg|d                             d          rt	          |d                   }nt	          d|d         z             }t          |d                   |j        d<   nt          |t                    rh|                    d          rt          d          |                    d          rt	          |          }nAd|v rd	|vrd
|vrt	          d|z             }n"t          j        d           t	                      }|s1d|j        d<   d|j        vr
d|j        d<   d|j        d<   d|j        d<   i }|D ]3}|                    dd          }||         du rd||<   (||         ||<   4|j                            |           | j        }	|	                    d|           dS )a  
        For the current (event/todo/journal), add an attendee.

        The attendee can be any of the following:
        * A principal
        * An email address prepended with "mailto:"
        * An email address without the "mailto:"-prefix
        * A two-item tuple containing a common name and an email address
        * (not supported, but planned: an ical text line starting with the word "ATTENDEE")

        Any number of attendee parameters can be given, those will be used
        as defaults unless no_default_parameters is set to True:

        partstat=NEEDS-ACTION
        cutype=UNKNOWN (unless a principal object is given)
        rsvp=TRUE
        role=REQ-PARTICIPANT
        schedule-agent is not set
        r   	Principalmailto:r   cnATTENDEEzdo we need to support this anyway?  Should be trivial, but can't figure out how to do it with the icalendar.Event/vCalAddress objects right now@:;FNEEDS-ACTIONpartstatcutypeUNKNOWNTRUErsvpzREQ-PARTICIPANTrole_-TattendeeN)r   r   rr   rj   r   tuple
startswithr   r   r>   NotImplementedErrorr!   r   replaceupdaterQ   rS   )
r?   r  r   r   r   attendee_objr   keynew_keyievents
             rB   add_attendeez#CalendarObjectResource.add_attendee  sM   ( 	*)))))h	** 	)#4466LL+.. 	)#LL%(( 	){%%i00 D*8A;77*9x{+BCC(-hqk(:(:L%%#&& 	)"":.. A) f   $$Y// A*844S%8%8S=P=P*9x+?@@M%   &==L % 	<.<L
+|22209#H-*0L'*;L' 	2 	2Ckk#s++G#$&&"(w",S/w""6***)

:|,,,,,rD   c                 l    |                      d           | j                            dd          dk    S )z
        Returns True if this object is a request, see
        https://www.rfc-editor.org/rfc/rfc2446.html#section-3.2.2
        Tr   methodNREQUESTr   r~   r   r?   s    rB   is_invite_requestz(CalendarObjectResource.is_invite_requestS  s6    
 			4	(((&**8T::iGGrD   c                 l    |                      d           | j                            dd          dk    S )z~
        Returns True if the object is a reply, see
        https://www.rfc-editor.org/rfc/rfc2446.html#section-3.2.3
        Tr   r  NREPLYr  r  s    rB   is_invite_replyz&CalendarObjectResource.is_invite_reply[  s6    
 			4	(((&**8T::gEErD   r   r   c                 2    |                      d|           dS )zE
        Accepts an invite - to be used on an invite object.
        ACCEPTEDN_reply_to_invite_requestr?   r   s     rB   accept_invitez$CalendarObjectResource.accept_invitec        	%%j(;;;;;rD   c                 2    |                      d|           dS )zF
        Declines an invite - to be used on an invite object.
        DECLINEDNr  r   s     rB   decline_invitez%CalendarObjectResource.decline_invitei  r"  rD   c                 2    |                      d|           dS )zP
        Tentatively accept an invite - to be used on an invite object.
        	TENTATIVENr  r   s     rB   tentatively_accept_invitez0CalendarObjectResource.tentatively_accept_inviteo  s      	%%k8<<<<<rD   c                 
   t          j        |                                            |s1| j                                                                        d         }| j                            d           |                     |           | 	                    t          j                    d           	 |                    | j                   d S # t          $ r |                                  | 	                    t          j                    d           | j                                                                        }|j        |j        k    r|                     ||           Y d S |                                  Y d S w xY w)Nr   METHOD)r   T)
use_cachedF)r   )r!   r   r  rH   ri   get_calendarsr~   rR   change_attendee_statusget_propertyr   ScheduleTag	add_eventrJ   	Exceptionr   schedule_outboxrI   r  r   )r?   r   r   outboxs       rB   r  z/CalendarObjectResource._reply_to_invite_requestx  sk   d,,../// 	B{,,..<<>>qAH##H---##X#666$*,,>>>	ty))))) 	 	 	 IIKKKd.00UCCC[**,,<<>>F|vz))--h-HHHHHH			s   3C BF*FFrz   
new_parentc                     |                      |p| j        | j        |r| j        nt	          t          j                                        }|s|s|                                |_        n| j        |_        |S )z
        Events, todos etc can be copied within the same calendar, to another
        calendar or even to another caldav server
        )rK   rJ   rC   )	rV   rK   rJ   rC   r>   uuiduuid1_generate_urlrI   )r?   rz   r4  r   s       rB   r   zCalendarObjectResource.copy  s{    
 nn,"9twwDJLL(9(9  
 

  	X 	''))CGGhCG
rD   r   c                 P   |r|                                  r| S | j        r|                     |          S | j        t	          d          | j        t	          d          	 | j                            t          | j                            }|j        r,|j        dk    r!t          j
        t          |                    |j        | _        n# t          j
        $ r | j        }|r	 |                                 cY S # t           $ r Y nw xY w| j        rt%          | j        d          r~	 | j                            |          }|rK|j        | _        |j        | _        t%          |d          r| j                            |j                   | cY S n# t          j
        $ r Y nw xY w t           $ r |                                 cY S w xY wd|j        v r$|j        d         | j        t.          j        j        <   d	|j        v r$|j        d	         | j        t4          j        j        <   | S )
a  
        (Re)load the object from the caldav server.

        For sync clients, loads and returns self.
        For async clients, returns a coroutine that must be awaited.

        Example (sync):
            obj.load()

        Example (async):
            await obj.load()
        r   N"Unexpected value None for self.urlrf     r   rL   EtagSchedule-Tag)	is_loadedis_async_client_async_loadrI   rh   rH   requestr>   statusr!   r   r#   rawrJ   rC   load_by_multigetr1  rK   r[   r   rL   r  headersr    GetEtagtagr   r/  r?   r   rr@   r   s        rB   r   zCalendarObjectResource.load  si     	 0 0 	K  	G##5E#FFF8ABBB;DEEE	+##CMM22Ax 5AHOO)&))444DII" 	 	 	 'C 0022222    D ; 
74;8K#L#L 
	"k;;C@@ ('*wDH(+DI&sG44 = $
 1 1#) < < <#'KKK( !.    	+ 	+ 	+((*****	+ QY*+)F*;DJs{'QY&&/0y/HDJt'+,sb   #A+C G	(C>;G	>
DG	
DG	+A$FG	G	F%"G	$F%%!G	G	c                 L  K   |r|                                  r| S | j        t          d          | j        t          d          	 | j                            t          | j                             d{V }|j        r,|j        dk    r!t          j        t          |                    |j
        | _        n# t          j        $ r | j        }|r	 |                                  d{V cY S # t          $ r Y nw xY w| j        rt!          | j        d          r	 | j                            |           d{V }|rK|j        | _        |j        | _        t!          |d          r| j                            |j                   | cY S n# t          j        $ r Y nw xY w t          $ r |                                  d{V cY S w xY wd|j        v r$|j        d         | j        t*          j        j        <   d|j        v r$|j        d         | j        t0          j        j        <   | S )	zAsync implementation of load.Nr:  rf   r;  r   rL   r<  r=  )r>  rI   rh   rH   rA  r>   rB  r!   r   r#   rC  rJ   rC   _async_load_by_multigetr1  rK   r[   r   rL   r  rE  r    rF  rG  r   r/  rH  s        rB   r@  z"CalendarObjectResource._async_load  s      	 0 0 	K8ABBB;DEEE	8k))#dh--88888888Ax 5AHOO)&))444DII" 	 	 	'C !%!=!=!?!??????????    D ; 
74;8K#L#L 
	$(K$A$A#$F$FFFFFFF ('*wDH(+DI&sG44 = $
 1 1#) < < <#'KKK( !.    	8 	8 	85577777777777	8 QY*+)F*;DJs{'QY&&/0y/HDJt'+,sb   A1B; ;GC0-G0
C=:G<C==GA*FG
GFGF'GGc                 ^  K   t          j        | j                   | j                            | j        gd           d{V }|st          j        | j                  |d         \  }| _        t          j        | j                   t          j        t          |          dk               | S )z)Async implementation of load_by_multiget.T
event_urlsraise_notfoundNr   r   )r!   r   rI   rK   _async_multigetr   rJ   r   )r?   items_urls      rB   rK  z.CalendarObjectResource._async_load_by_multiget  s      dhk11dhZX\1]]]]]]]] 	0%dh///(didi   c%jjAo&&&rD   c                 `   t          j        | j                   | j                            | j        gd          }t          |d          }|t          j        | j                  |\  }| _        t          j        | j                   t          j        t          |d          du            | S )zn
        Some servers do not accept a GET, but we can still do a REPORT
        with a multiget query
        TrM  N)r!   r   rI   rK   	_multigetnextr   rJ   )r?   mydataurl_datarI   s       rB   rD  z'CalendarObjectResource.load_by_multiget  s    
 	dh&&48*T&RR%%
 %dh///!TYdi   d64((D0111rD   c                    |                      d          }|st          | dd          r| j        }|s'|                    dd          }|rt	          |          }|st          | dd          r| j        }|Y|Wt	          |                              d          r5t          j        dt	          |                    	                    d	          }| t	          t          j                              }|                    dd           |                    d|           | j        j        D ]M}t          |t           j                  s1t%          j        |                    dd          | j        k               N||                                 }n| j        j                            |          }t3          j        |          | _        dS )
a  
        With CalDAV, every object has a URL.  With icalendar, every object
        should have a UID.  This UID may or may not be copied into self.id.

        This method will:

        0) if ID is given, assume that as the UID, and set it in the object
        1) if UID is given in the object, assume that as the ID
        2) if ID is not given, but the path is given, generate the ID from the
           path
        3) If neither ID nor path is given, use the uuid method to generate an
           ID (TODO: recommendation in the RFC is to concat some timestamp, serial or
           random number and a domain)
        4) if no path is given, generate the URL from the ID
        F)r   rC   Nr9   path.icsz(/|^)([^/]*).icsrm   )r   getattrrC   rR   r>   rY  endswithresearchgroupr6  r7  rS   r~   r<   rr   rs   rt   r!   r   r   r8  rK   rI   joinr'   	objectify)r?   rC   rY  rb   rw   s        rB   _find_id_pathz$CalendarObjectResource._find_id_path1  s     ))U);; 	gdD$// 	B 	ud##B WW 	fd33 	9D:$*s4yy/A/A&/I/I*-s4yy99??BBB:TZ\\""B	eT	eR(6 	= 	=Aa!344 =aeeE400DG;<<<<%%''DD;?''--D=&&rD   c                 b   | j                             | j        | j        ddi          }|j        dk    rd |j        D             d         }d S |j        dvrY|r	 dd l}n# t          $ r d}Y nw xY w|r| j         | 	                    d          S t          j        t          |                    d S )NContent-Typetext/calendar; charset="utf-8".  c                 6    g | ]}|d          dk    |d         S r   locationr   rG   ru   s     rB   rx   z/CalendarObjectResource._put.<locals>.<listcomp>b  *    BBBQqtz/A/AAaD/A/A/ArD   r         F)rH   putrI   rJ   rB  rE  vobjectImportErrorvobject_instance_putr!   PutErrorr#   r?   retry_on_failurerI  rY  ro  s        rB   rr  zCalendarObjectResource._put^  s    KOODHdi.Bb1cdd8s??BB!)BBB1EDDDXZ'' --"NNNN" - - -',$$$- 0 %%yy'''nVAYY/// ('s   A A-,A-c                   K   | j                             t          | j                  t          | j                  ddi           d{V }|j        dk    r2d |j        D             d         }t          j        |          | _        dS |j        dvr_|r	 ddl	}n# t          $ r d}Y nw xY w|r"| j         |                     d           d{V S t          j        t          |                    dS )	z(Async version of _put for async clients.rd  re  Nrf  c                 6    g | ]}|d          dk    |d         S rh  rG   ru   s     rB   rx   z5CalendarObjectResource._async_put.<locals>.<listcomp>y  rj  rD   r   rk  F)rH   rn  r>   rI   rJ   rB  rE  r'   ra  ro  rp  rq  
_async_putr!   rs  r#   rt  s        rB   rx  z!CalendarObjectResource._async_putq  s3     +//MM	NN=>
 
 
 
 
 
 
 

 8s??BB!)BBB1ED}T**DHHHXZ'' --"NNNN" - - -',$$$- 0%%!__U333333333nVAYY/// ('s   B B('B(c                 \    |                      ||           |                                  d S )NrC   rY  )rb  rr  )r?   rC   rY  ru  s       rB   _createzCalendarObjectResource._create  s,    bt,,,		rD   c                 l   K   |                      ||           |                                  d{V  dS )z+Async version of _create for async clients.rz  N)rb  rx  )r?   rC   rY  s      rB   _async_createz$CalendarObjectResource._async_create  sG      bt,,,oorD   c                     | j         j                            t          | j                  dz             }dt          |          vsJ |S )NrZ   )rK   rI   r`  r(   rC   r>   )r?   rI   s     rB   r8  z$CalendarObjectResource._generate_url  sF     ko"":dg#6#6#?@@#c((""""
rD   r  c                    ddl m} |s/| j        t          d          | j                                        }d}t          ||          r|                                }|D ]+}	  | j        |fi | |dz  }# t          j	        $ r Y (w xY w|s$t          j	        dt          |          z            t          j        |dk               dS | j        }|d         }t          |t                    r|g}d }	|D ]9}
 |	|
           |	|          k    r|
j                            |           |dz  }:|st          j	        d	          t          j        |dk               dS )
zO
        Updates the attendee-line according to the arguments received
        r   r   Nrf   r   z$Principal %s is not invited to eventr  c                 l    t          |                                                               dd          S )Nr    )r>   lowerr  )rw   s    rB   <lambda>z?CalendarObjectResource.change_attendee_status.<locals>.<lambda>  s$    Q!7!7	2!F!F rD   z)Participant %s not found in attendee list)r   r   rH   rh   ri   rr   calendar_user_address_setr-  r!   r   r>   r   rQ   r   r  )r?   r  kwargsr   cntattendee_emailsaddrr   attendee_linesstrip_mailtoattendee_lines              rB   r-  z-CalendarObjectResource.change_attendee_status  s    	*))))) 	/{" !HIII{,,..Hh	** 	&@@BBO'  /D/?????1HCC*   D b)*PSVW_S`S`*`aaaM#(###F+!*-nc** 	.,-NFF+ 	 	M|M**ll8.D.DDD$++F333q 	S%&QRRRcQhs   #A77B	B	no_overwrite	no_createobj_typeincrease_seqnoif_schedule_tag_matchonly_this_recurrenceall_recurrencesc                 v                                      s S  fd}|s|rddlm}	 s j        j                                         j        p j                            d          }
 |            }|
s|r |	j	        d          |r|r |	j	        d          |r|s |	j	        d          |s|rnd j        v rddd	l
ddlm}	  |            }| |	j        d
          |j        |r|j        } j                                        }dD ]}||v r||         ||<   |j                                        |d         j                                        z
  }|j        }|                    d           |                    d|j        |z              dD ]}||v r|                    |           |                    d|j        |z              |                    d           j        fdt+          dt-                              D             }|d         }||<   |rL|dd	         D ]A}|                             d          }|                             d|j        |z              B|                    |          S |r fdt+          dt-          j                            D             } |	j        t-          |          dk               |r j        j        |d         <   n                     j                   |                    |          S |rDd j        v r; j                            dd	          }| j                            d|dz               j        r j        j        nd	} j        r                     |          S                       j        |            S )a  Save the object, can be used for creation and update.

        no_overwrite and no_create will check if the object exists.
        Those two are mutually exclusive.  Some servers don't support
        searching for an object uid without explicitly specifying what
        kind of object it should be, hence obj_type can be passed.
        obj_type is only used in conjunction with no_overwrite and
        no_create.

        is_schedule_tag_match is currently ignored. (TODO - fix or remove)

        The SEQUENCE should be increased when saving a new version of
        the object.  If this behaviour is unwanted, then
        increase_seqno should be set to False.  Also, if SEQUENCE is
        not set, then this will be ignored.

        The behaviour when saving a single recurrence object to the
        server is as far as I can understand not defined in the RFCs,
        but all servers I've tested against will overwrite the full
        event with the recurrence instance (effectively deleting the
        recurrence rule).  That's almost for sure not what the caller
        intended.  only_this_recurrence and all_recurrences only
        applies when trying to save a recurrence object.  They are by
        nature mutually exclusive, but since only_this_recurrence is
        True by default, it will be ignored if all_recurrences is set.

        If you want to sent the recurrence as it is to the server,
        you should set both all_recurrences and only_this_recurrence
        to False.

        Returns:
         * self

        c                     ddl m}  j        pj                            d          }|rj        r	 sj        j                                        }n}|r9d| d}t          j        |          r t          j        |          |          S t          j        d          rj                            |          S n# | j        $ r Y d S w xY wd S )Nr   r!   r@   get__by_uidr   )
caldav.libr!   rC   rQ   r   rK   rV   __name__r  r[   r[  r   r   )r!   r@   	_obj_typemethod_namer  r?   s       rB   get_selfz-CalendarObjectResource.save.<locals>.get_self  s   (((((('@T599%@@C  t{   # -$(N$;$A$A$C$C		$,	  J&?Y&?&?&?"4;<< J#D74;#D#DS#I#IIt{,?@@ B#{<<SAAAB*      44 4s   AC .C 
CCr   r  r@   z'no_create flag was set, but no ID givenz4no_overwrite flag was set, but object already existsz1no_create flag was set, but object does not existr   Nz%Could not find parent recurring event)r   r   r   r   recurrence-iddtstart)rc   dtendr  c                 J    g | ]}t          |         j                  | S rG   )rr   rt   )rv   rb   rs   r   s     rB   rx   z/CalendarObjectResource.save.<locals>.<listcomp>E  s?       z!A$	HZ7[7[  rD   r   r  c                 r    g | ]3}j         |                             d           j        d          k    1|4S )r  )r<   r   rQ   )rv   rb   icir?   s     rB   rx   z/CalendarObjectResource.save.<locals>.<listcomp>T  s\          (+//@@/@A A A A ArD   SEQUENCErz  )r>  r  r!   rV   r  r  rC   rQ   r   ConsistencyErrorrs   r   r~   r   r   r\   r   rc   rR   rS   r<   r   r   r   r   r   rI   rY  r?  _async_save_finalr{  )r?   r  r  r  r  r  r  r  r  r!   r@   existingr   occnccpropdtstart_diffnew_durationep
comp_idxescomp_idxrb   ridexisting_idxseqnorY  rs   r  r   s   `  `                      @@@rB   r   zCalendarObjectResource.save  s   Z ~~ 	K	 	 	 	 	 	.  	b9 	b(((((( ;>288:: '@T599%@@C  xzzH  X9 X,e,-VWWW e e,e,-cddd b b,e,-`aaa !;	?$3;	?!999(((((((**C{)e)*QRRR(C  ?-.3355B . .Ds{{$'ID	  #y3355O8L8O8Z8Z8\8\\"|	"""	39|#;<<</ $ $BSyy\!9:::(((%    $QA//  
 &a=!(   I'^ I Idhh77!#&<2GHHHHxx~x>>># ?         "1c#*;&<&<==      c,//14555 @9=9QC%l1o66%%d&>???xx~x>>>  	DjD,DDD,00TBBE (,,ZCCC $2tx}}d  	0))$///d+++rD   c                 N   K   |                      | j        |           d{V  | S )z*Async helper for the final save operation.rz  N)r}  rC   )r?   rY  s     rB   r  z(CalendarObjectResource._async_save_finalp  s8        DG$ 777777777rD   c                 Z    |                                  sdS |                                 duS )zReturns True if there exists data in the object.  An
        object is considered not to be loaded if it contains no data
        but just the URL.

        Optimized to use cheap accessors (issue #613).
        FN	_has_datarP   r  s    rB   r>  z CalendarObjectResource.is_loadedu  s2     ~~ 	5--//t;;rD   c                 Z    |                                  sdS |                                 duS )a  
        Returns True if there exists a VEVENT, VTODO or VJOURNAL in the data.
        Returns False if it's only a VFREEBUSY, VTIMEZONE or unknown components.

        Used internally after search to remove empty search results (sometimes Google return such)
        FNr  r  s    rB   has_componentz$CalendarObjectResource.has_component  s2     ~~ 	5--//t;;rD   c                 .    | j         j        d| j        S )Nz: )rV   r  rI   r  s    rB   __str__zCalendarObjectResource.__str__  s    >222DHH==rD   c                 L   t          |          j                            d          r|                     |           | S t          |          j                            d          r|                     |           | S t          j        |          | _        d | _        d | _	        | S )Nro  rs   )
type
__module__r
  _set_vobject_instance_set_icalendar_instancer"   r   rT   _vobject_instancer;   )r?   rJ   s     rB   	_set_dataz CalendarObjectResource._set_data  s    
 :: ++I66 	&&t,,,K:: ++K88 	((...KXd^^
!%#' rD   c                     | j         rt          | j                   S | j        r&t          | j                                                  S | j        r&t          | j                                                  S d S r   )rT   r$   r  	serializer;   to_icalr  s    rB   	_get_dataz CalendarObjectResource._get_data  st    : 	E ,,,# 	E !7!A!A!C!CDDD% 	E !9!A!A!C!CDDDtrD   c                     | j         rt          | j                   S | j        r&t          | j                                                  S | j        r&t          | j                                                  S d S r   )rT   r&   r  r  r;   r  r  s    rB   _get_wire_dataz%CalendarObjectResource._get_wire_data  sq    : 	?4:&&&# 	?41;;==>>>% 	?43;;==>>>trD   z2vCal representation of the object as normal stringz>vCal representation of the object in wire format (UTF-8, CRLN)instvobject.base.Componentc                 X    || _         d | _        d | _        t          |          | _        | S r   )r  rT   r;   r   r2   r?   r  s     rB   r  z,CalendarObjectResource._set_vobject_instance  s-    !%
#' "4((rD   c                    	 dd l }n%# t          $ r t          j        d           Y d S w xY w| j        s|                                 d S 	 |                     |                    t          |                                                                n5#  t                              dt          | j                  z               xY w| j        S )Nr   zA vobject instance has been requested, but the vobject library is not installed (vobject is no longer an official dependency in 2.0)zUSomething went wrong while loading icalendar data into the vobject class.  ical url: )ro  rp  r   criticalr  r  r  readOner%   logr>   rI   )r?   ro  s     rB   _get_vobject_instancez,CalendarObjectResource._get_vobject_instance  s    	NNNN 	 	 	 W   44		
 % 	~~'t	**OOJt~~/?/?$@$@AA   k$(mm$   %%s    ))
AB 2Cc                 b    t          j        dt          d           |                                 S Nz6use event.vobject_instance or event.icalendar_instancerm   rn   )r{   r|   r}   r  r  s    rB    _get_deprecated_vobject_instancez7CalendarObjectResource._get_deprecated_vobject_instance  s8    D	
 	
 	
 	

 ))+++rD   c                 d    t          j        dt          d           |                     |          S r  )r{   r|   r}   r  r  s     rB    _set_deprecated_vobject_instancez7CalendarObjectResource._set_deprecated_vobject_instance  s:    D	
 	
 	
 	

 ))$///rD   zvobject instance of the objectzvobject.base.VBaserq  zavobject instance of the object (DEPRECATED!  This will yield an icalendar instance in caldav 3.0)instancec                    t          |t          j                  s}	 t          j                                        }nF#  t          j                    }|                    dd           |                    dd           Y nxY w|                    |           |}|| _        d | _        d | _        t          |          | _
        | S )Nr   z-//python-caldav//caldav//en_DKr   z2.0)rr   rs   r   newrS   r   r;   rT   r  r   r2   )r?   r  cals      rB   r  z.CalendarObjectResource._set_icalendar_instance  s    $	 233 	*(,,..*(**"CDDD	5)))))d###D#' 
!%$T**s
   ; AA>c                     | j         s?| j        sd S t          j                            t          | j                            | _        | j         S r   )r;   rJ   rs   r   	from_icalr%   r~   r  s    rB   _get_icalendar_instancez.CalendarObjectResource._get_icalendar_instance  sI    ' 	Z9 t&/&8&B&B:diCXCX&Y&YD#''rD   z icalendar instance of the objectr~   c                 2   | j         | j         S | j        t          | j                  | _         nb| j        t	          | j                  | _         nA| j        't          t          | j                            | _         nt                      | _         | j         S )zNEnsure we have a DataState object, migrating from legacy attributes if needed.)	r2   r;   r   r  r   rT   r   r$   r   r  s    rB   _ensure_statez$CalendarObjectResource._ensure_state$  s    ;"; #/()ABBDKK#/&t'=>>DKKZ#&}TZ'@'@AADKK%--DK{rD   c                 N    |                                                                  S )a5  Get raw iCalendar data as string.

        This is always safe to call and returns the current data without
        side effects. If the current representation is a parsed object,
        it will be serialized.

        Returns:
            The iCalendar data as a string, or empty string if no data.
        )r  get_datar  s    rB   r  zCalendarObjectResource.get_data5  s"     !!##,,...rD   c                 N    |                                                                  S )a  Get a COPY of the icalendar object for read-only access.

        This is safe for inspection - modifications to the returned object
        will NOT be saved. For editing, use edit_icalendar_instance().

        Returns:
            A copy of the icalendar.Calendar object.
        )r  get_icalendar_copyr  s    rB   get_icalendar_instancez-CalendarObjectResource.get_icalendar_instanceA  s"     !!##66888rD   c                 N    |                                                                  S )a  Get a COPY of the vobject object for read-only access.

        This is safe for inspection - modifications to the returned object
        will NOT be saved. For editing, use edit_vobject_instance().

        Returns:
            A copy of the vobject component.
        )r  get_vobject_copyr  s    rB   get_vobject_instancez+CalendarObjectResource.get_vobject_instanceL  s"     !!##44666rD   c              #   n  K   | j         rt          d          |                                 }t          |t                    s=|                                }t	          |          | _        d| _        d| _        || _	        d| _         	 | j        
                                V  d| _         dS # d| _         w xY w)aE  Context manager to borrow the icalendar object for editing.

        Usage::

            with event.edit_icalendar_instance() as cal:
                cal.subcomponents[0]['SUMMARY'] = 'New Summary'
            event.save()

        While inside the context, the icalendar object is the authoritative
        source. Accessing other representations (vobject) while borrowed
        will raise RuntimeError.

        Yields:
            The authoritative icalendar.Calendar object.

        Raises:
            RuntimeError: If another representation is currently borrowed.
        zxCannot borrow icalendar - another representation is already borrowed. Complete the current edit before starting another.NTF)r3   RuntimeErrorr  rr   r   r  r2   rT   r  r;   get_authoritative_icalendar)r?   stater  s      rB   edit_icalendar_instancez.CalendarObjectResource.edit_icalendar_instanceW  s      ( > 	E  
 ""$$ %00 	+**,,C(--DKDJ%)D"'*D$	#+99;;;;;"DNNNUDN""""   B+ +	B4c              #   n  K   | j         rt          d          |                                 }t          |t                    s=|                                }t	          |          | _        d| _        d| _        || _	        d| _         	 | j        
                                V  d| _         dS # d| _         w xY w)a4  Context manager to borrow the vobject object for editing.

        Usage::

            with event.edit_vobject_instance() as vobj:
                vobj.vevent.summary.value = 'New Summary'
            event.save()

        While inside the context, the vobject object is the authoritative
        source. Accessing other representations (icalendar) while borrowed
        will raise RuntimeError.

        Yields:
            The authoritative vobject component.

        Raises:
            RuntimeError: If another representation is currently borrowed.
        zvCannot borrow vobject - another representation is already borrowed. Complete the current edit before starting another.NTF)r3   r  r  rr   r   r  r2   rT   r;   r  get_authoritative_vobject)r?   r  vobjs      rB   edit_vobject_instancez,CalendarObjectResource.edit_vobject_instance  s      ( > 	E  
 ""$$ %.. 	*))++D&t,,DKDJ'+D$%)D"	#+7799999"DNNNUDN""""r  c                 N    |                                                                  S )zGet UID without triggering format conversions.

        This is for internal use where we just need to peek at the UID
        without needing to modify anything.
        )r  get_uidr  s    rB   r:   z%CalendarObjectResource._get_uid_cheap  s"     !!##++---rD   c                 N    |                                                                  S )zGet component type (VEVENT/VTODO/VJOURNAL) without parsing.

        This is for internal use to quickly determine the type.
        )r  get_component_typer  s    rB   rP   z0CalendarObjectResource._get_component_type_cheap  s"    
 !!##66888rD   c                 N    |                                                                  S )z9Check if we have any data without triggering conversions.)r  has_datar  s    rB   r  z CalendarObjectResource._has_data  s     !!##,,...rD   c                 :    | j         }|                     |          S )a*  According to the RFC, either DURATION or DUE should be set
        for a task, but never both - implicitly meaning that DURATION
        is the difference between DTSTART and DUE (personally I
        believe that's stupid.  If a task takes five minutes to
        complete - say, fill in some simple form that should be
        delivered before midnight at new years eve, then it feels
        natural for me to define "duration" as five minutes, DTSTART
        to "some days before new years eve" and DUE to 20xx-01-01
        00:00:00 - but I digress.

        This method will return DURATION if set, otherwise the
        difference between DUE and DTSTART (if both of them are set).

        TODO: should be fixed for Event class as well (only difference
        is that DTEND is used rather than DUE) and possibly also for
        Journal (defaults to one day, probably?)

        WARNING: this method is likely to be deprecated and moved to
        the icalendar library.  If you decide to use it, please put
        caldav<3.0 in the requirements.
        )rQ   _get_durationr   s     rB   r^   z#CalendarObjectResource.get_duration  s     , $!!!$$$rD   c                    d|v r|d         j         S d|v r| j        |v r|| j                 j         }|d         j         }t          |t                    t          |t                    k    r@t          |j        |j        |j                  }t          |j        |j        |j                  }||z
  S d|v r+t          |d         t                    st          d          S t          d          S )NrY   rZ   r   )daysr   )r   r_   rr   r   yearmonthdayr   )r?   rb   r`   r   s       rB   r  z$CalendarObjectResource._get_duration  s    ??Z=##!^^! 3 3DN#&CiLOE #x((Juh,G,GGG U[%)DDsxCG<<;!^^Jq|X$F$F^!$$$$Q<<rD   )NNNNNN)Fr4   N)T)NT)NNTT)FFFr   )FNNN)NNT)FFNTFTF)r  r  )r4   r  )hr  r  __qualname____doc__r1   r   __annotations__r_   r  r;   rT   r2   r   r3   boolpropertyr>   rC   setterr	   r
   r   r'   r   rO   rd   rk   r   r   r   r   r   r   r   r   r   r   r   r   r	  r   r   r   r   r   r   rQ   	componentr   	get_dtendr  r  r  r!  r%  r(  r  r   r   r@  rK  rD  rb  rr  rx  r{  r}  r8  r-  r   r  r>  r  r  r  r  r  rJ   	wire_datar  r  r  r  rq  r  r  r  r~   r  r  rs   r   r  r  r   r  r  r:   rP   r  r   r^   r  __classcell__)rV   s   @rB   r+   r+   =   s
         * %$% %    IE  $FI###ItC$J    X" Yd
 t    Y )-<@! G G%G ;,s2T9G Dj	G
 d
G $JG TzG 
G G G G G G2# # # #.P P P P T
        D4/ 4/( 4/ 4/d 4/^b 4/ 4/ 4/ 4/n 04*	* * * *b +/26"#: :C.4': SE4K(4/: 	:
 : 
S#c(]	#: : : :x9 9 9%     DI )-<@	   @	O 	O4 	ODK 	O 	O 	O 	O	N 	N 	N$ 	N 	N 	N 	N   6
2 
2 
2 
2 #(   a   $I  $ I?- ?-D ?-[_ ?- ?- ?- ?-BH4 H H H HF F F F F< <hz&: <d < < < << <x
'; <t < < < <= =#* = = = = =   2 T sTz T    $? ?T ?d ? ? ? ?B+ +$ +4 + + + +Z	t 	 	 	 	$    *+' +' +' +' +'Z0 0 0 0&0 0 0 0,    
         
  '  ' sTz ' t '  '  '  ' V ###&+%) %l ll l *	l
 l  $l #l l 
l l l l\t    
< < <	<t 	< 	< 	< 	<> > > > >  $     9"V  D#    L  I   &x0H'I & & & &2,(;S2T , , , ,0 0 0 0 .6X,. . .*    &.X((o& & &H"     (( ( ( 'h.     y    "
/# 
/ 
/ 
/ 
/	9	(: 	9 	9 	9 	9	7 	7 	7 	7 (# (# ^(#T (# (# ^(#X.d
 . . . .93: 9 9 9 9/4 / / / /%i % % % %2             rD   r+   c                   $    e Zd ZdZej        ZdZdS )r   z
    The `Event` object is used to represent an event (VEVENT).

    As of 2020-12 it adds very little to the inheritated class.  (I have
    frequently asked myself if we need those subclasses ... perhaps
    not)
    r   N)r  r  r  r  r+   rd   	set_dtendr_   rG   rD   rB   r   r     s'          '.IIIIrD   r   c                       e Zd ZdZdS )r   z
    The `Journal` object is used to represent a journal entry (VJOURNAL).

    As of 2020-12 it adds nothing to the inheritated class.  (I have
    frequently asked myself if we need those subclasses ... perhaps
    not)
    N)r  r  r  r  rG   rD   rB   r   r     s          	DrD   r   c                   J    e Zd ZdZ	 	 ddeez  ez  ez  dz  dedz  ddfdZ	dS )r   a  
    The `FreeBusy` object is used to represent a freebusy response from
    the server.  __init__ is overridden, as a FreeBusy response has no
    URL or ID.  The inheritated methods .save and .load is moot and
    will probably throw errors (perhaps the class hierarchy should be
    rethought, to prevent the FreeBusy from inheritating moot methods)

    Update: With RFC6638 a freebusy object can have a URL and an ID.
    NrI   rC   r4   c                 P    t                               | |j        ||||           d S )N)rH   rI   rJ   rK   rC   )r+   rO   rH   )r?   rK   rJ   rI   rC   s        rB   rO   zFreeBusy.__init__  s:     	''Cd6b 	( 	
 	
 	
 	
 	
rD   r   )
r  r  r  r  r>   r
   r   r'   r   rO   rG   rD   rB   r   r     sv          =A	
 	
 ;,s2T9		

 $J	
 
	
 	
 	
 	
 	
 	
rD   r   c            	           e Zd ZdZdZddZddefdZd Zdd	Z		 	 	 dde
dz  deded         ddfdZdddZddedz  fdZddZddZdddZddZeZdS )r   a  The `Todo` object is used to represent a todo item (VTODO).  A
    Todo-object can be completed.

    There is some extra logic here - arguably none of it belongs to
    the caldav library, and should be moved either to the icalendar
    library or to the plann library (plann is a cli-tool, should
    probably be split up into one library for advanced calendaring
    operations and the cli-tool as separate packages)
    r   NTc                 j   |s| j         }|s|d         }|sr|du s|At          d |D                       r(d|v r|d         j        }nA|pt          j                    }n+|p(t          j                    |                     |          z
  }t          |d          r|                    t          j	                  }|s|}|r-d|v r)|
                                }|                    d           t          |                                                    d          |	          }|                    |          S )
ab  Special logic to fint the next DTSTART of a recurring
        just-completed task.

        If any BY*-parameters are present, assume the task should have
        fixed deadlines and preserve information from the previous
        dtstart.  If no BY*-parameters are present, assume the
        frequency is meant to be the interval between the tasks.

        Examples:

        1) Garbage collection happens every week on a Tuesday, but
        never earlier than 09 in the morning.  Hence, it may be
        important to take out the thrash Monday evenings or Tuesday
        morning.  DTSTART of the original task is set to Tuesday
        2022-11-01T08:50, DUE to 09:00.

        1A) Task is completed 07:50 on the 1st of November.  Next
        DTSTART should be Tuesday the 7th of November at 08:50.

        1B) Task is completed 09:15 on the 1st of November (which is
        probably OK, since they usually don't come before 09:30).
        Next DTSTART should be Tuesday the 7th of November at 08:50.

        1C) Task is completed at the 5th of November.  We've lost the
        DUE, but the calendar has no idea weather the DUE was a very
        hard due or not - and anyway, probably we'd like to do it
        again on Tuesday, so next DTSTART should be Tuesday the 7th of
        November at 08:50.

        1D) Task is completed at the 7th of November at 07:50.  Next
        DTSTART should be one hour later.  Now, this is very silly,
        but an algorithm cannot do guesswork on weather it's silly or
        not.  If DTSTART would be set to the earliest possible time
        one could start thinking on this task (like, Monday evening),
        then we would get Tue the 14th of November, which does make
        sense.  Unfortunately the icalendar standard does not specify
        what should be used for DTSTART and DURATION/DUE.

        1E) Task is completed on the 7th of November at 08:55.  This
        efficiently means we've lost the 1st of November recurrence
        but have done the 7th of November recurrence instead, so next
        timestamp will be the 14th of November.

        2) Floors at home should be cleaned like once a week, but
        there is no fixed deadline for it.  For some people it may
        make sense to have a routine doing it i.e. every Tuesday, but
        this is not a strict requirement.  If it wasn't done one
        Tuesday, it's probably even more important to do it Wednesday.
        If the floor was cleaned on a Saturday, it probably doesn't
        make sense cleaning it again on Tuesday, but it probably
        shouldn't wait until next Tuesday.  Rrule is set to
        FREQ=WEEKLY, but without any BYDAY.  The original VTODO is set
        up with DTSTART 16:00 on Tuesday the 1st of November and DUE
        17:00.  After 17:00 there will be dinner, so best to get it
        done before that.

        2A) Floor cleaning was finished 14:30.  The next recurrence
        has DTSTART set to 13:30 (and DUE set to 14:30).  The idea
        here is that since the floor starts accumulating dirt right
        after 14:30, obviously it is overdue at 16:00 Tuesday the 7th.

        2B) Floor cleaning was procrastinated with one day and
        finished Wednesday at 14:30.  Next instance will be Wednesday
        in a week, at 14:30.

        2C) Floor cleaning was procrastinated with two weeks and
        finished Tuesday the 14th at 14:30. Next instance will be
        Tuesday the 21st at 14:30.

        While scenario 2 is the most trivial to implement, it may not
        be the correct understanding of the RFC, and it may be tricky
        to get the RECURRENCE-ID set correctly.

        RRULETNc              3   D   K   | ]}|                     d           |V  dS )BYN)r
  ru   s     rB   r   zTodo._next.<locals>.<genexpr>  s4      0X0XqQ\\RVEWEW0X0X0X0X0X0X0XrD   rZ   r\   COUNTzutf-8)r  )rQ   r   r   r   nowr  r[   r\   r   r]   r   rR   r   r  decodeafter)r?   tsrb   r  r   byno_counts          rB   _nextz
Todo._next/  sA   V  	)(A 	gJE 	GTzzbjS0X0XE0X0X0X-X-Xj>>	loGG 2HLNNGGF1C1CA1F1F F 7L)) 	7((66G 	B 	5((JJLLEIIg//88'JJJ{{2rD   r4   c                     |s| j         }d|d         v r6|d         d         d         dk    rdS |d         d         dxx         dz  cc<   dS )Nr  r  r   r   FT)rQ   r   s     rB   _reduce_countzTodo._reduce_count  si     	)(Aaj  z'"1%**ugJw"""a'"""trD   c                    |                                  s|                     d          S |                     |          }|s|                     d          S |                                 }| j        j                            |j        dz             |_        |j        	                    d           |
                                 |                                 |                                 }| j        }|	                    dd           |                    d|           |                     |d           | 
                                 dS )	aD  This mode will create a new independent task which is
        marked as completed, and modify the existing recurring task.
        It is probably the most safe way to handle the completion of a
        recurrence of a recurring task, though the link between the
        completed task and the original task is lost.
        F)handle_rrulerZ  r  rZ   Nr   )movable_attr)r  completer  r   rK   rI   r`  rC   rQ   rR   r   r^   rS   set_duration)r?   completion_timestampnext_dtstart	completedrc   rb   s         rB   _complete_recurring_safezTodo._complete_recurring_safe  s+    !!## 	5==e=444zz"677 	5==e=444IIKK	,,Y\F-BCC	%))'222$$&&$	i	i&&&(777		rD   c                 B     j         j        }|d         }d|vrd|d<   t          |          dk    r|                                }|                    d           |                    d|                    d|                     |                    dd          }|                    d|dz              |                    |           |d	         }|                    d|d                   }|                                }|                    dd          }|                    d|dz              t          |          d
k    rU|d         j                            dd          dk    r!|d         j                            d           nt          d           
                    ||           |                    dd           |                    d                     ||                     d|d         j        d<   |                    dd          }	|	U|	                    dd          }
|
&|
d         dv r|D ]} 
                    ||           |                    d|	           nr|                    dd          }
|
Z|
d         t           fd|D                       k    r5 
                    |d         |                                d           dS |	p|}                     |          }|                    dd           |                    dd                                |||          }|                    d|                                ||d            j         j                            |                                d           dS )a  The RFC is not much helpful, a lot of guesswork is needed
        to consider what the "right thing" to do wrg of a completion of
        recurring tasks is ... but this is my shot at it.

        1) The original, with rrule, will be kept as it is.  The rrule
        string is fetched from the first subcomponent of the
        icalendar.

        2) If there are multiple recurrence instances in subcomponents
        and the last one is marked with RANGE=THISANDFUTURE, then
        select this one.  If it has the rrule property set, use this
        rrule rather than the original one.  Drop the RANGE parameter.
        Calculate the next RECURRENCE-ID from the DTSTART of this
        object.  Mark task as completed.  Increase SEQUENCE.

        3) Create a new recurrence instance with RANGE=THISANDFUTURE,
        without RRULE set (Ref
        https://github.com/Kozea/Radicale/issues/1264).  Set the
        RECURRENCE-ID to the one calculated in #2.  Calculate the
        DTSTART based on rrule and completion timestamp/date.
        r   r   r   r   r  r   rZ   r  rm   RANGENTHISANDFUTUREzmultiple instances found, but last one is not of type THISANDFUTURE, possibly this has been created by some incompatible client, but we should deal with it)rb   r   r  )r   r   r$  c                 >    g | ]}                     |          |S rG   )
is_pending)rv   rw   r?   s     rB   rx   z:Todo._complete_recurring_thisandfuture.<locals>.<listcomp>   s*    BBBqtq/A/ABBBBrD   Fr  )rb   r   )rb   r   r  )rb   rc   r!  )r~   r<   r   r   rR   rS   r   r   r   r  _complete_icalr  r   r  _set_duration)r?   r$  recurrencesorigjust_completedr  prevr   thisandfuturerrule2countrb   rc   r%  s   `             rB   !_complete_recurring_thisandfuturez&Todo._complete_recurring_thisandfuture  s   , -;1~4+DN{q  !YY[[Nw'''DX0Y0YZZZ"&&z155Ez519555~...2$w-00		!!*a00*eai000
 {aO$+//>>/QQ_%,009999) r   	D"6777/4000/4::E:+J+JKKK9Ho&-g6""7D11 JJw--E U1X%7%7$ V VA''@T'UUUUgv....IIgt,,E U1XBBBBKBBB2 2 & & ##KNI]#^^^			///%%%%--)T***%&&&zzD:NzOO)\222]XERRR-44]CCC			'''''rD   Fsafer$  r   
rrule_mode)r9  this_and_futurec                     |st          j        t          j                  }d| j        v r|r t          | d|z            |          S |                     |           |                                  dS )a  Marks the task as completed.

        Parameters
        ----------
        completion_timestamp : datetime
            Defaults to ``datetime.now()``.
        handle_rrule : Bool
            If set to True, the library will try to be smart if
            the task is recurring.  The default is False, for backward
            compatibility.  I may consider making this one mandatory.
        rrule_mode : str
            The RFC leaves a lot of room for interpretation on how
            to handle recurring tasks, and what works on one server may break at
            another.  The following modes are accepted:
            * this_and_future - see doc for _complete_recurring_thisandfuture for details
            * safe - see doc for _complete_recurring_safe for details
        r  z_complete_recurring_%sr,  N)r   r  r   r]   rQ   r[  r/  r   )r?   r$  r   r:  s       rB   r"  zTodo.complete  s{    . $ 	>#+<#=#= d...<.G74!9J!FGGH\]]]1EFFF		rD   c                     || j         }|                     |          sJ |                    dd           }|                    dd           |                    d|           d S )Nr   r   )rQ   r.  rR   rS   )r?   rb   r$  rB  s       rB   r/  zTodo._complete_ical0  si    9(Aq!!!!!x&&	h$$$	k/00000rD   c                     || j         }|                    dd           dS |                    dd          dv rdS |                    dd          dv rdS J )Nr   Fr   r   )r   z
IN-PROCESST)r   r   )rQ   r   r   s     rB   r.  zTodo.is_pending8  sk    9(A55d##/555>**.LLL455>**.HHH5rD   c                     d| j         v r| j                             d           | j                             dd           d| j         v r| j                             d           |                                  dS )z9Undo completion - marks a completed task as not completedrB  r   r&  N)rQ   rR   rS   r   r  s    rB   
uncompletezTodo.uncompleteD  sx     t///$((222 $$X~>>>$222$((555		rD   rZ   c                 >    | j         }|                     |||          S )a  
        If DTSTART and DUE/DTEND is already set, one of them should be moved.  Which one?  I believe that for EVENTS, the DTSTART should remain constant and DTEND should be moved, but for a task, I think the due date may be a hard deadline, hence by default we'll move DTSTART.

        TODO: can this be written in a better/shorter way?

        WARNING: this method may be deprecated and moved to
        the icalendar library at some point in the future.
        )rQ   r0  )r?   rc   r!  rb   s       rB   r#  zTodo.set_durationP  s$     $!!!X|<<<rD   c                 <   d|v sd|v rd|v r|                     |d            |dk    r|                     dd            |dk    r&|                    d|d         j        |z
             d S |dk    r&|                    d|d         j        |z              d S d S d|v r&|                    d|d         j        |z
             d S d|v r&|                    d|d         j        |z              d S d|v r|                     d           |                    d|           d S )Nr   rY   rZ   )rR   rS   r   )r?   rb   rc   r!  s       rB   r0  zTodo._set_duration\  sG   QJJ*//yA~~EE,%%%u$$j$'''y((i5x!788888&&eQy\_x788888 '&aZZEE)QuX[8344444!^^EE%98344444Qj!!!EE*h'''''rD   c                 *   | j         }t          |d          r&|j        s|                    t          j                  }|r|                     dh          }|d         D ]}|                                }t          |d          r&|j        s|                    t          j                  }|rJ|                    d          |                    d          k     r|dk    r|c S t          j
        d          t                              | ||           dS )a6  The RFC specifies that a VTODO cannot have both due and
        duration, so when setting due, the duration field must be
        evicted

        check_dependent=True will raise some error if there exists a
        parent calendar component (through RELATED-TO), and the parents
        due or dtend is before the new dtend).

        WARNING: this method may become deprecated and parts of
        it moved to the icalendar library at some point in the future.

        WARNING: the check_dependent-logic may be rewritten to support
        RFC9253 in 3.x
        rX   r-   z%sr4   zkparent object has due/end %s, cannot procrastinate child object without first procrastinating parent objectN)rQ   r[   rX   r\   r   r]   r   r  strftimer!   r  r+   rd   )r?   duera   check_dependentrb   parentsrK   pends           rB   set_duezTodo.set_duen  s$    $3!! 	/#* 	/....C 	(((44G!(+  ''))4** 94; 9??8<88D DMM$//#,,t2D2DDD&(22%0 F   	&&tS,?????rD   )NNNNNTr   r  )NFr9  r   )rZ   )FF)r  r  r  r  r_   r  r  r  r'  r8  r   r   r"  r/  r.  r@  r#  r0  rI  rd   rG   rD   rB   r   r   "  sr         Ie e e eN t      8T( T( T( T(p 15"9?	 &o  56	
 
   >1 1 1 1 1
 
D4K 
 
 
 
	 	 	 	
= 
= 
= 
=( ( ( ( ($ @  @  @  @D GGGrD   r   )Dr  r   r]  sysr6  r{   collectionsr   r   r   r   typingr   r   r	   urllib.parser
   r   rs   dateutil.rruler   r   r   r   date	TimeStamp	davclientr   collections.abcr   r   r   version_infotyping_extensionsr   
contextlibr   	datastater   r   r   r   r   	davobjectr   elementsr   r    libr!   r"   	lib.errorr#   lib.python_utilitiesr$   r%   r&   lib.urlr'   operations.calendarobject_opsr(   	getLoggerr  r+   r   r   r   r   rG   rD   rB   <module>r_     sw  
 
  				 



   # # # # # # 2 2 2 2 2 2 2 2 2 2 / / / / / / / / / / 1 1 1 1 1 1 1 1     # # # # # # ( ( ( ( ( ( ( (	)))))))))II	D %%%%%%%$$$$$$ / / / / / / / /      g&&&&&&& % % % % % % Y Y Y Y Y Y Y Y Y Y Y Y Y Y                                   D D D D D D D D D D       5 5 5 5 5 5g!!r  r  r  r  r Y r  r  r j-
 
 
 
 
" 
 
 
		 		 		 		 		$ 		 		 		
 
 
 
 
% 
 
 
.n n n n n! n n n n ns   A   A$