gcalevents 0.4.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ p1�S���4l,��w �𗍾5����O[���,i����:1��A��ڝ$hB��9@0I��ut�����uM�I ���XX���"<XR��d��%,L����R�����2Y�m?�s�OoU_��\�d�e�IwO�}!и*�}��:؈uQ�xZ/5�Lo̡qK:�p�� �m�24K�]~ �G86eHfX�\�����v�>L�^ �$�yD>{�76�؃ j�D�ϚCSِ8��� ��m�����d�
@@ -0,0 +1,40 @@
1
+ CHANGELOG
2
+ *********
3
+ 0.4.10 2007-11-13
4
+ -----------------
5
+ Change of display format
6
+
7
+ 0.4.9 2007-11-11
8
+ ----------------
9
+ Description can be displayed shortened.
10
+
11
+ 0.4.8
12
+ -----
13
+ Bugfixes:
14
+ - works with one or none calendars defined in configuration
15
+
16
+ 0.4.7
17
+ -----
18
+ Added RDoc.
19
+ Bugfixes:
20
+ - added support for Windows without HOME environmental variable
21
+ Changes:
22
+ - "next day" to "earliest day" :)
23
+
24
+ 0.4.6
25
+ -----
26
+ Bugfixes:
27
+ - dealing with events that started in the past
28
+ - sending emails
29
+
30
+ 0.4.5
31
+ -----
32
+ - added displaying of Location field
33
+
34
+ 0.4.4
35
+ -----
36
+ - added email address and title to XML configuration
37
+
38
+ 0.4.0
39
+ -----
40
+ - Added sending mail
@@ -0,0 +1,7 @@
1
+ CHANGELOG
2
+ Manifest.txt
3
+ README
4
+ Rakefile
5
+ bin/gcalevents
6
+ lib/calendarchecker.rb
7
+ lib/calendars.rb
data/README ADDED
@@ -0,0 +1,40 @@
1
+ = GCalEvents
2
+
3
+ Read events from your Google Calendars and put it on console or sends to GMail.
4
+ Allow configuration of different 'look forward' time for different calendars.
5
+
6
+ == Instalation
7
+ Please use ruby gems:
8
+ % gem install --remote gcalevents+.
9
+
10
+ === Configuration
11
+ Configuration is stored in XML file at: $HOME/.gcalendar.xml.
12
+
13
+ ==== Sample configuration file
14
+ <?xml version="1.0" encoding="UTF-8"?>
15
+ <config>
16
+ <username>username@gmail.com</username> <!-- Google Account username -->
17
+ <password>y0uRpAsSw04d</password> <!-- Google Account password -->
18
+ <days>0</days> <!-- How many days in the future to read -->
19
+ <email_to>my@email.address</email_to> <!--Optional. Email address to send notifications. Default: username.-->
20
+ <email_to>my_friend@email.address</email_to> <!--Optional. There can be many email addresses.-->
21
+ <email_subject>MySubject</email_subject> <!--Optional. Default: "Google Calendar Events".-->
22
+ <banner>Upcoming events</banner> <!--Optional. Displayed before events. Default: "-=Events on Google Calendar=-". -->
23
+ <calendars> <!--Optional. By default read all calendars for days specified in this XML. -->
24
+ <title forward="7">Realy important calendar</title>
25
+ <title forward="3">Birdthday</title>
26
+ <title forward="false" regexp="true">^Not really that important</title>
27
+ </calendars>
28
+ </config>
29
+ == Usage
30
+ When configured properly just run:
31
+ % gcalevents
32
+ After some time events will show off.
33
+
34
+ Read help for parameters:
35
+ % gcalevents -h
36
+
37
+ == Author
38
+ Roman 'MrStone' Kamyk (mailto:rkj@go2.pl),
39
+ Student of Poznan University Of Technology, Computing Science Institute.
40
+
@@ -0,0 +1,22 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ require './lib/calendarchecker.rb'
6
+
7
+ Hoe.new('gcalevents', PROGVERSION) do |p|
8
+ p.rubyforge_name = 'gcalevents'
9
+ p.author = "Roman Kamyk"
10
+ p.email = 'roman.kamyk@gmail.com'
11
+ p.summary = 'Reads Google Calendar and prints events'
12
+ p.url = "http://gcalevents.rubyforge.org"
13
+ p.extra_deps = ["rake", "gcalapi", "xml-simple", "gmailer"]
14
+ @changes = p.changes = p.paragraphs_of('CHANGELOG', 0..1).join("\n\n")
15
+ end
16
+
17
+ task :publish => [:release, :post_news, :publish_docs] do
18
+ sh "svn ci -m '#{@changes}'"
19
+ sh "hg ci -m '#{@changes}'"
20
+ end
21
+
22
+ # vim: syntax=Ruby
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/ruby
2
+
3
+ begin
4
+ require 'calendarchecker.rb'
5
+ rescue LoadError
6
+ require 'rubygems'
7
+ require 'calendarchecker.rb'
8
+ end
9
+ GCalendarChecker.new.putEvents
10
+
@@ -0,0 +1,249 @@
1
+ #!/usr/bin/ruby
2
+ # See README
3
+ require 'rubygems'
4
+ require "googlecalendar/calendar"
5
+ require 'xmlsimple'
6
+ require 'optparse'
7
+ require 'calendars'
8
+ require 'gmailer'
9
+ require 'pp'
10
+
11
+ PROGNAME = "GCalEvents"
12
+ PROGVERSION = "0.4.10"
13
+
14
+ # Big, bad main class serving everything.
15
+ class GCalendarChecker
16
+ # read configuration from XML file.
17
+ def readConfig
18
+ xml = XmlSimple.xml_in(File.new("#{ENV['HOME'] || ENV['USERPROFILE']}/.gcalendar.xml"), "ForceArray"=>["title"])
19
+ @options[:username] = xml["username"]
20
+ @options[:password] = xml["password"]
21
+ @server = GoogleCalendar::Service.new(@options[:username], @options[:password])
22
+ @calendars = Calendars.new(xml["calendars"]);
23
+ @options[:forward] = xml["days"].to_i
24
+ @options[:email_to] = xml["email_to"] || @options[:username]
25
+ @options[:email_subject] = xml["email_subject"] || "Google Calendar Events"
26
+ @options[:banner] = xml["banner"] || "-=Events on Google Calendar=-"
27
+ @options[:desc_len] = xml["description_length"].to_i || -1
28
+ if $DEBUG
29
+ puts @options.inspect
30
+ puts @options[:email_to].class
31
+ @options[:email_to].each { |to|
32
+ puts "sendmail(msg, #{to})"
33
+ }
34
+ end
35
+ end
36
+
37
+ # Parses arguments from commandline
38
+ def parseOptions
39
+ OptionParser.new do |opts|
40
+ opts.banner = "Usage: #{$0} [options]"
41
+ opts.program_name = PROGNAME
42
+ opts.on("-d", "--days N", Integer, "Read events N days in the future") do |n|
43
+ @options[:forward] = n;
44
+ end
45
+ opts.on("-f", "--from-date Date", "Read events starting from Date") do |fromdate|
46
+ @options[:fromdate] = Time.parse(fromdate)
47
+ end
48
+ opts.on("-t", "--to-date Date", "Read events until Date. (Unless longer period specified by --date or in config file)") do |todate|
49
+ @options[:todate] = Time.parse(todate)
50
+ end
51
+ opts.on("-m", "--match-only Name", "Read events only from calendar Name") do |n|
52
+ @options[:match_only] = Regexp.new(n, true)
53
+ end
54
+ opts.on("-s", "--send-mail", "Send email with event to you google account") { @options[:send_mail] = true }
55
+ opts.on("-n", "--no-output", "Do not print anything to stdout") { @options[:no_output] = true }
56
+ opts.on("-e", "--encrypt", "Encrypt mail") { @options[:encrypt] = true }
57
+ opts.on("-i", "--sign", "Sign mail") { @options[:sign] = true }
58
+ opts.on_tail("-v", "--version", "Show version") do
59
+ puts "#{PROGNAME}, version #{PROGVERSION}"
60
+ exit
61
+ end
62
+ opts.on_tail("-h", "--help", "Show this message") do
63
+ puts opts
64
+ exit
65
+ end
66
+ end.parse!
67
+ @options
68
+ end
69
+
70
+ def initialize
71
+ @options = {}
72
+ begin
73
+ readConfig
74
+ rescue => e
75
+ puts "Error during parsing configuration: #{e}!"
76
+ puts e.backtrace
77
+ exit
78
+ end
79
+ begin
80
+ parseOptions
81
+ rescue => e
82
+ puts "Error during parsing options: #{e}!"
83
+ exit
84
+ end
85
+ if @options[:fromdate]
86
+ @startTime = @options[:fromdate]
87
+ else
88
+ @startTime = Time.now
89
+ end
90
+ if @options[:todate]
91
+ @endTime = @options[:todate]
92
+ else
93
+ @endTime = Time.local(@startTime.year, @startTime.month, @startTime.day, 23, 59, 59, 99)
94
+ end
95
+ end
96
+
97
+ def isToday(time)
98
+ now = Time.now
99
+ time.day == now.day and now+3600*24 > time
100
+ end
101
+
102
+ def isNextWeek(time)
103
+ nextWeek = Time.now+3600*24*6
104
+ time > Time.now and Time.local(nextWeek.year, nextWeek.month, nextWeek.day, 23, 59, 59, 99) > time
105
+ end
106
+
107
+ def isThisMonth(time)
108
+ now = Time.now
109
+ time.month == now.month
110
+ end
111
+
112
+ def isThisYear(time)
113
+ now = Time.now
114
+ time.year == now.year
115
+ end
116
+
117
+ def sameDay(t1, t2)
118
+ t2 -= 1 # So XXXX-YY-01 00:00 and XXXX-YY-02 00:00 be same days ;)
119
+ t1.day == t2.day and t1.month == t2.month and t1.year == t2.year
120
+ end
121
+
122
+ # Translates start and end time into a nice string.
123
+ def formatEventTime(time, endTime)
124
+ unless endTime.nil? or sameDay(time, endTime)
125
+ return "from #{formatTime(time)} to #{formatTime(endTime)}"
126
+ else
127
+ return "#{formatTime(time)}"
128
+ end
129
+ end
130
+
131
+ # Translates time into a string depending on how much in the future
132
+ # it is.
133
+ # It is:
134
+ # - "today",
135
+ # - "this weekday", if it is in one week,
136
+ # - "weekday monthday", if it is in this month,
137
+ # - "weekday monthday yearday", if it is this year,
138
+ # - "weekday isodate", else
139
+ def formatTime(time)
140
+ return "today" if isToday(time)
141
+ return "#{time.strftime("%a")}" if isNextWeek(time)
142
+ return "#{time.strftime("%a %d")}" if isThisMonth(time)
143
+ return "#{time.strftime("%a %d %b")}" if isThisYear(time)
144
+ return "#{time.strftime("%a %Y-%m-%d")}"
145
+ end
146
+
147
+ def shortDesc(desc)
148
+ noLB = desc.gsub(/\s+/, " ")
149
+ return noLB unless noLB.length > @options[:desc_len]
150
+ return noLB[0..@options[:desc_len]] + "..."
151
+ end
152
+
153
+ # Translates event into nice string, containing:
154
+ # - Title
155
+ # - Desciption
156
+ # - Location
157
+ # - Start and end time
158
+ def eventToString(event)
159
+ string = ""
160
+ est = event.st.localtime unless event.st.nil?
161
+ een = event.en.localtime unless event.en.nil?
162
+ unless est.nil?
163
+ string << "#{formatEventTime(est, een)}"
164
+ time = " #{est.strftime("%H:%M")}"
165
+ time << "-#{event.en.localtime.strftime("%H:%M")}"
166
+ string << time unless time == " 00:00-00:00"
167
+ end
168
+ string << "|#{event.title}"
169
+ string << " (#{shortDesc(event.desc)})" unless event.desc.nil? or event.desc.empty?
170
+ string << " @ #{event.where}" unless event.where.nil? or event.where.empty?
171
+ string
172
+ end
173
+
174
+ # Sends email containg body to *to* person using Google account from XML configuration.
175
+ def sendmail(body, receiver)
176
+ if @options[:encrypt]
177
+ body = `echo '#{body}' | gpg --armor -ser '#{receiver}'`
178
+ elsif @options[:sign]
179
+ body = `echo '#{body}' | gpg --clearsign -r '#{receiver}'`
180
+ end
181
+ GMailer.connect(@options[:username], @options[:password]) do |g|
182
+ g.send(
183
+ :to => receiver,
184
+ :subject => @options[:email_subject],
185
+ :body => body
186
+ )
187
+ end
188
+ end
189
+
190
+ def max(a, b)
191
+ return a if a>b
192
+ return b
193
+ end
194
+
195
+ def collectEvents(cal, startTime, endTime)
196
+ cal.events({"start-min"=>startTime, "start-max"=>endTime, "orderby"=>"starttime"}).collect { |event|
197
+ {:cal=>cal, :event=>event} unless event.st.nil?
198
+ }
199
+ end
200
+
201
+ # Reads events from Google Calendars
202
+ def getEvents
203
+ events = []
204
+ if $DEBUG
205
+ puts @server
206
+ puts GoogleCalendar::Calendar.calendars(@server)
207
+ end
208
+ GoogleCalendar::Calendar.calendars(@server).each { |feed, cal|
209
+ next unless @calendars.display?(cal.title)
210
+ next if @options[:match_only] and !(cal.title =~ @options[:match_only])
211
+ forward = max(@calendars.forward(cal.title), @options[:forward])
212
+ items = collectEvents(cal, @startTime, @endTime+24*3600*forward)
213
+ if $DEBUG
214
+ puts items
215
+ end
216
+ events += items.reject { |a| a.nil?} unless items.nil?
217
+ }
218
+ events
219
+ end
220
+
221
+ # Main method that puts all events on console and send email if apropriate.
222
+ def putEvents
223
+ begin
224
+ events = getEvents.sort{|a, b|
225
+ a[:event].st <=> b[:event].st
226
+ }
227
+ msg = "#{@options[:banner]}\n"
228
+ events.each { |event|
229
+ msg += "#{event[:cal].title}|#{eventToString(event[:event])}\n"
230
+ }
231
+ rescue => e
232
+ puts "Error during reading GCalendar - #{e}"
233
+ puts e.backtrace
234
+ exit
235
+ end
236
+ if @options[:send_mail]
237
+ @options[:email_to].each { |to|
238
+ sendmail(msg, to)
239
+ }
240
+ end
241
+ unless @options[:no_output]
242
+ puts msg
243
+ end
244
+ end
245
+ end
246
+
247
+ if $0 == __FILE__
248
+ GCalendarChecker.new.putEvents
249
+ end
@@ -0,0 +1,60 @@
1
+ # Remembers calendar meta data from xml configuration.
2
+ class Calendar
3
+ def initialize(calendar)
4
+ @regexp = false;
5
+ @display = true;
6
+ @forward = 0;
7
+ if calendar["forward"] == "false"
8
+ @display = false
9
+ else
10
+ @forward = calendar["forward"].to_i
11
+ end
12
+ @regexp = true if calendar["regexp"] == "true"
13
+ @title = calendar["content"]
14
+ if $DEBUG
15
+ puts calendar.inspect
16
+ puts "D: #{@display}, RE: #{@regexp}\n*******"
17
+ end
18
+ end
19
+
20
+ # Checks if title match this calendar.
21
+ def match?(title)
22
+ if @regexp
23
+ return title =~ /#{@title}/
24
+ else
25
+ return title == @title
26
+ end
27
+ end
28
+
29
+ attr_reader :forward, :display
30
+ end
31
+
32
+ # Container for calendars read from configuration.
33
+ class Calendars
34
+ def initialize(calendars)
35
+ @calendars = [];
36
+ return if calendars.nil?
37
+ calendars["title"].each { |cal|
38
+ @calendars << Calendar.new(cal)
39
+ }
40
+ end
41
+
42
+ # Checks if any calendar match title.
43
+ def display?(title)
44
+ cal = @calendars.find { |cal|
45
+ cal.match?(title)
46
+ }
47
+ return cal.display unless cal.nil?
48
+ return true;
49
+ end
50
+
51
+ # Returns how many days in the future calendar should be chcecked.
52
+ def forward(title)
53
+ cal = @calendars.find { |cal|
54
+ cal.match?(title)
55
+ }
56
+ return cal.forward unless cal.nil?
57
+ return 0;
58
+ end
59
+ end
60
+
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.4
3
+ specification_version: 1
4
+ name: gcalevents
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.4.10
7
+ date: 2007-11-13 00:00:00 +01:00
8
+ summary: Reads Google Calendar and prints events
9
+ require_paths:
10
+ - lib
11
+ email: roman.kamyk@gmail.com
12
+ homepage: http://gcalevents.rubyforge.org
13
+ rubyforge_project: gcalevents
14
+ description: The author was too lazy to write a description
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ - |
29
+ -----BEGIN CERTIFICATE-----
30
+ MIIDODCCAiCgAwIBAgIBADANBgkqhkiG9w0BAQUFADBCMRQwEgYDVQQDDAtyb21h
31
+ bi5rYW15azEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPyLGQBGRYD
32
+ Y29tMB4XDTA3MTExMDA1MzUzM1oXDTA4MTEwOTA1MzUzM1owQjEUMBIGA1UEAwwL
33
+ cm9tYW4ua2FteWsxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixk
34
+ ARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMdV1ujoU4I2
35
+ daF4KANtDPTSjLYhXC1CiiyEgGEVA6GvieQ2NpNNsSXl+6tbWXGNUWFHj50rrLTC
36
+ e1dJSGGTZa9ZjI6fkeb/Gr13s71ncCJ+hBbpvktWIWdvOvzvNo9bdzNCKX00Rlk5
37
+ hQzxhm/ZxQ2VG4ZDYc/gWOCzKYH8aKrAzzdjRsxE/QMgnVbnirCGSPQTjPVhBvcX
38
+ pH2yDvZF9NOs3D89JvA4P50WRCe8/kKPx7TG9Qkd303/FmO8yDUvJn0KgiYkm1pc
39
+ Sb+kcDZnh2+2uvkygLLDQhV5m7DfFLLkgwb/t7R4tSNFqcHoa0829rnSVBbCZACg
40
+ mrXhThP3LX8CAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0O
41
+ BBYEFGVgSLBvjD5kTd+1XMf58PK9llj6MA0GCSqGSIb3DQEBBQUAA4IBAQCGX43w
42
+ PspP+rmsfCKztiUwtfb4d+eqW62WaAUBT37KeW8IEm3UpAe5T1c3fFm46bxM3a2Y
43
+ wUeLqSMSquXNzb2fy+3vLAUYHc4UkR5nA5kB+F3RJwuc7LJCBGlkPsCfa91dE6j5
44
+ S80vqeRf4ITITHZbFLuVFFvQb/nPGe2LtyP4+neAktSu4r7rQ5vLbQQ/NSAliFrP
45
+ pJbWXmfjKQsDKGgs1TiISC3kfLcynhCgCcbLCek5Oc0U195z36e8x3aYEJSGFVmF
46
+ y8xfBxyZ4t0FP3lTPvGMfmSKOVOjcwT4OVpzdvRXWR8lghrQlAzNG5HdOxMzeBjb
47
+ Z2byiG0rlbybmXMS
48
+ -----END CERTIFICATE-----
49
+
50
+ post_install_message:
51
+ authors:
52
+ - Roman Kamyk
53
+ files:
54
+ - CHANGELOG
55
+ - Manifest.txt
56
+ - README
57
+ - Rakefile
58
+ - bin/gcalevents
59
+ - lib/calendarchecker.rb
60
+ - lib/calendars.rb
61
+ test_files: []
62
+
63
+ rdoc_options:
64
+ - --main
65
+ - README.txt
66
+ extra_rdoc_files:
67
+ - Manifest.txt
68
+ executables:
69
+ - gcalevents
70
+ extensions: []
71
+
72
+ requirements: []
73
+
74
+ dependencies:
75
+ - !ruby/object:Gem::Dependency
76
+ name: rake
77
+ version_requirement:
78
+ version_requirements: !ruby/object:Gem::Version::Requirement
79
+ requirements:
80
+ - - ">"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.0.0
83
+ version:
84
+ - !ruby/object:Gem::Dependency
85
+ name: gcalapi
86
+ version_requirement:
87
+ version_requirements: !ruby/object:Gem::Version::Requirement
88
+ requirements:
89
+ - - ">"
90
+ - !ruby/object:Gem::Version
91
+ version: 0.0.0
92
+ version:
93
+ - !ruby/object:Gem::Dependency
94
+ name: xml-simple
95
+ version_requirement:
96
+ version_requirements: !ruby/object:Gem::Version::Requirement
97
+ requirements:
98
+ - - ">"
99
+ - !ruby/object:Gem::Version
100
+ version: 0.0.0
101
+ version:
102
+ - !ruby/object:Gem::Dependency
103
+ name: gmailer
104
+ version_requirement:
105
+ version_requirements: !ruby/object:Gem::Version::Requirement
106
+ requirements:
107
+ - - ">"
108
+ - !ruby/object:Gem::Version
109
+ version: 0.0.0
110
+ version:
111
+ - !ruby/object:Gem::Dependency
112
+ name: hoe
113
+ version_requirement:
114
+ version_requirements: !ruby/object:Gem::Version::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: 1.3.0
119
+ version:
@@ -0,0 +1,2 @@
1
+ ��v��<��D~������\��'/�˭G_,~�� $����ɽ%[7�'�bi}����^ǣ�\�t��c��k�~pK暉�5��<\%��Nu�)�sQ����Sd�T�?�.H�Bȧ"����qvw]�.�fv�Q��Ws�H�9�k�� �\S e��|��o�2��������$O*a#�5��%�kǠ�{j�d(
2
+ ~��u-�"A�[�"q6����ȿ�J�W� ����F;�,^�1bpu�>�����Y