Esempio n. 1
0
 def write_items(self, calendar):
     """
     Write all events to the calendar
     """
     for item in self.items:
         event = Event() if vText(
             'MEETING') in item['categories'] else Todo()
         for ifield, efield in ITEM_EVENT_FIELD_MAP:
             val = item.get(ifield)
             if isinstance(val, list):
                 for list_item in val:
                     event.add(efield, list_item)
             elif val is not None:
                 event.add(efield, val)
         calendar.add_component(event)
def make_service_call(host, port, username, pwd, dbname, option):
    def uid_generat(data):# UID generat
        sha_obj = hashlib.sha1(data)
        return sha_obj.hexdigest()
    if host == '1' and port == '1':
        sock_common = xmlrpclib.ServerProxy('http://127.0.0.1:8069/xmlrpc/common')
        uid = sock_common.login(dbname, username, pwd)
        sock = xmlrpclib.ServerProxy('http://127.0.0.1:8069/xmlrpc/object')
    else:
        sock_common = xmlrpclib.ServerProxy('http://'+host+':'+port+'/xmlrpc/common')
        uid = sock_common.login(dbname, username, pwd)
        sock = xmlrpclib.ServerProxy('http://'+host+':'+port+'/xmlrpc/object')
    if option == "task":
        task_ids = sock.execute(dbname, uid, pwd, 'crm.task', 'search',\
                             [('task_type', '=', 't'), ('user_id', '=', uid), ('state', '!=', 'cancel')])
        task_data = sock.execute(dbname, uid, pwd, 'crm.task', 'read', task_ids,\
                    ['name','description','start_datetime','stop_datetime',\
                     'priority','state','location','write_date'])

        def ics_datetime(idate):
            if idate:
                #returns the datetime as UTC, because it is stored as it in the database
                idate = idate.split('.', 1)[0]
                return DT.datetime.strptime(idate,\
                     '%Y-%m-%d %H:%M:%S').replace(tzinfo=pytz.timezone('UTC'))
            return False

        cal = Calendar()
        cal.add('PRODID', 'Zimbra-Calendar-Provider')
        cal.add('VERSION', '2.0')
        cal.add('METHOD', 'PUBLISH')

        for data in task_data:
            todo = Todo()
            todo.add('summary', data['name'])
            todo.add('description', data['description'])
            if data['start_datetime']:
                todo.add('DTSTART', ics_datetime(data['start_datetime']))
            else:
                todo.add('DTSTART', ics_datetime(data['stop_datetime']))
            if data['stop_datetime']:
                todo.add('DUE', ics_datetime(data['stop_datetime']))
            else:
                todo.add('DUE', ics_datetime(data['start_datetime']))
            if data['write_date']:
                todo.add('DTSTAMP', DT.datetime.strptime(data['write_date'],\
                                                          '%Y-%m-%d %H:%M:%S'))
                todo.add('LAST-MODIFIED', \
                DT.datetime.strptime(data['write_date'], '%Y-%m-%d %H:%M:%S'))
            todo['uid'] = uid_generat('crmTask'+str(data['id']))

            if data['priority'] == 'low':
                todo.add('priority', 9)
            elif data['priority'] == 'medium':
                todo.add('priority', 5)
            elif data['priority'] == 'high':
                todo.add('priority', 1)
            else:
                todo.add('priority', 5)

            if data['state'] == 'done':
                todo.add('status', 'COMPLETED')
                todo.add('PERCENT-COMPLETE', 100)
            elif data['state'] == 'cancel':
                todo.add('status', 'DEFERRED')
            elif data['state'] == 'open':
                todo.add('status', 'IN-PROCESS')
            else:
                todo.add('status', 'NEEDS-ACTION')
                todo.add('PERCENT-COMPLETE', 0)
            cal.add_component(todo)
        return cal.to_ical()
    else:
        event_ids = sock.execute(dbname, uid, pwd, 'calendar.event', 'search',\
                                 [('user_id','=',uid)])
        event_data = sock.execute(dbname, uid, pwd, 'calendar.event', 'read',\
                     event_ids,['show_as','allday','name','description',\
                                'start_datetime','stop_datetime','location','write_date','start_date','stop_date'])
#                             'start','stop','location','write_date'])
        def ics_datetime(idate):
            if idate:
                #returns the datetime as UTC, because it is stored as it in the database
                return DT.datetime.strptime(idate,\
                     '%Y-%m-%d %H:%M:%S').replace(tzinfo=pytz.timezone('UTC'))
            return False

        cal = Calendar()
        cal.add('PRODID', 'Zimbra-Calendar-Provider')
        cal.add('VERSION', '2.0')
        cal.add('METHOD', 'PUBLISH')
        for data in event_data:
            event = Event()
            if data['allday']:
                event.add('CREATED', date.today())
                event.add('DTSTART', DT.datetime.combine(DT.datetime.strptime(data['start_date'], '%Y-%m-%d'), DT.time.min))
                event.add('DTEND', DT.datetime.combine(DT.datetime.strptime(data['stop_date'], '%Y-%m-%d'), DT.time.max))
                event.add('X-MICROSOFT-CDO-ALLDAYEVENT', 'TRUE')
            else:
                event.add('CREATED', date.today())
                event.add('DTSTART', ics_datetime(data['start_datetime']))
                event.add('DTEND', ics_datetime(data['stop_datetime']))
                event.add('X-MICROSOFT-CDO-ALLDAYEVENT', 'FALSE')
            if data['write_date']:
                event.add('DTSTAMP', DT.datetime.strptime(data['write_date'],\
                                                           '%Y-%m-%d %H:%M:%S'))
                event.add('LAST-MODIFIED', \
                DT.datetime.strptime(data['write_date'], '%Y-%m-%d %H:%M:%S'))
            if data['show_as']:
                event.add('X-MICROSOFT-CDO-INTENDEDSTATUS', data['show_as'])
            event.add('UID', uid_generat('crmCalendar'+str(data['id'])))
            event.add('SUMMARY', data['name'])
            if data['description']:
                event.add('DESCRIPTION', data['description'])
            if data['location']:
                event.add('LOCATION', data['location'])
            cal.add_component(event)
        return cal.to_ical()
Esempio n. 3
0
def task_create(task=None, title='Task title', due=None, alarm=None, note='', sequence=0, uid=None, priority=None, next_action=None):
  from uuid import uuid4
  from icalendar import Calendar, Todo, Alarm
  if task is not None:
    title = task.name
    due = task.due
    alarm = task.alarm
    note = task.note
    sequence = task.sequence
    priority = task.priority
    next_action = task.next_action
  if (due is not None and alarm is None):
    # Should not arrive here, this should have already have been handled
    alarm = due
    if is_same_time(due, universe.defaulttime.due):
      # Warning for day events 1800 - 1000 = 8 hours
      alarm = due + universe.defaulttime.alldaydiff
    else: 
      # Default warning of an hour
      alarm = due + universe.defaulttime.diff
  if (alarm is not None and due is None):
    due = alarm
  # alarm now defunct - just use due
  cal = Calendar()
  cal.add('prodid', '-//enoky//v0.1//EN')
  cal.add('version', '2.0')

  todo = Todo()
  todo.add('summary', title)
  if priority is not None:
    todo.add('priority', priority)
  if due is not None:
    todo.add('due', due)
    todo.add('dtstart', due)
  todo.add('status', 'NEEDS-ACTION')
  todo.add('dtstamp', universe.now)
  todo.add('created', universe.now)
  if uid is None:
    uid = uuid4()
  todo['uid'] = uid
  todo.add('sequence', sequence)
  notenext = note
  if (next_action is not None) and (len(next_action) > 0):
    if len(notenext) > 0:
      notenext = notenext + '\n'
    notenext = notenext + universe.next_char + ' ' + next_action.lstrip()
  if len(notenext) > 0:
    todo.add('description', notenext)

  if alarm is not None:
    valarm = Alarm()
    valarm['uid'] = uuid4()
    valarm.add('trigger', alarm)
    # Possibly not needed. How add due date?!
    valarm.add('description', 'Event reminder')
    valarm.add('action', 'DISPLAY')
    todo.add_component(valarm)

  cal.add_component(todo)
  vcal = cal.to_ical()
  return vcal
Esempio n. 4
0
def todo_add(caldav_conn, args):
    ## TODO: copied from calendar_add, should probably be consolidated
    if args.icalendar or args.nocaldav:
        niy(feature="add todo item by icalendar raw stdin data or create raw icalendar data to stdout")
    if args.todo_uid:
        uid = args.todo_uid
    else:
        uid = uuid.uuid1()
    cal = Calendar()
    cal.add('prodid', '-//{author_short}//{product}//{language}'.format(author_short=__author_short__, product=__product__, language=args.language))
    cal.add('version', '2.0')
    todo = Todo()
    todo.add('dtstamp', _now())

    for setarg in ('due', 'dtstart'):
        if getattr(args, 'set_'+setarg):
            if type(getattr(args, 'set_'+setarg)) == str:
                val = dateutil.parser.parse(getattr(args, 'set_'+setarg))
            else:
                val = getattr(args, 'set_'+setarg)
        todo.add(setarg, val)
    todo.add('uid', str(uid))
    todo.add('summary', ' '.join(args.summaryline))
    todo.add('status', 'NEEDS-ACTION')

    if args.is_child:
        for t in todo_select(caldav_conn, args):
            todo.add('related-to', t.instance.vtodo.uid.value)
            rt = t.instance.vtodo.add('related-to')
            rt.params['RELTYPE']=['CHILD']
            rt.value = str(uid)
            t.save()

    for attr in vtodo_txt_one:
        if attr == 'summary':
            continue
        val = getattr(args, 'set_'+attr)
        if val:
            todo.add(attr, val)
    ## TODO: this doesn't currently work quite the way we'd like it to
    ## work (it adds to lines to the ical, and vobject cares only
    ## about one of them), and if we do get it to work, we'd like to
    ## refactor and get the same logic in the edit-function
    for attr in vtodo_txt_many:
        val = getattr(args, 'set_'+attr)
        if val:
            vals = val.split(',')
            todo.add(attr, vals)

    if args.alarm is not None:
        alarm = create_alarm(' '.join(args.summaryline), parse_time_delta(args.alarm))
        todo.add_component(alarm)

    cal.add_component(todo)
    _calendar_addics(caldav_conn, cal.to_ical(), uid, args)
    print("Added todo item with uid=%s" % uid)
Esempio n. 5
0
def todo_add(caldav_conn, args):
    ## TODO: copied from calendar_add, should probably be consolidated
    if args.icalendar or args.nocaldav:
        niy(feature="add todo item by icalendar raw stdin data or create raw icalendar data to stdout")
    if args.todo_uid:
        uid = args.todo_uid
    else:
        uid = uuid.uuid1()
    cal = Calendar()
    cal.add(
        "prodid",
        "-//{author_short}//{product}//{language}".format(
            author_short=__author_short__, product=__product__, language=args.language
        ),
    )
    cal.add("version", "2.0")
    todo = Todo()
    ## TODO: what does the cryptic comment here really mean, and why was the dtstamp commented out?  dtstamp is required according to the RFC.
    ## TODO: (cryptic old comment:) not really correct, and it breaks i.e. with google calendar
    todo.add("dtstamp", datetime.now())

    for arg in ("set_due", "set_dtstart"):
        if getattr(args, arg):
            if type(getattr(args, arg)) == str:
                val = dateutil.parser.parse(getattr(args, arg))
            else:
                val = getattr(args, arg)
        todo.add(arg, val)
    todo.add("uid", str(uid))
    todo.add("summary", " ".join(args.summaryline))
    todo.add("status", "NEEDS-ACTION")

    if args.is_child:
        for t in todo_select(caldav_conn, args):
            todo.add("related-to", t.instance.vtodo.uid.value)
            rt = t.instance.vtodo.add("related-to")
            rt.params["RELTYPE"] = ["CHILD"]
            rt.value = str(uid)
            t.save()

    for attr in vtodo_txt_one + vtodo_txt_many:
        if attr == "summary":
            continue
        val = getattr(args, "set_" + attr)
        if val:
            todo.add(attr, val)
    cal.add_component(todo)
    _calendar_addics(caldav_conn, cal.to_ical(), uid, args)
    print("Added todo item with uid=%s" % uid)
Esempio n. 6
0
def todo_add(caldav_conn, args):
    ## TODO: copied from calendar_add, should probably be consolidated
    if args.icalendar or args.nocaldav:
        niy(feature=
            "add todo item by icalendar raw stdin data or create raw icalendar data to stdout"
            )
    if args.todo_uid:
        uid = args.todo_uid
    else:
        uid = uuid.uuid1()
    cal = Calendar()
    cal.add(
        'prodid', '-//{author_short}//{product}//{language}'.format(
            author_short=__author_short__,
            product=__product__,
            language=args.language))
    cal.add('version', '2.0')
    todo = Todo()
    todo.add('dtstamp', _now())

    for setarg in ('due', 'dtstart'):
        if getattr(args, 'set_' + setarg):
            if type(getattr(args, 'set_' + setarg)) == str:
                val = dateutil.parser.parse(getattr(args, 'set_' + setarg))
            else:
                val = getattr(args, 'set_' + setarg)
        todo.add(setarg, val)
    todo.add('uid', str(uid))
    todo.add('summary', ' '.join(args.summaryline))
    todo.add('status', 'NEEDS-ACTION')

    if args.is_child:
        for t in todo_select(caldav_conn, args):
            todo.add('related-to', t.instance.vtodo.uid.value)
            rt = t.instance.vtodo.add('related-to')
            rt.params['RELTYPE'] = ['CHILD']
            rt.value = str(uid)
            t.save()

    for attr in vtodo_txt_one:
        if attr == 'summary':
            continue
        val = getattr(args, 'set_' + attr)
        if val:
            todo.add(attr, val)
    ## TODO: this doesn't currently work quite the way we'd like it to
    ## work (it adds to lines to the ical, and vobject cares only
    ## about one of them), and if we do get it to work, we'd like to
    ## refactor and get the same logic in the edit-function
    for attr in vtodo_txt_many:
        val = getattr(args, 'set_' + attr)
        if val:
            vals = val.split(',')
            todo.add(attr, vals)

    if args.alarm is not None:
        alarm = create_alarm(' '.join(args.summaryline),
                             parse_time_delta(args.alarm))
        todo.add_component(alarm)

    cal.add_component(todo)
    _calendar_addics(caldav_conn, cal.to_ical(), uid, args)
    print("Added todo item with uid=%s" % uid)
Esempio n. 7
0
def todo_add(caldav_conn, args):
    ## TODO: copied from calendar_add, should probably be consolidated
    if args.icalendar or args.nocaldav:
        niy(feature=
            "add todo item by icalendar raw stdin data or create raw icalendar data to stdout"
            )
    if args.todo_uid:
        uid = args.todo_uid
    else:
        uid = uuid.uuid1()
    cal = Calendar()
    cal.add(
        'prodid', '-//{author_short}//{product}//{language}'.format(
            author_short=__author_short__,
            product=__product__,
            language=args.language))
    cal.add('version', '2.0')
    todo = Todo()
    ## TODO: what does the cryptic comment here really mean, and why was the dtstamp commented out?  dtstamp is required according to the RFC.
    ## TODO: (cryptic old comment:) not really correct, and it breaks i.e. with google calendar
    todo.add('dtstamp', datetime.now())

    for arg in ('set_due', 'set_dtstart'):
        if getattr(args, arg):
            if type(getattr(args, arg)) == str:
                val = dateutil.parser.parse(getattr(args, arg))
            else:
                val = getattr(args, arg)
        todo.add(arg, val)
    todo.add('uid', str(uid))
    todo.add('summary', ' '.join(args.summaryline))
    todo.add('status', 'NEEDS-ACTION')

    if args.is_child:
        for t in todo_select(caldav_conn, args):
            todo.add('related-to', t.instance.vtodo.uid.value)
            rt = t.instance.vtodo.add('related-to')
            rt.params['RELTYPE'] = ['CHILD']
            rt.value = str(uid)
            t.save()

    for attr in vtodo_txt_one + vtodo_txt_many:
        if attr == 'summary':
            continue
        val = getattr(args, 'set_' + attr)
        if val:
            todo.add(attr, val)
    cal.add_component(todo)
    _calendar_addics(caldav_conn, cal.to_ical(), uid, args)
    print("Added todo item with uid=%s" % uid)
Esempio n. 8
0
    'E': 'EASTERLY',
}

ical_freq_hsh = {
    'YEARLY': 'y',
    'MONTHLY': 'm',
    'WEEKLY': 'w',
    'DAILY': 'd',
    'HOURLY': 'h',
    'MINUTELY': 'n',
    # 'EASTERLY': 'e'
}

item_types = {
        '*': Event(),
        '-': Todo(),
        '%': Journal()
        }


# BEGIN:VCALENDAR
# VERSION:2.0
# PRODID:-//etm_tk 3.2.38//dgraham.us//
# BEGIN:VEVENT
# SUMMARY:Charleston Volvo Open
# DTSTART;VALUE=DATE:20190402
# UID:f42d3035fd634835a01f6193a925f32eetm
# RRULE:FREQ=DAILY;COUNT=4
# END:VEVENT
# END:VCALENDAR
 
Esempio n. 9
0
def create_calendar_feed(user, secret):
    if True:  #try:
        # check access
        enabled = frappe.db.get_value("Calendar Feed Settings",
                                      "Calendar Feed Settings", "enabled")
        if float(enabled) == 0:
            return
        erp_secret = frappe.db.get_value("Calendar Feed Settings",
                                         "Calendar Feed Settings", "secret")
        if not secret == erp_secret:
            return

        # initialise calendar
        cal = Calendar()

        # set properties
        cal.add('prodid', '-//finkzeit//libracore//')
        cal.add('version', '2.0')

        # get data for public events
        show_public_events = frappe.db.get_value("Calendar Feed Settings",
                                                 "Calendar Feed Settings",
                                                 "show_public_events")
        if float(show_public_events) == 1:
            sql_query = """SELECT `subject`, `starts_on`, `ends_on`, `modified`, `description`
                 FROM `tabEvent` 
                 WHERE `event_type` = 'Public'"""
            events = frappe.db.sql(sql_query, as_dict=True)
            # add events
            for erp_event in events:
                event = Event()
                event.add('summary', erp_event['subject'])
                event.add('dtstart', erp_event['starts_on'])
                if erp_event['ends_on']:
                    event.add('dtend', erp_event['ends_on'])
                event.add('dtstamp', erp_event['modified'])
                event.add('description', erp_event['description'])
                # add to calendar
                cal.add_component(event)

        # get data for personal events
        sql_query = """SELECT `subject`, `starts_on`, `ends_on`, `modified`, `description` 
             FROM `tabEvent` 
             WHERE `event_type` = 'Private'
               AND (`owner` = '{user}' OR `modified_by` = '{user}')""".format(
            user=user)
        events = frappe.db.sql(sql_query, as_dict=True)
        # add events
        for erp_event in events:
            event = Event()
            event.add('summary', erp_event['subject'])
            event.add('dtstart', erp_event['starts_on'])
            if erp_event['ends_on']:
                event.add('dtend', erp_event['ends_on'])
            event.add('dtstamp', erp_event['modified'])
            event.add('description', erp_event['description'])
            # add to calendar
            cal.add_component(event)

        # get data for personal todo's
        sql_query = """SELECT 
               IFNULL(`reference_type`, '-') AS `reference_type`, 
               IFNULL(`reference_name`, '-') AS `reference_name`,
               `description`, 
               `modified`, 
               `date` 
             FROM `tabToDo` 
             WHERE `status` = 'Open'
               AND (`owner` = '{user}' OR `modified_by` = '{user}')""".format(
            user=user)
        todos = frappe.db.sql(sql_query, as_dict=True)
        # add events
        for erp_todo in todos:
            todo = Todo()
            todo.add(
                'summary', "{0} {1}".format(erp_todo['reference_type'],
                                            erp_todo['reference_name']))
            todo.add('dtstamp', erp_todo['modified'])
            todo.add('description', erp_todo['description'])
            if erp_todo['date']:
                todo.add('due', erp_todo['date'])
            todo.add('status', 'Open')
            # add to calendar
            cal.add_component(todo)

        # return calendar object
        return cal
Esempio n. 10
0
def make_todo(item: ToDoItem) -> Todo:
    todo = Todo()
    todo['uid'] = item.id
    todo['summary'] = item.title
    todo['status'] = "Completed" if item.completed else "In Progress"
    return todo
Esempio n. 11
0
def TodoFromJSON(cal, data):
    tz = pytz.timezone("Europe/Budapest")
    if 'dynalist_info' in data:
        if data['note'] == '':
            description = data['dynalist_info']
        else:
            description = data['note'] + '\n' + data['dynalist_info']
    else:
        description = data['note']
    duedate = data['date'].replace('-', '')
    time = data['time'].replace(':', '')
    if not duedate == '':
        Y = int(duedate[:4])
        m = int(duedate[4:6])
        D = int(duedate[6:8])
        if not time == '':
            H = int(time[:2])
            M = int(time[2:4])

    if cal is None:
        cal = Calendar()
        cal.add('prodid', '-//Dynatask//')
        cal.add('version', '2.0')
        todo = Todo()
        if 'dynalist_id' in data:
            todo.add('uid', data['caldav_uid'])
            todo.add('X-DYNATASK-DYNALISTID', data['dynalist_id'])
        elif 'caldav_uid' in data:
            todo.add('uid', data['caldav_uid'])
        todo.add('summary', data['name'])
        now = datetime.now(pytz.utc)
        todo.add('dtstamp', now)
        todo.add('created', now)
        todo.add('last-modified', now)
        if not duedate == '':
            if not time == '':
                todo.add('due', datetime(Y, m, D, H, M, tzinfo=tz))
            else:
                todo.add('due', datetime(Y, m, D).date())
        todo.add('description', description)

        if 'checked' in data:
            if data['checked']:
                todo.add('status', 'COMPLETED')
                todo.add('completed', datetime.now(pytz.utc))
                todo.add('percent-complete', '100')
            else:
                todo.add('status', 'NEEDS-ACTION')
                todo.add('percent-complete', '0')

        if 'caldav_parent' in data:
            todo.add('related-to', data['caldav_parent'])

        if 'alarm' in data and not data['alarm'] == '':
            alarm = Alarm()
            alarm.add('action', 'DISPLAY')
            alarm.add('trigger', timedelta(minutes=-int(data['alarm'])))
            todo.add_component(alarm)

        cal.add_component(todo)
        return (cal)
Esempio n. 12
0
def createVTODOs(task, parent=None):
    todos = []
    todo = Todo()
    try:
        todo.add('UID', str(task['id']))
    except KeyError:
        todo.add('UID', str(uuid.uuid1()))
    try:
        todo.add('dtstamp', datetime.strptime(task['createdAt'], "%Y-%m-%dT%H:%M:%S.%f%z"))
    except ValueError: #Thank you for using different formats within the same field!
        try:
            todo.add('dtstamp', datetime.strptime(task['createdAt'], "%Y-%m-%dT%H:%M:%S%z"))
        except:
            logger.error('Could not parse creation date for Task {}'.format(task['id']))
            quit()
    todo.add('summary', task.get('title', ''))
    if task.get('dueDate', None) is not None:
        todo.add('DUE', datetime.strptime(task['dueDate'], "%Y-%m-%dT%H:%M:%S"))
    if task['completed']:
        todo.add('status', 'COMPLETED')
        todo.add('PERCENT-COMPLETE', '100')
        todo.add('COMPLETED', datetime.strptime(task['completedAt'], "%Y-%m-%dT%H:%M:%S.%f%z"))
        todo.add('LAST-MODIFIED', datetime.strptime(task['completedAt'], "%Y-%m-%dT%H:%M:%S.%f%z"))
    todo.add('COMMENT', task.get('notes', ''))
    if task.get('reminders', False):
        reminders = []
        for reminder in task['reminders']:
            try:
                reminders += [datetime.strptime(reminder['remindAt'], "%Y-%m-%dT%H:%M:%S.%f%z")]
            except ValueError: #Thank you for using different formats within the same file!
                try:
                    reminders += [datetime.strptime(reminder['remindAt'], "%Y-%m-%dT%H:%M:%S%z")]
                except:
                    logger.error('Could not parse reminder date for Task {}'.format(task['id']))
        logger.debug('Task {} has {} reminders. Not supported'.format(task['id'], len(reminders)))
    if task.get('comment', False):
        todo.add('description', task['comment'])
    if task.get('files', False):
        logger.error('There are files linked!')
    if parent is not None:
        todo.add('RELATED-TO', parent)
    todos.extend([todo])
    if task.get('subtasks', False):
        logger.debug('Task {} has {} subtasks'.format(task['id'], len(task['subtasks'])))
        for subtask in task['subtasks']:
            todos.extend(createVTODOs(subtask, parent=task['id']))
    return todos
Esempio n. 13
0
def	todo_ical_export(request):
	'''
	Type: iCalendar
	Mime: text/calendar
	Ext: ics
	#tpl = loader.get_template('task/todo.ics')
	#response.write(tpl.render(Context({'object_list': object_list})).encode('utf-8'))
	'''
	user = User.objects.get(pk=request.user.id)	# aka author
	response = HttpResponse(mimetype='text/calendar')
	response['Content-Disposition'] = '; filename=todo.ics'
	cal = Calendar()
	cal.add('version', '2.0')
	cal.add('prodid', '-//LanSite GroupWare//eap.su//')
	for object in vToDo.objects.filter(user=user):
		todo = Todo()
		# 1. Task
		#todo['created'] = object.created
		todo.add('created', object.created)
		todo.add('last-modified', object.updated)
		todo.add('summary', object.summary)
		if (object.getstatusname()):
			todo.add('status', object.getstatusname())
		if (object.getrestrictionname()):
			todo.add('class', object.getrestrictionname())
		if (object.getcategories()):
			todo.add('categories', object.getcategories())
		# 2. vCal
		if object.attendee:
			email = object.attendee.email
			if email:
				todo.add('attendee', 'MAILTO:%s' % email)
			email = user.email
			if email:
				todo.add('organizer', 'MAILTO:%s' % email)
		if object.description:
			todo.add('description', object.description)
		if object.start_d:
			if object.start_t:
				todo.add('dtstart', datetime.combine(object.start_d, object.start_t))
			else:
				todo.add('dtstart', object.start_d)
		if object.duration_d:
			if object.duration_t:
				todo.add('duration', timedelta(
					days=object.duration_d,
					hours=object.duration_t.hour,
					minutes=object.duration_t.minute,
					seconds=object.duration_t.second
				))
			else:
				todo.add('duration', timedelta(days=object.duration_d))
		if object.location:
			todo.add('location', object.location)
		if object.priority:
			todo.add('priority', object.priority)
		if object.URL:
			todo.add('URL', object.URL)
		# 3. vToDo
		if object.due_d:
			if object.due_t:
				todo.add('due', datetime.combine(object.due_d, object.due_t))
			else:
				todo.add('due', object.due_d)
		if object.completed:
			todo.add('completed', object.completed)
		if object.percent:
			todo.add('percent-complete', object.percent)
		cal.add_component(todo)
	response.write(cal.as_string())		# .encode('utf-8')
	return response