RSS

(root)/misc-scripts : /ics-gcal.py (revision 75)

Line Revision Contents
1 49
#!/usr/bin/python -tt
2
3 75
""" ics-gcal.py (c) 2008, 2010 Matthew Ernisse <mernisse@ub3rgeek.net>
4 49
5
Cobbled together with help from gdata API documentation:
6
http://code.google.com/apis/calendar/developers_guide_python.html
7
8
To Use:
9
	add the following to your .mailcap and then you can simply
10
exec the attachment and it will get added to your google calendar.
11
12
If the event has a reminder set it will set a reminder using your 
13
default method for 30 minutes prior to the event.
14
15
text/calendar;  ics-gcal.py -u <gcal un> -p <gcal pw> -f %s; \
16
                copiousoutput; needsterminal
17 50
18
Calendar name can be found on the calendar details page, or based
19
on your calendar's xml/ical links.  
20
21
If your XML link is:
22
http://www.google.com/calendar/feeds/yourname@gmail.com/public/basic
23
24
Then your calendar name is yourname@gmail.com
25 49
26 75
You may also now use a configuration file, NOTE this is not actually any
27
more secure than using the command line in your .mailcap configuration file
28
assuming sane permissions.
29
30
In ~/.config/ics-gcal.conf you may specify the following tokens:
31
email = <gcal user>
32
password = <gcal password>
33
calendar = "calendar name"
34
35
If the command line has these options specified they will OVERRIDE the 
36
config file.  None are required as long as between the config file and
37
the command like all required options are set.
38
39 49
Requires:
40
	gdata python bindings
41
	atom python module
42
	vobject python module
43
44
	Google Calendar account
45
46
"""
47
import getopt
48
import time
49
import sys
50
import os
51
import vobject
52
53
from gdata.calendar.service import *
54 58
from gdata.calendar import CalendarEventEntry, Reminder, Recurrence, Where, When
55 49
56
def Usage():
57
	"""Print usage statement
58
59
	Returns:
60
		None
61
	
62
	"""
63 51
	print """Usage: %s [-hR] [-c calendar] [-f file] [-p password] [-r minutes] [-u username] 
64 49
	Take a vcalendar stream from a file and insert to it into a Google 
65
	calendar
66
67
	Arguments:
68 51
	-c <calendar> - Which calendar to upload to, default = 'default'
69
	-f <file>     - ics file for input
70 49
	-h            - Show Usage and exit.
71
	-p <password> - Google Calendar password
72 50
	-r <minutes>  - Number of minutes for reminder length, default = 30
73 51
	-R            - Force adding a reminder even if the ics does not have
74
                        an alarm set.
75
	-u <username> - Google Calendar username
76 49
77
	""" % (sys.argv[0])
78
79
	return None
80
81
#def Reply(ics, reply="tentative"):
82
#
83
#	if reply == "accept":
84
#		message = "Event Accepted"
85
#		subject = 
86
#			
87
#	elif reply == "tentative":
88
#		message = "Event Tentativly Accepted"
89
#		subject = 
90
#
91
#	elif reply == "deny":
92
#		message = "Event Declined"
93
#		subject = 
94
#
95
#	else:
96
#		print "Invalid reply specified"
97
#		return None
98
#
99
#
100
101 51
def uploadToGoogle(ics, email, password, calendar="default", reminder=30, \
102
                   forceReminder=False):
103 49
	""" Upload to your Google Calendar.
104
105
	Arguments:
106
		ics - vobject vevent object.
107
		email - string, your gcal account name
108
		password - string, your gcal password
109 50
		calendar - string, which calendar to upload to.
110
		reminder - integer, number of minutes to set
111
			   reminder for.  Default 30
112 51
		forceReminder - boolean, If true, always set a
113
			        reminder.
114 49
115
	Returns:
116
		True on success, None on failure
117
118
	"""
119
	# sucks that gdata won't take a timetuple or a isoformat :(
120
	# it seems that sometimes vobject doesn't give me a
121
	# datetime object and instead gives me a unicode string.
122
	# it'd be nice to handle that.
123
	if type(u' ') == type(ics.vevent.dtstart.value):
124
		start = time.strptime(ics.vevent.dtstart.value, 
125
			"%Y%m%dT%H%M%S")
126
		start = time.strftime("%Y-%m-%dT%H:%M:%S.000Z", 
127
			start)
128
	else:
129
		start = time.strftime("%Y-%m-%dT%H:%M:%S.000Z", 
130
			ics.vevent.dtstart.value.utctimetuple())
131
132
	if type(u' ') == type(ics.vevent.dtend.value):
133
		end = time.strptime(ics.vevent.dtend.value, 
134
			"%Y%m%dT%H%M%S")
135
		end = time.strftime("%Y-%m-%dT%H:%M:%S.000Z", 
136
			end)
137
	else:
138
		end = time.strftime("%Y-%m-%dT%H:%M:%S.000Z", 
139
			ics.vevent.dtend.value.utctimetuple())
140
141
	event = CalendarEventEntry()
142
	event.title = atom.Title(text=ics.vevent.summary.value)
143 60
	if getattr(ics.vevent, "description", None):
144
		event.content = atom.Content(text=ics.vevent.description.value)
145
	else:
146
		event.content = atom.Content(text="")
147
148 49
	if getattr(ics.vevent, "location", None):
149 60
		event.where.append(
150
			Where(value_string=ics.vevent.location.value)
151
		)
152 49
	else:
153
		event.where.append(Where(value_string=""))
154 60
155 49
	event.when.append(When(start_time=start, end_time=end))
156
157 50
	# an alarm is set, so go ahead and set a reminder
158 49
	if 'valarm' in ics.vevent.contents:
159
		for when in event.when:
160
			if len(when.reminder) > 0:
161 50
				when.reminder[0].minutes = reminder
162 49
			else:
163 50
				when.reminder.append(Reminder(minutes=reminder))
164 51
	elif forceReminder:
165 60
		for when in event.when:
166
			when.reminder.append(Reminder(minutes=reminder))
167 58
168
	if getattr(ics.vevent, "rrule", None):
169
		try:
170
			event.recurrence = Recurrence(text=("%s\r\n%s\r\n%s\r\n") % (
171
				"DTSTART;VALUE=DATE:%s" % (
172
					time.strftime("%Y%m%d",ics.vevent.dtstart.value.utctimetuple())
173
					),
174
				"DTEND;VALUE=DATE:%s" % (
175
					time.strftime("%Y%m%d",ics.vevent.dtend.value.utctimetuple())
176
					),
177
				"RRULE:%s" % (
178
					ics.vevent.rrule.value
179
					)
180
				)
181
			)
182
		except Exception, e:
183
			print "could not add Recurrence to event, %s" % (str(e))
184
			return None
185 49
186
	try:
187
		cal = CalendarService()
188
		cal.email = email
189
		cal.password = password
190
		cal.source = "ics-gcal.py_mernisse@ub3rgeek.net"
191
		cal.ProgrammaticLogin()
192
	except Exception, e:
193 51
		print "cannot login to Google Calendar: %s"  % ( str(e) )
194 49
		return None
195
196
	try:
197 50
		new_event = cal.InsertEvent(event, '/calendar/feeds/%s/private/full' % (calendar))
198 49
	except Exception, e:
199 51
		print "cannot upload event to Google Calendar: %s"  % ( str(e) )
200 49
		return None
201
    
202
	print 'New single event inserted: %s' % (new_event.id.text,)
203
	print '\tEvent edit URL: %s' % (new_event.GetEditLink().href,)
204
	print '\tEvent HTML URL: %s' % (new_event.GetHtmlLink().href,)
205
206
	return True
207
208
def Main(argv = None):
209
	if not argv:
210
		argv = sys.argv[1:]
211
212
	if not len(argv) >= 1:
213
		Usage()
214
		return 2
215
216
	try:
217 51
		optlist, args = getopt.getopt(argv, "hRu:p:f:c:r:")
218 49
	except getopt.GetoptError, e:
219
		print str(e)
220
		Usage()
221
		return 2
222
223 51
	calendar = "default"
224 49
	email = None
225 51
	fd = None
226
	force = None
227 49
	password = None
228 50
	reminder = 30
229 49
230 75
	try:
231
		fd = open(os.path.expanduser('~/.config/ics-gcal.conf')
232
		for line in fd.readlines():
233
			try:
234
				token, value = line.split(r'=', 2)
235
			except ValueError:
236
				pass
237
238
			token = token.strip().lower()
239
			value = value.strip()
240
241
			if token == 'email':
242
				email = value	
243
			elif token == 'password':
244
				password = value
245
			elif token == 'calendar':
246
				calendar = value
247
248
		fd.close()
249
		fd = None
250
251
	except OSError:
252
		pass
253
254 49
	for o,v in optlist:
255 51
		if o == "-c":
256 50
			calendar = v
257 51
258 49
		elif o == "-f":
259
			try:
260
				fd = open(v)
261
			except IOError, e:
262
				print str(e)
263
				return 1
264 51
		elif o == "-h":
265
			Usage()
266
			return 0
267
268
		elif o == "-p":
269
			password = v
270
271
		elif o == "-r":
272
			reminder = int(v)
273
274
		elif o == "-R":
275
			force = True
276
277
		elif o == "-u":
278
			email = v
279 49
280
	if not email or not password or not fd:
281
		print "You did not specify the required arguments (username, password and file)"
282
		Usage()
283
		return 2
284
285
	try:
286
		ics = vobject.readOne(fd)
287
		fd.close()
288
	except Exception, e:
289
		print "cannot parse vcal input file: %s"  % ( str(e) )
290
		return 1
291
292 51
	if not uploadToGoogle(ics, email, password, calendar, reminder, force):
293 49
		return 1
294
295
	return 0
296
297
if __name__ == "__main__":
298
	sys.exit(Main(sys.argv[1:]))
299

Loggerhead 1.17 is a web-based interface for Bazaar branches