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.
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
+