emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* script to transfer schedule from org-mode to Microsoft Outlook
@ 2010-05-13 11:27 Emin.shopper Martinian.shopper
  0 siblings, 0 replies; only message in thread
From: Emin.shopper Martinian.shopper @ 2010-05-13 11:27 UTC (permalink / raw)
  To: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 355 bytes --]

Dear Experts,

I find org-mode very useful but also need to sync my calendar with
outlook. To do that, I use the attached Org2CSV.py script along with a
modified version of the Orgnode.py script from Charles Cave (also
attached). Once I have the CSV I can import it into Outlook or Google
Calendar. I'm sending in case others find it useful.

Best,
-Emin

[-- Attachment #2: Org2CSV.py --]
[-- Type: text/x-python, Size: 3316 bytes --]

"""Script to take scheduled items in an org-mode file and export to CSV.

Once you have the CSV file you can import it into Microsoft Outlook
or Google's Calendar.
"""


import glob, csv, datetime, sys
import Orgnode

def MakeCSV(globPattern, output, onlyToday=True,
            defaultReminder=datetime.timedelta(minutes=5)):
    """Make a CSV file representing all scheduled items.

    INPUTS:

    -- globPattern:        File name or pattern (e.g., ~/org/*.org)
                           representing files to process.

    -- output:             Name of output csv file to write to.

    -- onlyToday=True:     Whether to only output today's items (if True)
                           or output all items (if False).

    -- defaultReminder=datetime.timedelta(minutes=5):

                           Offset for reminders. A reminder will be
                           generated this amount prior to each scheduled
                           item with a start time.

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

    PURPOSE:    Create a CSV file from org-mode files so that the
                schedule can be imported into Microsoft Outlook or
                Google calendar.

    """
    today = datetime.date.today().timetuple()[0:3]
    out = open(output, 'wb')
    writer = csv.writer(out)
    writer.writerow(["Subject", "Start Date", "Start Time", "End Date",
                     "End Time", "All day event",  "Description",
                     "Show time as", "Location", "Reminder Date",
                     "Reminder Time", "Reminder on/off"])
    for fileName in glob.glob(globPattern):
        for n in Orgnode.makelist(fileName):
            if (n.scheduled and (
                not onlyToday or n.scheduled.timetuple()[0:3] == today)):
                row = [n.headline, n.scheduled, n.starttime, n.scheduled,
                       n.endtime, 'FALSE', n.body, 3, '', '', '', '']
                if (row[2]):
                    row[2] = row[2].strftime('%H:%M:00')
                if (row[4]):
                    row[4] = row[4].strftime('%H:%M:00')
                if (row[2] and defaultReminder is not None):
                    row[-3] = row[1]
                    row[-2] = (n.starttime-defaultReminder).strftime('%H:%M:00')
                    row[-1] = "TRUE"
                 
                writer.writerow(row)

def MakeUsage():
    'Return string representing usage information.'
    return '''
    Org2CSV.py --globPatttern=<pattern> --output=<file> [--onlyToday=<o>]

    where <pattern> is a wild card pattern for all org-mode files
    to process, <file> is the name of an output csv file, and <o> is
    either "True" or "False".
    '''    
    
if __name__ == '__main__':
    argvDict = dict([item.split('=') for item in sys.argv[1:] if item])
    argvDict = dict([(k.lstrip('-'), v) for (k,v) in argvDict.items()])
    onlyTodayArg = argvDict.get('onlyToday', True)
    argvDict['onlyToday'] = False if (
        onlyTodayArg is False or onlyTodayArg == 'False') else onlyTodayArg
    try:
        MakeCSV(**argvDict)
    except Exception, e:
        print 'Unable to make csv file due to exception:\n%s\nUsage:\n%s' % (
            str(e), MakeUsage())
    
           

[-- Attachment #3: Orgnode.py --]
[-- Type: text/x-python, Size: 10830 bytes --]

"""
The Orgnode module consists of the Orgnode class for representing a
headline and associated text from an org-mode file, and routines for
constructing data structures of these classes.
"""

# Program written by Charles Cave   (charlesweb@optusnet.com.au)
# February - March 2009
# Version 2 - June 2009
#   Added support for all tags, TODO priority and checking existence of a tag
# More information at
#    http://members.optusnet.com.au/~charles57/GTD

import re, sys
import datetime

def makelist(filename):
   """
   Read an org-mode file and return a list of Orgnode objects
   created from this file.
   """
   ctr = 0

   try:
      f = open(filename, 'r')
   except IOError:
      print "Unable to open file [%s] " % filename
      print "Program terminating."
      sys.exit(1)

   todos         = dict()  # populated from #+SEQ_TODO line
   todos['TODO'] = ''   # default values
   todos['DONE'] = ''   # default values
   level         = 0
   heading       = ""
   bodytext      = ""
   tag1          = ""      # The first tag enclosed in ::
   alltags       = []      # list of all tags in headline
   sched_date    = ''
   sched_dict    = None
   deadline_date = ''
   nodelist      = []
   propdict      = dict()
   
   for line in f:
       ctr += 1     
       hdng = re.search('^(\*+)\s(.*?)\s*$', line)
       if hdng:
          if heading:  # we are processing a heading line
             thisNode = Orgnode(level, heading, bodytext, tag1, alltags)
             if sched_date:
                thisNode.setScheduled(sched_date)
                thisNode.setStartTime(sched_dict)
                thisNode.setEndTime(sched_dict)
                sched_date = ""
                sched_dict = None
             if deadline_date:
                thisNode.setDeadline(deadline_date)
                deadline_date = ''
             thisNode.setProperties(propdict)
             nodelist.append( thisNode )
             propdict = dict()
          level = hdng.group(1)
          heading =  hdng.group(2)
          bodytext = ""
          tag1 = ""
          alltags = []       # list of all tags in headline
          tagsrch = re.search('(.*?)\s*:(.*?):(.*?)$',heading)
          if tagsrch:
              heading = tagsrch.group(1)
              tag1 = tagsrch.group(2)
              alltags.append(tag1)
              tag2 = tagsrch.group(3)
              if tag2:
                 for t in tag2.split(':'):
                    if t != '': alltags.append(t)
       else:      # we are processing a non-heading line
           if line[:10] == '#+SEQ_TODO':
              kwlist = re.findall('([A-Z]+)\(', line)
              for kw in kwlist: todos[kw] = ""

           if line[:1] != '#':
               bodytext = bodytext + line

           if re.search(':PROPERTIES:', line): continue
           if re.search(':END:', line): continue
           prop_srch = re.search('^\s*:(.*?):\s*(.*?)\s*$', line)
           if prop_srch:
              propdict[prop_srch.group(1)] = prop_srch.group(2)
              continue
           sd_re = re.search('(SCHEDULED:\s+<(?P<year>[0-9]+)\-(?P<month>[0-9]+)\-(?P<day>[0-9]+) *([A-z]* (?P<starttime>[0-9]+:[0-9]+)(-(?P<endtime>[0-9]+:[0-9]+))*))',line)
           if sd_re:
              sched_dict = sd_re.groupdict()              
              sched_date = datetime.date(int(sched_dict['year']),
                                         int(sched_dict['month']),
                                         int(sched_dict['day']))

           dd_re = re.search('DEADLINE:\s*<(\d+)\-(\d+)\-(\d+)', line)
           if dd_re:
              deadline_date = datetime.date(int(dd_re.group(1)),
                                            int(dd_re.group(2)),
                                            int(dd_re.group(3)) )

   # write out last node              
   thisNode = Orgnode(level, heading, bodytext, tag1, alltags)
   thisNode.setProperties(propdict)   
   if sched_date:
      thisNode.setScheduled(sched_date)
      thisNode.setStartTime(sched_dict)
      thisNode.setEndTime(sched_dict)
   if deadline_date:
      thisNode.setDeadline(deadline_date)
   nodelist.append( thisNode )
              
   # using the list of TODO keywords found in the file
   # process the headings searching for TODO keywords
   for n in nodelist:
       h = n.Heading()
       todoSrch = re.search('([A-Z]+)\s(.*?)$', h)
       if todoSrch:
           if todos.has_key( todoSrch.group(1) ):
               n.setHeading( todoSrch.group(2) )
               n.setTodo ( todoSrch.group(1) )
       prtysrch = re.search('^\[\#(A|B|C)\] (.*?)$', n.Heading())
       if prtysrch:
          n.setPriority(prtysrch.group(1))
          n.setHeading(prtysrch.group(2))
                            
   return nodelist

######################
class Orgnode(object):
    """
    Orgnode class represents a headline, tags and text associated
    with the headline.
    """
    def __init__(self, level, headline, body, tag, alltags):
        """
        Create an Orgnode object given the parameters of level (as the
        raw asterisks), headline text (including the TODO tag), and
        first tag. The makelist routine postprocesses the list to
        identify TODO tags and updates headline and todo fields.
        """
        self.level = len(level)
        self.headline = headline
        self.body = body
        self.tag = tag            # The first tag in the list
        self.tags = dict()        # All tags in the headline
        self.todo = ""
        self.prty = ""            # empty of A, B or C
        self.scheduled = ""       # Scheduled date
        self.deadline = ""        # Deadline date
        self.properties = dict()
        self.starttime = ''
        self.endtime = ''
        for t in alltags:
           self.tags[t] = ''

        # Look for priority in headline and transfer to prty field
        
    def Heading(self):
        """
        Return the Heading text of the node without the TODO tag
        """
        return self.headline

    def setHeading(self, newhdng):
        """
        Change the heading to the supplied string
        """
        self.headline = newhdng

    def Body(self):
        """
        Returns all lines of text of the body of this node except the
        Property Drawer
        """
        return self.body

    def Level(self):
        """
        Returns an integer corresponding to the level of the node.
        Top level (one asterisk) has a level of 1.
        """
        return self.level

    def Priority(self):
        """
        Returns the priority of this headline: 'A', 'B', 'C' or empty
        string if priority has not been set.
        """
        return self.prty

    def setPriority(self, newprty):
        """
        Change the value of the priority of this headline.
        Values values are '', 'A', 'B', 'C'
        """
        self.prty = newprty
    
    def Tag(self):
        """
        Returns the value of the first tag.
        For example, :HOME:COMPUTER: would return HOME
        """
        return self.tag

    def Tags(self):
        """
        Returns a list of all tags 
        For example, :HOME:COMPUTER: would return ['HOME', 'COMPUTER']
        """
        return self.tags.keys()

    def hasTag(self, srch):
        """
        Returns True if the supplied tag is present in this headline
        For example, hasTag('COMPUTER') on headling containing
        :HOME:COMPUTER: would return True.
        """
        return self.tags.has_key(srch)
        
    def setTag(self, newtag):
        """
        Change the value of the first tag to the supplied string
        """
        self.tag = newtag

    def setTags(self, taglist):
        """
        Store all the tags found in the headline. The first tag will
        also be stored as if the setTag method was called.
        """
        for t in taglist:
           self.tags[t] = ''
        
    def Todo(self):
        """
        Return the value of the TODO tag
        """
        return self.todo

    def setTodo(self, value):
        """
        Set the value of the TODO tag to the supplied string
        """
        self.todo = value

    def setProperties(self, dictval):
        """
        Sets all properties using the supplied dictionary of
        name/value pairs
        """
        self.properties = dictval

    def Property(self, keyval):
        """
        Returns the value of the requested property or null if the
        property does not exist.
        """
        return self.properties.get(keyval, "")
    
    def setScheduled(self, dateval):
        """
        Set the scheduled date using the supplied date object
        """
        self.scheduled = dateval

    def setStartTime(self, sched_dict):
       if ('starttime' in sched_dict):
          self.starttime = datetime.datetime(
             *map(int,([sched_dict[n] for n in ['year', 'month', 'day']]
                       + sched_dict['starttime'].split(':') + [0])))


    def setEndTime(self, sched_dict):
       if (sched_dict.get('endtime')):
          self.endtime = datetime.datetime(
             *map(int,([sched_dict[n] for n in ['year', 'month', 'day']]
               + sched_dict['endtime'].split(':') + [0])))

    def Scheduled(self):
        """
        Return the scheduled date object or null if nonexistent
        """
        return self.scheduled
    
    def setDeadline(self, dateval):
        """
        Set the deadline (due) date using the supplied date object
        """
        self.deadline = dateval

    def Deadline(self):
        """
        Return the deadline date object or null if nonexistent
        """
        return self.deadline

    def __repr__(self):
        """
        Print the level, heading text and tag of a node and the body
        text as used to construct the node.
        """
        # This method is not completed yet.
        n = ''
        for i in range(0, self.level):
           n = n + '*'
        n = n + ' ' + self.todo + ' '
        if self.prty:
           n = n +  '[#' + self.prty + '] '
        n = n + self.headline
        n = "%-60s " % n     # hack - tags will start in column 62
        closecolon = ''
        for t in self.tags.keys():
           n = n + ':' + t
           closecolon = ':'   
        n = n + closecolon
# Need to output Scheduled Date, Deadline Date, property tags The
# following will output the text used to construct the object
        n = n + "\n" + self.body
        
        return n


    

[-- Attachment #4: Type: text/plain, Size: 201 bytes --]

_______________________________________________
Emacs-orgmode mailing list
Please use `Reply All' to send replies to the list.
Emacs-orgmode@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-orgmode

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2010-05-13 11:28 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-05-13 11:27 script to transfer schedule from org-mode to Microsoft Outlook Emin.shopper Martinian.shopper

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).