#!/usr/bin/env python # Read an ICS file, break it into "documents" which are events, todos, # or journal entries, and interface with recoll execm # # For historical reasons, this can use either the icalendar or the # vobject Python modules, or an internal splitter. The default is now # to use the internal splitter, the other modules are more trouble # than they're worth (to us and until we will want to get into date # computations etc.) import rclexecm import sys # Decide how we'll process the file. modules = ('internal', 'icalendar', 'vobject') usemodule = 'internal' forcevobject = 0 if usemodule != 'internal': try: if forcevobject: raise Exception from icalendar import Calendar, Event usemodule = 'icalendar' except: try: import vobject usemodule = 'vobject' except: print "RECFILTERROR HELPERNOTFOUND python:icalendar" print "RECFILTERROR HELPERNOTFOUND python:vobject" sys.exit(1); class IcalExtractor: def __init__(self, em): self.file = "" self.contents = [] self.em = em self.em.setmimetype("text/plain") def extractone(self, index): if index >= len(self.contents): return(False, "", "", True) docdata = self.contents[index] #self.em.rclog(docdata) iseof = rclexecm.RclExecM.noteof if self.currentindex >= len(self.contents) -1: iseof = rclexecm.RclExecM.eofnext return (True, docdata, str(index), iseof) ###### File type handler api, used by rclexecm ----------> def openfile(self, params): self.file = params["filename:"] try: calstr = open(self.file, 'rb') except Exception, e: self.em.rclog("Openfile: open: %s" % str(e)) return False self.currentindex = 0 if usemodule == 'internal': self.contents = ICalSimpleSplitter().splitcalendar(calstr) elif usemodule == 'icalendar': try: cal = Calendar.from_string(calstr.read()) except Exception, e: self.em.rclog("Openfile: read or parse error: %s" % str(e)) return False self.contents = cal.walk() self.contents = [item.as_string() for item in self.contents if (item.name == 'VEVENT' or item.name == 'VTODO' or item.name == 'VJOURNAL')] else: try: cal = vobject.readOne(calstr) except Exception, e: self.em.rclog("Openfile: cant parse object: %s" % str(e)) return False for lstnm in ('vevent_list', 'vtodo_list', 'vjournal_list'): lst = getattr(cal, lstnm, []) for ev in lst: self.contents.append(ev.serialize()) #self.em.rclog("openfile: Entry count: %d"%(len(self.contents))) return True def getipath(self, params): try: index = int(params["ipath:"]) except: return False return self.extractone(index) def getnext(self, params): if self.currentindex >= len(self.contents): self.em.rclog("getnext: EOF hit") return (False, "", "", rclexecm.RclExecM.eofnow) else: ret= self.extractone(self.currentindex) self.currentindex += 1 return ret # Trivial splitter: cut objects on BEGIN/END (only for 'interesting' objects) # ignore all other syntax class ICalSimpleSplitter: # Note that if an 'interesting' element is nested inside another one, # it will not be extracted (stay as text in external event). This is # not an issue and I don't think it can happen with the current list interesting = ('VTODO', 'VEVENT', 'VJOURNAL') def splitcalendar(self, fin): curblkname = '' curblk = '' lo = [] for line in fin: line = line.rstrip() if line == '': continue if curblkname: curblk = curblk + line + "\n" l = line.split(":") if len(l) < 2: continue # If not currently inside a block and we see an # 'interesting' BEGIN, start block if curblkname == '' and l[0].upper() == "BEGIN" : name = l[1].upper() if name in ICalSimpleSplitter.interesting: curblkname = name curblk = curblk + line + "\n" # If currently accumulating block lines, check for end if curblkname and l[0].upper() == "END" and \ l[1].upper() == curblkname: lo.append(curblk) curblkname = '' curblk = '' if curblk: lo.append(curblk) curblkname = '' curblk = '' return lo ##### Main program: either talk to the parent or execute test loop e = rclexecm.RclExecM() ical = IcalExtractor(e) if len(sys.argv) == 1: e.mainloop(ical) else: # Got a file name parameter: testing without an execm parent # Loop on all entries if not ical.openfile({'filename:':sys.argv[1]}): print "Open error" sys.exit(1) ecnt = 0 while 1: ok, data, ipath, eof = ical.getnext("") if ok: ecnt = ecnt + 1 print "=========== ENTRY %d =================" % ecnt print data print else: print "Got error, eof %d"%eof break