""" Gets pending events from the system in iCalendar (RFC 2445) format. """ RESPONSE.setHeader('Content-Type','text/calendar') from DateTime import DateTime zcat=context.portal_catalog cal=context.portal_calendar # lines shouldn't be longer than 75 bytes according to the spec. # The default value here gives us some slack. lineLen=60 # Weirdly the spec insists on that least efficient of line endings: the # CRLF rather than either the CR or LF by itself. This section just # handles the (mostly constant) header. iCalendar='BEGIN:VCALENDAR\r\nCALSCALE:GREGORIAN\r\n' iCalendar='%sX-WR-TIMEZONE;VALUE=TEXT:%s\r\n'%(iCalendar,DateTime().timezone()) iCalendar='%sX-WR-CALDESC;VALUE=TEXT:Zope CMF Calendar%s\r\n'%(iCalendar) iCalendar='%sPRODID:-//Zope CMF//iCalendar 1.0a//%s\r\n'%(iCalendar,context.Language() or 'EN') iCalendar='%sX-WR-CALNAME;VALUE=TEXT:%s Calendar\r\n'%(iCalendar,context.getPublisher()) iCalendar='%s%s\r\n'%(iCalendar,'VERSION:2.0') # This section handles the individual events in the calendar, converting # them to iCalendar VEVENTS. for objCat in zcat(portal_type=cal.getCalendarTypes(), review_state='published', start=DateTime().earliestTime(), start_usage='range:min', sort_on='start', sort_order='reverse'): obj=objCat.getObject() iCalendar='%sBEGIN:VEVENT\r\n'%(iCalendar) # All iCalendar dates are unfortunately a bastardization of HTML4 style dates creationDate=DateTime(obj.CreationDate()).HTML4().replace('-','').replace(':','') startTime=DateTime.HTML4(obj.start()).replace('-','').replace(':','') endTime=DateTime.HTML4(obj.end()).replace('-','').replace(':','') iCalendar='%sDTSTAMP:%s\r\n'%(iCalendar,creationDate) iCalendar='%sUID:%s\r\n'%(iCalendar,obj.event_email or obj.id) # We're living a little dangerously by not checking the length of the title # and hoping it (plus the string "SUMMARY:") will be under the 75 bytes. # We're also relying on it not containing HTML. title=context.html2txt(obj.title.strip()).replace(',','\,').replace(';','\;') or 'None Provided' iCalendar='%sSUMMARY:%s\r\n'%(iCalendar,title) # This section "folds" the potentially long description via the spec description='' workStr=context.html2txt(obj.description.strip()).replace('\r',' ').replace('\n',' ').replace(',','\,').replace(';','\;') numLinesToBeProcessed=len(workStr)/lineLen startingChar=0 while numLinesToBeProcessed>=1: description='%s%s\r\n '%(description,workStr[startingChar:startingChar+lineLen]) startingChar+=lineLen numLinesToBeProcessed-=1 description='%s%s'%(description,workStr[startingChar:]) # The DESCRIPTION, ORGANIZER, CONTACT, and LOCATION are all optional but # are filled in here if provided. if description: iCalendar='%sDESCRIPTION:%s\r\n'%(iCalendar,description) if obj.event_email: iCalendar='%sORGANIZER:MAILTO:%s\r\n'%(iCalendar,obj.event_email) if obj.event_phone: iCalendar='%sCONTACT:%s\r\n'%(iCalendar,obj.event_phone) if obj.location: iCalendar='%sLOCATION:%s\r\n'%(iCalendar,context.html2txt(obj.location.strip())) iCalendar='%sDTSTART:%s\r\n'%(iCalendar,startTime) iCalendar='%sDTEND:%s\r\n'%(iCalendar,endTime) iCalendar='%sTZNAME:%s\r\n'%(iCalendar,DateTime().strftime('%Z')) iCalendar='%sEND:VEVENT\r\n'%(iCalendar) # This section handles the constant footer. iCalendar='%sEND:VCALENDAR\r\n'%(iCalendar) return iCalendar