mumboe-vpim 0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/CHANGES +510 -0
  2. data/COPYING +58 -0
  3. data/README +185 -0
  4. data/lib/vpim/address.rb +219 -0
  5. data/lib/vpim/agent/atomize.rb +104 -0
  6. data/lib/vpim/agent/base.rb +73 -0
  7. data/lib/vpim/agent/calendars.rb +173 -0
  8. data/lib/vpim/agent/handler.rb +26 -0
  9. data/lib/vpim/agent/ics.rb +161 -0
  10. data/lib/vpim/attachment.rb +102 -0
  11. data/lib/vpim/date.rb +222 -0
  12. data/lib/vpim/dirinfo.rb +277 -0
  13. data/lib/vpim/duration.rb +119 -0
  14. data/lib/vpim/enumerator.rb +32 -0
  15. data/lib/vpim/field.rb +614 -0
  16. data/lib/vpim/icalendar.rb +384 -0
  17. data/lib/vpim/maker/vcard.rb +16 -0
  18. data/lib/vpim/property/base.rb +193 -0
  19. data/lib/vpim/property/common.rb +315 -0
  20. data/lib/vpim/property/location.rb +38 -0
  21. data/lib/vpim/property/priority.rb +43 -0
  22. data/lib/vpim/property/recurrence.rb +69 -0
  23. data/lib/vpim/property/resources.rb +24 -0
  24. data/lib/vpim/repo.rb +261 -0
  25. data/lib/vpim/rfc2425.rb +367 -0
  26. data/lib/vpim/rrule.rb +591 -0
  27. data/lib/vpim/time.rb +40 -0
  28. data/lib/vpim/vcard.rb +1456 -0
  29. data/lib/vpim/version.rb +18 -0
  30. data/lib/vpim/vevent.rb +187 -0
  31. data/lib/vpim/view.rb +90 -0
  32. data/lib/vpim/vjournal.rb +58 -0
  33. data/lib/vpim/vpim.rb +65 -0
  34. data/lib/vpim/vtodo.rb +103 -0
  35. data/lib/vpim.rb +13 -0
  36. data/samples/README.mutt +93 -0
  37. data/samples/ab-query.rb +57 -0
  38. data/samples/agent.ru +10 -0
  39. data/samples/cmd-itip.rb +156 -0
  40. data/samples/ex_cpvcard.rb +55 -0
  41. data/samples/ex_get_vcard_photo.rb +22 -0
  42. data/samples/ex_mkv21vcard.rb +34 -0
  43. data/samples/ex_mkvcard.rb +64 -0
  44. data/samples/ex_mkyourown.rb +29 -0
  45. data/samples/ics-dump.rb +210 -0
  46. data/samples/ics-to-rss.rb +84 -0
  47. data/samples/mutt-aliases-to-vcf.rb +45 -0
  48. data/samples/osx-wrappers.rb +86 -0
  49. data/samples/reminder.rb +209 -0
  50. data/samples/rrule.rb +71 -0
  51. data/samples/tabbed-file-to-vcf.rb +390 -0
  52. data/samples/vcf-dump.rb +86 -0
  53. data/samples/vcf-lines.rb +61 -0
  54. data/samples/vcf-to-ics.rb +22 -0
  55. data/samples/vcf-to-mutt.rb +121 -0
  56. data/test/test_agent_atomize.rb +84 -0
  57. data/test/test_agent_calendars.rb +128 -0
  58. data/test/test_agent_ics.rb +96 -0
  59. data/test/test_all.rb +17 -0
  60. data/test/test_date.rb +120 -0
  61. data/test/test_dur.rb +41 -0
  62. data/test/test_field.rb +156 -0
  63. data/test/test_ical.rb +437 -0
  64. data/test/test_misc.rb +13 -0
  65. data/test/test_repo.rb +129 -0
  66. data/test/test_rrule.rb +1030 -0
  67. data/test/test_vcard.rb +973 -0
  68. data/test/test_view.rb +79 -0
  69. 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
+
@@ -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
+