mumboe-vpim 0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +510 -0
- data/COPYING +58 -0
- data/README +185 -0
- data/lib/vpim/address.rb +219 -0
- data/lib/vpim/agent/atomize.rb +104 -0
- data/lib/vpim/agent/base.rb +73 -0
- data/lib/vpim/agent/calendars.rb +173 -0
- data/lib/vpim/agent/handler.rb +26 -0
- data/lib/vpim/agent/ics.rb +161 -0
- data/lib/vpim/attachment.rb +102 -0
- data/lib/vpim/date.rb +222 -0
- data/lib/vpim/dirinfo.rb +277 -0
- data/lib/vpim/duration.rb +119 -0
- data/lib/vpim/enumerator.rb +32 -0
- data/lib/vpim/field.rb +614 -0
- data/lib/vpim/icalendar.rb +384 -0
- data/lib/vpim/maker/vcard.rb +16 -0
- data/lib/vpim/property/base.rb +193 -0
- data/lib/vpim/property/common.rb +315 -0
- data/lib/vpim/property/location.rb +38 -0
- data/lib/vpim/property/priority.rb +43 -0
- data/lib/vpim/property/recurrence.rb +69 -0
- data/lib/vpim/property/resources.rb +24 -0
- data/lib/vpim/repo.rb +261 -0
- data/lib/vpim/rfc2425.rb +367 -0
- data/lib/vpim/rrule.rb +591 -0
- data/lib/vpim/time.rb +40 -0
- data/lib/vpim/vcard.rb +1456 -0
- data/lib/vpim/version.rb +18 -0
- data/lib/vpim/vevent.rb +187 -0
- data/lib/vpim/view.rb +90 -0
- data/lib/vpim/vjournal.rb +58 -0
- data/lib/vpim/vpim.rb +65 -0
- data/lib/vpim/vtodo.rb +103 -0
- data/lib/vpim.rb +13 -0
- data/samples/README.mutt +93 -0
- data/samples/ab-query.rb +57 -0
- data/samples/agent.ru +10 -0
- data/samples/cmd-itip.rb +156 -0
- data/samples/ex_cpvcard.rb +55 -0
- data/samples/ex_get_vcard_photo.rb +22 -0
- data/samples/ex_mkv21vcard.rb +34 -0
- data/samples/ex_mkvcard.rb +64 -0
- data/samples/ex_mkyourown.rb +29 -0
- data/samples/ics-dump.rb +210 -0
- data/samples/ics-to-rss.rb +84 -0
- data/samples/mutt-aliases-to-vcf.rb +45 -0
- data/samples/osx-wrappers.rb +86 -0
- data/samples/reminder.rb +209 -0
- data/samples/rrule.rb +71 -0
- data/samples/tabbed-file-to-vcf.rb +390 -0
- data/samples/vcf-dump.rb +86 -0
- data/samples/vcf-lines.rb +61 -0
- data/samples/vcf-to-ics.rb +22 -0
- data/samples/vcf-to-mutt.rb +121 -0
- data/test/test_agent_atomize.rb +84 -0
- data/test/test_agent_calendars.rb +128 -0
- data/test/test_agent_ics.rb +96 -0
- data/test/test_all.rb +17 -0
- data/test/test_date.rb +120 -0
- data/test/test_dur.rb +41 -0
- data/test/test_field.rb +156 -0
- data/test/test_ical.rb +437 -0
- data/test/test_misc.rb +13 -0
- data/test/test_repo.rb +129 -0
- data/test/test_rrule.rb +1030 -0
- data/test/test_vcard.rb +973 -0
- data/test/test_view.rb +79 -0
- metadata +140 -0
@@ -0,0 +1,86 @@
|
|
1
|
+
# OSX wrapper methods.
|
2
|
+
#
|
3
|
+
# The OSX classes are mirrored fairly directly into ruby by ruby/cocoa. Too
|
4
|
+
# directly for ease, this is a start at convenient ruby APIs on top of the low-level cocoa
|
5
|
+
# methods.
|
6
|
+
|
7
|
+
=begin
|
8
|
+
|
9
|
+
Ideas for things to add:
|
10
|
+
|
11
|
+
+ each for the addressbook
|
12
|
+
|
13
|
+
+ ABRecord#[] <- valueForProperty
|
14
|
+
|
15
|
+
+ [] and each for NSCFArray (which is actually an instance of OCObject)
|
16
|
+
|
17
|
+
+ [] and each for NSCFDictionary (which is actually an instance of OCObject)
|
18
|
+
|
19
|
+
+ Can I add methods to OCObject, and have them implement themselves based on the the 'class'?
|
20
|
+
|
21
|
+
+ ABMultiValue#[index]
|
22
|
+
|
23
|
+
if index
|
24
|
+
|
25
|
+
is a :token, then its the identifier,
|
26
|
+
is a string, its a label
|
27
|
+
is a number, its an array index
|
28
|
+
|
29
|
+
return a Struct, so you can do
|
30
|
+
|
31
|
+
mvalue["work"].value
|
32
|
+
|
33
|
+
=end
|
34
|
+
|
35
|
+
require 'osx/addressbook'
|
36
|
+
|
37
|
+
# put into osx/ocobject?
|
38
|
+
module OSX
|
39
|
+
# When an NSData object is returned by an objective/c API (such as
|
40
|
+
# ABPerson.vCardRepresentation, I actually get a OCObject back, who's class
|
41
|
+
# instance points to either a NSData, or a related class.
|
42
|
+
#
|
43
|
+
# This is a convenience method to get the NSData data back as a ruby string.
|
44
|
+
# Is it the right place to put this?
|
45
|
+
class OCObject
|
46
|
+
def bytes
|
47
|
+
s = ' ' * length
|
48
|
+
getBytes(s)
|
49
|
+
s
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# put into osx/abperson?
|
55
|
+
module OSX
|
56
|
+
class ABPerson
|
57
|
+
def vCard
|
58
|
+
card = self.vCardRepresentation.bytes
|
59
|
+
|
60
|
+
# The card representation appears to be either ASCII, or UCS-2. If its
|
61
|
+
# UCS-2, then the first byte will be 0, so check for this, and convert
|
62
|
+
# if necessary.
|
63
|
+
#
|
64
|
+
# We know it's 0, because the first character in a vCard must be the 'B'
|
65
|
+
# of "BEGIN:VCARD", and in UCS-2 all ascii are encoded as a 0 byte
|
66
|
+
# followed by the ASCII byte, UNICODE is great.
|
67
|
+
if card[0] == 0
|
68
|
+
nsstring = OSX::NSString.alloc.initWithCharacters(card, :length, card.size/2)
|
69
|
+
card = nsstring.UTF8String
|
70
|
+
|
71
|
+
# TODO: is nsstring.UTF8String == nsstring.to_s ?
|
72
|
+
end
|
73
|
+
card
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# put into osx/group?
|
79
|
+
module OSX
|
80
|
+
class ABGroup
|
81
|
+
def name
|
82
|
+
self.valueForProperty(OSX::kABGroupNameProperty).to_s
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
data/samples/reminder.rb
ADDED
@@ -0,0 +1,209 @@
|
|
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 .ics
|
22
|
+
files can be found 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_dump = nil
|
33
|
+
opt_verbose = nil
|
34
|
+
opt_days = 7
|
35
|
+
|
36
|
+
opts = GetoptLong.new(
|
37
|
+
[ "--help", "-h", GetoptLong::NO_ARGUMENT ],
|
38
|
+
[ "--days", "-n", GetoptLong::REQUIRED_ARGUMENT ],
|
39
|
+
[ "--verbose", "-v", GetoptLong::NO_ARGUMENT ],
|
40
|
+
[ "--debug", "-d", GetoptLong::NO_ARGUMENT ]
|
41
|
+
)
|
42
|
+
|
43
|
+
opts.each do |opt, arg|
|
44
|
+
case opt
|
45
|
+
when "--help" then
|
46
|
+
puts HELP
|
47
|
+
exit 0
|
48
|
+
|
49
|
+
when "--days" then
|
50
|
+
opt_days = arg.to_i
|
51
|
+
|
52
|
+
when "--verbose" then
|
53
|
+
opt_verbose = true
|
54
|
+
|
55
|
+
when "--debug" then
|
56
|
+
opt_verbose = true
|
57
|
+
if opt_debug
|
58
|
+
opt_dump = true
|
59
|
+
end
|
60
|
+
opt_debug = true
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
calendars = []
|
65
|
+
|
66
|
+
if ARGV.length > 0
|
67
|
+
Vpim::Repo::Directory.each(ARGV.first) do |cal|
|
68
|
+
calendars << cal
|
69
|
+
end
|
70
|
+
else
|
71
|
+
Vpim::Repo::Apple3.new.each() do |cal|
|
72
|
+
calendars << cal
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
if opt_dump
|
77
|
+
pp ARGV
|
78
|
+
pp calendars
|
79
|
+
end
|
80
|
+
|
81
|
+
SECSPERDAY = (24 * 60 * 60)
|
82
|
+
|
83
|
+
t0 = Time.new.to_a
|
84
|
+
t0[0] = t0[1] = t0[2] = 0 # sec,min,hour = 0
|
85
|
+
t0 = Time.local(*t0)
|
86
|
+
t1 = t0 + opt_days * SECSPERDAY
|
87
|
+
|
88
|
+
if opt_dump
|
89
|
+
puts "to: #{t0}"
|
90
|
+
puts "t1: #{t1}"
|
91
|
+
end
|
92
|
+
|
93
|
+
if opt_verbose
|
94
|
+
puts "Events in the next #{opt_days} days:"
|
95
|
+
end
|
96
|
+
|
97
|
+
# Collect all events, then all todos.
|
98
|
+
all_events = []
|
99
|
+
all_todos = []
|
100
|
+
|
101
|
+
calendars.each do |cal|
|
102
|
+
if opt_debug; puts "Calendar: #{cal.name}"; end
|
103
|
+
|
104
|
+
# TODO - mv collection algorithm to library
|
105
|
+
begin
|
106
|
+
cal.events.each do |e|
|
107
|
+
begin
|
108
|
+
if opt_dump; pp e; end
|
109
|
+
if e.occurs_in?(t0, t1)
|
110
|
+
if e.summary
|
111
|
+
all_events.push(e)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
rescue
|
115
|
+
$stderr.puts "error in #{cal.name} (\"#{e.summary}\"): #{$!.to_s}"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
all_todos.concat(cal.todos.to_a)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
puts
|
124
|
+
|
125
|
+
# TODO - mv sorting algorithm to library
|
126
|
+
def start_of_first_occurrence(t0, t1, e)
|
127
|
+
e.occurrences(t1) do |t|
|
128
|
+
# An event might start before t0, but end after it..., in which case
|
129
|
+
# we are still interested.
|
130
|
+
if (t + (e.duration || 0)) >= t0
|
131
|
+
return t
|
132
|
+
end
|
133
|
+
end
|
134
|
+
nil
|
135
|
+
end
|
136
|
+
|
137
|
+
all_events.sort! do |lhs, rhs|
|
138
|
+
start_of_first_occurrence(t0, t1, lhs) <=> start_of_first_occurrence(t0, t1, rhs)
|
139
|
+
end
|
140
|
+
|
141
|
+
all_events.each do |e|
|
142
|
+
puts "#{e.summary}:"
|
143
|
+
|
144
|
+
if opt_verbose
|
145
|
+
if e.description; puts " description=#{e.description}"; end
|
146
|
+
if e.comments.any?; puts " comment=#{e.comments.first}"; end
|
147
|
+
if e.location; puts " location=#{e.location}"; end
|
148
|
+
if e.status; puts " status=#{e.status}"; end
|
149
|
+
if e.dtstart; puts " dtstart=#{e.dtstart}"; end
|
150
|
+
if e.duration; puts " duration=#{Vpim::Duration.new(e.duration).to_s}"; end
|
151
|
+
end
|
152
|
+
|
153
|
+
i = 1
|
154
|
+
e.occurrences(t1) do |t|
|
155
|
+
# An event might start before t0, but end after it..., in which case
|
156
|
+
# we are still interested.
|
157
|
+
dstr = ''
|
158
|
+
if e.duration
|
159
|
+
dstr = " for #{Vpim::Duration.new(e.duration).to_s}"
|
160
|
+
end
|
161
|
+
|
162
|
+
# TODO - mv to library, as variant of occurs_in?
|
163
|
+
if (t + (e.duration || 0)) >= t0
|
164
|
+
puts " ##{i} on #{t}#{dstr}"
|
165
|
+
i += 1
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
=begin
|
171
|
+
def fix_priority(vtodo)
|
172
|
+
p = vtodo.priority
|
173
|
+
if !p
|
174
|
+
p = 10
|
175
|
+
|
176
|
+
end
|
177
|
+
=end
|
178
|
+
|
179
|
+
all_todos.sort! do |x,y|
|
180
|
+
x = x.priority
|
181
|
+
y = y.priority
|
182
|
+
|
183
|
+
# 0 means no priority, put these last, not first
|
184
|
+
x = 10 if x == 0
|
185
|
+
y = 10 if y == 0
|
186
|
+
|
187
|
+
x <=> y
|
188
|
+
end
|
189
|
+
|
190
|
+
priorities = [
|
191
|
+
'no importance',
|
192
|
+
'very important',
|
193
|
+
'very important',
|
194
|
+
'very important',
|
195
|
+
'important',
|
196
|
+
'important',
|
197
|
+
'important',
|
198
|
+
'not important',
|
199
|
+
'not important',
|
200
|
+
'not important'
|
201
|
+
]
|
202
|
+
|
203
|
+
all_todos.each do |e|
|
204
|
+
status = e.status || 'Todo'
|
205
|
+
if status != 'COMPLETED'
|
206
|
+
puts "#{status.capitalize}: #{e.summary}" # (#{priorities[e.priority]})"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
data/samples/rrule.rb
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
|
+
|