vpim 0.597 → 0.602

Sign up to get free protection for your applications and to get access to all the features.
data/bin/reminder ADDED
@@ -0,0 +1,203 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $-w = true
4
+
5
+ require 'ubygems' rescue "ignored"
6
+
7
+ require 'getoptlong'
8
+ require 'pp'
9
+ require 'plist'
10
+
11
+ require 'vpim/repo'
12
+
13
+ $stdout.sync = true
14
+ $stderr.sync = true
15
+
16
+ HELP =<<EOF
17
+ Usage: #{$0} [where]
18
+
19
+ Shows events and todos occuring soon.
20
+
21
+ By default, the Apple iCal v3 calendars are used, but if a location where
22
+ .ics files is specified, any calendars found there will be used.
23
+
24
+ Options
25
+ -h,--help Print this helpful message.
26
+ -n,--days N How many of the next days are considered to be "soon", default
27
+ is seven.
28
+ -v,--verbose Print more information about upcoming events.
29
+ EOF
30
+
31
+ opt_debug = nil
32
+ opt_verbose = nil
33
+ opt_days = 7
34
+
35
+ opts = GetoptLong.new(
36
+ [ "--help", "-h", GetoptLong::NO_ARGUMENT ],
37
+ [ "--days", "-n", GetoptLong::REQUIRED_ARGUMENT ],
38
+ [ "--verbose", "-v", GetoptLong::NO_ARGUMENT ],
39
+ [ "--debug", "-d", GetoptLong::NO_ARGUMENT ]
40
+ )
41
+
42
+ opts.each do |opt, arg|
43
+ case opt
44
+ when "--help" then
45
+ puts HELP
46
+ exit 0
47
+
48
+ when "--days" then
49
+ opt_days = arg.to_i
50
+
51
+ when "--verbose" then
52
+ opt_verbose = true
53
+
54
+ when "--debug" then
55
+ opt_verbose = true
56
+ opt_debug = true
57
+ end
58
+ end
59
+
60
+ calendars = []
61
+
62
+ if ARGV.length > 0
63
+ Vpim::Repo::Directory.each(ARGV.first) do |cal|
64
+ calendars << cal
65
+ end
66
+ else
67
+ Vpim::Repo::Ical3.each() do |cal|
68
+ calendars << cal
69
+ end
70
+ end
71
+
72
+ if opt_debug
73
+ pp ARGV
74
+ pp calendars
75
+ end
76
+
77
+ SECSPERDAY = (24 * 60 * 60)
78
+
79
+ t0 = Time.new.to_a
80
+ t0[0] = t0[1] = t0[2] = 0 # sec,min,hour = 0
81
+ t0 = Time.local(*t0)
82
+ t1 = t0 + opt_days * SECSPERDAY
83
+
84
+ if opt_debug
85
+ puts "to: #{t0}"
86
+ puts "t1: #{t1}"
87
+ end
88
+
89
+ if opt_verbose
90
+ puts "Events in the next #{opt_days} days:"
91
+ end
92
+
93
+ # Collect all events, then all todos.
94
+ all_events = []
95
+ all_todos = []
96
+
97
+ calendars.each do |cal|
98
+ if opt_debug; puts cal.name; end
99
+
100
+ begin
101
+ cal.events.each do |e|
102
+ begin
103
+ if opt_debug; pp e; end
104
+ if e.occurs_in?(t0, t1)
105
+ if e.summary
106
+ all_events.push(e)
107
+ end
108
+ end
109
+ rescue
110
+ $stderr.puts "error in #{cal.name} (\"#{e.summary}\"): #{$!.to_s}"
111
+ end
112
+ end
113
+
114
+ all_todos.concat(cal.todos)
115
+ end
116
+ end
117
+
118
+ puts
119
+
120
+ def start_of_first_occurence(t0, t1, e)
121
+ e.occurences.each_until(t1).each do |t|
122
+ # An event might start before t0, but end after it..., in which case
123
+ # we are still interested.
124
+ if (t + (e.duration || 0)) >= t0
125
+ return t
126
+ end
127
+ end
128
+ nil
129
+ end
130
+
131
+ all_events.sort! do |lhs, rhs|
132
+ start_of_first_occurence(t0, t1, lhs) <=> start_of_first_occurence(t0, t1, rhs)
133
+ end
134
+
135
+ all_events.each do |e|
136
+ puts "#{e.summary}:"
137
+
138
+ if opt_verbose
139
+ if e.description; puts " description=#{e.description}"; end
140
+ if e.comments; puts " comment=#{e.comments.first}"; end
141
+ if e.location; puts " location=#{e.location}"; end
142
+ if e.status; puts " status=#{e.status}"; end
143
+ if e.dtstart; puts " dtstart=#{e.dtstart}"; end
144
+ if e.duration; puts " duration=#{Vpim::Duration.new(e.duration).to_s}"; end
145
+ end
146
+
147
+ i = 1
148
+ e.occurences.each_until(t1).each do |t|
149
+ # An event might start before t0, but end after it..., in which case
150
+ # we are still interested.
151
+ dstr = ''
152
+ if e.duration
153
+ d = e.duration
154
+ dstr = " for #{Vpim::Duration.new(e.duration).to_s}"
155
+ end
156
+
157
+ if (t + (e.duration || 0)) >= t0
158
+ puts " ##{i} on #{t}#{dstr}"
159
+ i += 1
160
+ end
161
+ end
162
+ end
163
+
164
+ =begin
165
+ def fix_priority(vtodo)
166
+ p = vtodo.priority
167
+ if !p
168
+ p = 10
169
+
170
+ end
171
+ =end
172
+
173
+ all_todos.sort! do |x,y|
174
+ x = x.priority
175
+ y = y.priority
176
+
177
+ # 0 means no priority, put these last, not first
178
+ x = 10 if x == 0
179
+ y = 10 if y == 0
180
+
181
+ x <=> y
182
+ end
183
+
184
+ priorities = [
185
+ 'no importance',
186
+ 'very important',
187
+ 'very important',
188
+ 'very important',
189
+ 'important',
190
+ 'important',
191
+ 'important',
192
+ 'not important',
193
+ 'not important',
194
+ 'not important'
195
+ ]
196
+
197
+ all_todos.each do |e|
198
+ status = e.status || 'Todo'
199
+ if status != 'COMPLETED'
200
+ puts "#{status.capitalize}: #{e.summary}" # (#{priorities[e.priority]})"
201
+ end
202
+ end
203
+
data/bin/rrule ADDED
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $-w = true
4
+ $:.unshift File.dirname($0) + "/../lib"
5
+
6
+ require 'vpim/rrule'
7
+ require 'getoptlong'
8
+ require 'parsedate'
9
+
10
+ HELP =<<EOF
11
+ Usage: #{$0} [options] rrule
12
+
13
+ Options
14
+ -h,--help Print this helpful message.
15
+ -t,--start Start time for recurrence rule, defaults to current time.
16
+
17
+ Examples:
18
+
19
+ FREQ=DAILY;COUNT=10
20
+ FREQ=DAILY;UNTIL=19971224T000000Z
21
+ FREQ=DAILY;INTERVAL=2
22
+ FREQ=DAILY;INTERVAL=10;COUNT=5
23
+
24
+ Demonstrate DST time change:
25
+
26
+ #{$0} --start '2004-04-03 02:00' 'FREQ=daily;count=3'
27
+ #{$0} --start '2004-10-30 02:00' 'FREQ=daily;count=3'
28
+
29
+ Note: In the US DST starts at 2AM, on the first Sunday of April, and reverts
30
+ at 2AM on the last Sunday of October.
31
+
32
+ EOF
33
+
34
+ dtstart = Time.new
35
+
36
+ opts = GetoptLong.new(
37
+ [ "--help", "-h", GetoptLong::NO_ARGUMENT ],
38
+ [ "--start", "-t", GetoptLong::REQUIRED_ARGUMENT]
39
+ )
40
+
41
+ opts.each do |opt, arg|
42
+ case opt
43
+ when "--help" then
44
+ puts HELP
45
+ exit 0
46
+
47
+ when "--start" then
48
+ date = ParseDate.parsedate(arg)
49
+ date.pop
50
+ date.pop
51
+ dtstart = Time.local(*date)
52
+ end
53
+ end
54
+
55
+ if ARGV.length < 1
56
+ puts "no rrule specified, try -h!\n"
57
+ exit 1
58
+ end
59
+
60
+ puts "Start: #{Vpim.encode_date_time(dtstart)}"
61
+
62
+ ARGV.each do |rule|
63
+ rrule = Vpim::Rrule.new(dtstart, rule)
64
+
65
+ puts "Rule: #{rule}"
66
+
67
+ rrule.each_with_index do |t, count|
68
+ puts format("count=%3d %s", count, t.to_s)
69
+ end
70
+ end
71
+
@@ -288,7 +288,7 @@ seq
288
288
  set_text_list('CATEGORIES', cats)
289
289
  end
290
290
 
291
- # Set the comment, see Icalendar::Get::Common#comment.
291
+ # Set the comment, see Icalendar::Get::Common#comments.
292
292
  def comment(value)
293
293
  set_text 'COMMENT', value
294
294
  end
data/lib/vpim/repo.rb ADDED
@@ -0,0 +1,116 @@
1
+ =begin
2
+ Copyright (C) 2008 Sam Roberts
3
+
4
+ This library is free software; you can redistribute it and/or modify it
5
+ under the same terms as the ruby language itself, see the file COPYING for
6
+ details.
7
+ =end
8
+
9
+ require 'vpim/icalendar'
10
+ require 'vpim/duration'
11
+
12
+ module Vpim
13
+ # A Repo is a representation of an event repository. Currently iCalv3
14
+ # repositories and directories containing .ics files are supported.
15
+ #
16
+ # TODO - should yield them if a block is given, or return
17
+ # an enumerable otherwise. Later.
18
+ module Repo
19
+ def self.somethings_from_file(something, file) #:nodoc:
20
+ somethings = []
21
+ begin
22
+ cals = Vpim::Icalendar.decode(File.open(file))
23
+
24
+ cals.each do |cal|
25
+ cal.send(something).each do |x|
26
+ somethings << x
27
+ end
28
+ end
29
+ end
30
+ somethings
31
+ end
32
+
33
+ def self.events_from_file(file) #:nodoc:
34
+ self.somethings_from_file("events", file)
35
+ end
36
+
37
+ def self.todos_from_file(file) #:nodoc:
38
+ self.somethings_from_file("todos", file)
39
+ end
40
+
41
+ # An Apple iCal version 3 repository.
42
+ module Ical3
43
+ class Calendar
44
+ def initialize(dir) # :nodoc:
45
+ @dir = dir
46
+ end
47
+ def plist(key) #:nodoc:
48
+ Plist::parse_xml( @dir + "/Info.plist")[key]
49
+ end
50
+
51
+ # The calendar name.
52
+ def name
53
+ plist "Title"
54
+ end
55
+
56
+ # Whether a calendar should be displayed.
57
+ def displayed
58
+ 1 == plist("Checked")
59
+ end
60
+
61
+ # Array of all events defined in the calendar.
62
+ def events #:yield: Vevent
63
+ Dir[ @dir + "/Events/*.ics" ].map do |ics|
64
+ Repo.events_from_file(ics)
65
+ end.flatten
66
+ end
67
+
68
+ # Array of all todos defined in the calendar.
69
+ def todos #:yield: Vevent
70
+ Dir[ @dir + "/Events/*.ics" ].map do |ics|
71
+ Repo.todos_from_file(ics)
72
+ end.flatten
73
+ end
74
+
75
+ end
76
+
77
+ def self.each(where = "~/Library/Calendars") # :yield: Apple::Calendar
78
+ Dir[ File.expand_path(where + "/**/*.calendar") ].each do |dir|
79
+ yield Calendar.new(dir)
80
+ end
81
+ self
82
+ end
83
+ end
84
+ module Directory
85
+ class Calendar
86
+ def initialize(file) #:nodoc:
87
+ @file = file
88
+ end
89
+
90
+ def name
91
+ File.basename(@file)
92
+ end
93
+
94
+ def displayed
95
+ true
96
+ end
97
+
98
+ def events
99
+ Repo.events_from_file(@file)
100
+ end
101
+
102
+ def todos
103
+ Repo.todos_from_file(@file)
104
+ end
105
+ end
106
+
107
+ def self.each(where)
108
+ Dir[ File.expand_path(where + "/**/*.ics") ].each do |file|
109
+ yield Calendar.new(file)
110
+ end
111
+ self
112
+ end
113
+ end
114
+ end
115
+ end
116
+
data/lib/vpim/time.rb CHANGED
@@ -21,7 +21,7 @@ class Time
21
21
 
22
22
  # Returns a new Time, +months+ later than this time. The day will be
23
23
  # rounded down if it is not valid for that month.
24
- # 31 plus 1 month will be on Feb 28!
24
+ # Jan 31 plus 1 month will be on Feb 28!
25
25
  def plus_month(months)
26
26
  d = Date.new(year, month, day)
27
27
  d >>= months
data/lib/vpim/version.rb CHANGED
@@ -7,9 +7,9 @@
7
7
  =end
8
8
 
9
9
  module Vpim
10
- PRODID = '-//Ensemble Independent//vPim 0.597//EN'
10
+ PRODID = '-//Ensemble Independent//vPim 0.602//EN'
11
11
 
12
- VERSION = '0.597'
12
+ VERSION = '0.602'
13
13
 
14
14
  # Return the API version as a string.
15
15
  def Vpim.version
@@ -0,0 +1,93 @@
1
+
2
+ ** cmd-itip.rb
3
+
4
+ This script pretty-prints iTIP calendar invitations, often sent by email using iMIP
5
+ as text/calendar objects.
6
+
7
+ Download the latest vPim from:
8
+
9
+ http://rubyforge.org/projects/vpim/
10
+
11
+ It requires Ruby to be installed.
12
+
13
+ Install vpim:
14
+
15
+ tar -xzf vpim-XX.tgz
16
+ cd vpim-XX
17
+ ruby install.rb config
18
+ ruby install.rb setup
19
+ sudo ruby install.rb install
20
+
21
+ Install cmd-itip.rb into your path, perhaps without the extension.
22
+
23
+ cp samples/cmd-itip.rb ~/bin/cmd-itip
24
+ chmod +x ~/bin/cmd-itip
25
+
26
+ Modify your ~/.mailcap or /etc/mailcap files to call cmd-itip, add a line like:
27
+
28
+ text/calendar; cmd-itip --myaddr "sroberts@" %s; copiousoutput
29
+
30
+ If you give a REGEX to --myaddr to tell cmd-itip your email addresses, cmd-itip
31
+ will avoid printing some information on the attendees to an invitation.
32
+
33
+ Modify muttrc to autoview calendars with a command like:
34
+
35
+ auto_view text/calendar
36
+
37
+ Notes on Notes;
38
+
39
+ Because Domino sends a close-to-unreadable text/plain attachment along with the
40
+ text/calendar in a multipart/alternative, and the text/plain is first in the
41
+ alternatives, the garbage will be at the top, and the nicely printed calendar
42
+ at the bottom. Because of this, I reorder the view preference so the calendar
43
+ invitation is clearly printed at the top of the message with a muttrc command
44
+ like:
45
+
46
+ alternative_order text/calendar text/plain
47
+
48
+ Domino also includes the calendar twice in the mail message, so you'll see it
49
+ twice, I don't know what to do about that.
50
+
51
+ Notes on application/octet-stream:
52
+
53
+ Some calendar programs, such as Apple's Mail.app, wrongly send iCalendar attachments
54
+ with a content-type of application/octet-stream. In order to be processed correctly, use
55
+ the mutt 1.5 or later capability to lookup the correct MIME content-type based on the
56
+ file extension. Put this in your muttrc file:
57
+
58
+ mime_lookup application/octet-stream
59
+
60
+ and ensure /etc/mime.types or ~/.mime.types contains:
61
+
62
+ text/calendar ics
63
+
64
+
65
+
66
+ ** vcf-to-mutt.rb
67
+
68
+ This script searches a set of vCards can output the results as a Mutt query response,
69
+ or a Mutt aliases file.
70
+
71
+ It used to support querying the OS X Address Book, but that is better done with lbdb, see
72
+ http://www.spinnaker.de/lbdb/.
73
+
74
+ To install, you must:
75
+
76
+ 1 - install vPim (see README)
77
+
78
+ 3 - copy vcf-to-mutt into a directory in your path, such
79
+ as ~/bin, and chmod +x vcf-to-mutt.rb to make it executable.
80
+
81
+ 4 - Put in your muttrc file (either ~/.muttrc or ~/.mutt/muttrc) a line such as:
82
+
83
+ set query_command = "vcf-to-mutt.rb '%s'"
84
+
85
+ 5 - The query command ("Q") will query the address book, control-t will give you auto-completion
86
+ of email addresses, see the Mutt manual page.
87
+
88
+
89
+ ** mutt-aliases-to-vcf.rb
90
+
91
+ This script converts a mutt aliases file into a vCard file.
92
+
93
+
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $-w = true
4
+ $:.unshift File.dirname($0) + '/../lib'
5
+
6
+ require 'osx-wrappers'
7
+
8
+ require 'getoptlong'
9
+ require 'vpim/vcard'
10
+ require 'osx-wrappers'
11
+
12
+ HELP =<<EOF
13
+ Usage: ab-query.rb [--me] [--all]
14
+
15
+ Queries the OS X Address Book for vCards.
16
+
17
+ -h, --help print this helpful message
18
+ -m, --me list my vCard
19
+ -a, --all list all vCards
20
+ EOF
21
+
22
+ opts = GetoptLong.new(
23
+ [ "--help", "-h", GetoptLong::NO_ARGUMENT ],
24
+ [ "--me", "-m", GetoptLong::NO_ARGUMENT ],
25
+ [ "--all", "-a", GetoptLong::NO_ARGUMENT ]
26
+ )
27
+
28
+ abook = nil
29
+
30
+ opts.each do |opt, arg|
31
+ case opt
32
+ when "--help" then
33
+ puts HELP
34
+ exit 0
35
+
36
+ when "--all" then
37
+ abook = OSX::ABAddressBook.sharedAddressBook unless abook
38
+
39
+ abook.people.to_a.each {
40
+ |person|
41
+
42
+ puts person.vCard
43
+ }
44
+
45
+ when "--me" then
46
+ abook = OSX::ABAddressBook.sharedAddressBook unless abook
47
+
48
+ puts abook.me.vCard
49
+ end
50
+ end
51
+
52
+
53
+ unless abook
54
+ puts HELP
55
+ exit 1
56
+ end
57
+