vpim 0.695 → 13.11.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/{README → README.rdoc} +2 -13
  3. data/lib/vpim.rb +1 -0
  4. data/lib/vpim/address.rb +3 -2
  5. data/lib/vpim/agent/atomize.rb +4 -0
  6. data/lib/vpim/agent/base.rb +74 -0
  7. data/lib/vpim/agent/calendars.rb +1 -0
  8. data/lib/vpim/agent/handler.rb +27 -0
  9. data/lib/vpim/agent/ics.rb +162 -0
  10. data/lib/vpim/attachment.rb +1 -0
  11. data/lib/vpim/date.rb +3 -2
  12. data/lib/vpim/dirinfo.rb +5 -4
  13. data/lib/vpim/duration.rb +1 -0
  14. data/lib/vpim/enumerator.rb +1 -0
  15. data/lib/vpim/field.rb +3 -2
  16. data/lib/vpim/icalendar.rb +9 -5
  17. data/lib/vpim/maker/vcard.rb +1 -0
  18. data/lib/vpim/property/base.rb +1 -0
  19. data/lib/vpim/property/common.rb +1 -0
  20. data/lib/vpim/property/location.rb +10 -0
  21. data/lib/vpim/property/priority.rb +2 -1
  22. data/lib/vpim/property/recurrence.rb +1 -0
  23. data/lib/vpim/property/resources.rb +1 -2
  24. data/lib/vpim/repo.rb +2 -1
  25. data/lib/vpim/rfc2425.rb +32 -24
  26. data/lib/vpim/rrule.rb +9 -8
  27. data/lib/vpim/time.rb +1 -0
  28. data/lib/vpim/vcard.rb +13 -11
  29. data/lib/vpim/version.rb +2 -2
  30. data/lib/vpim/vevent.rb +3 -1
  31. data/lib/vpim/view.rb +3 -2
  32. data/lib/vpim/vjournal.rb +1 -0
  33. data/lib/vpim/vpim.rb +2 -1
  34. data/lib/vpim/vtodo.rb +1 -0
  35. data/samples/agent.ru +10 -0
  36. data/test/test_all.rb +2 -0
  37. data/test/test_date.rb +6 -5
  38. data/test/test_dur.rb +1 -0
  39. data/test/test_field.rb +3 -2
  40. data/test/test_ical.rb +12 -2
  41. data/test/test_misc.rb +13 -0
  42. data/test/test_repo.rb +22 -2
  43. data/test/test_rrule.rb +1 -0
  44. data/test/test_vcard.rb +53 -1
  45. metadata +36 -46
  46. data/lib/vpim/agent/app.rb +0 -194
  47. data/lib/vpim/agent/main.rb +0 -327
  48. data/lib/vpim/agent/scraps.rb +0 -292
  49. data/test/test_agent_app.rb +0 -74
  50. data/test/test_agent_atomize.rb +0 -84
  51. data/test/test_agent_calendars.rb +0 -128
  52. data/test/test_view.rb +0 -79
@@ -1,327 +0,0 @@
1
- require 'etc'
2
- require 'pp'
3
- require 'rss/maker'
4
- require 'socket'
5
- require 'webrick'
6
- require 'vpim/icalendar'
7
- require 'vpim/vcard'
8
-
9
- #--------------------------------------------------------------------------------
10
- # Load DNSSD support, if possible.
11
- # TODO - should be in net/dns/dnssd
12
- # FIXME - doesn't work with dnssd
13
- @avoid_native = true
14
- begin
15
- if @avoid_native
16
- raise LoadError
17
- else
18
- require 'dnssd'
19
- end
20
- rescue LoadError
21
- begin
22
- require 'net/dns/mdns-sd'
23
- DNSSD = Net::DNS::MDNSSD
24
- rescue LoadError
25
- DNSSD = nil
26
- end
27
- end
28
-
29
- #--------------------------------------------------------------------------------
30
- # Set up server environment.
31
-
32
- # Find the user's name and host.
33
-
34
- require 'etc'
35
-
36
- $user = Etc.getpwuid(Process.uid).gecos
37
- $host = Socket.gethostname
38
-
39
- $services = []
40
-
41
- $stuff = []
42
-
43
- def register(name, path, protocol = 'http')
44
- # $services << DNSSD.register(name, '_http._tcp', 'local', $port, 'path' => path )
45
-
46
- puts "register #{name.inspect} on path #{path.inspect} with #{protocol}"
47
-
48
- $stuff << [name, path, protocol]
49
- end
50
-
51
- # Create a HTTP server, possibly on a dynamic port.
52
- # - Dynamic ports don't actually work well. While it is true we can advertise them,
53
- # non-DNSSD aware clients will store the hostname and port when they subscribe to
54
- # a calendar, but when the server restarts the port will be different. Not good.
55
- $port = 8191
56
-
57
- server = WEBrick::HTTPServer.new( :Port => $port )
58
-
59
- if $port == 0
60
- # Server may have created multiple listeners, all on a different dynamically
61
- # assigned port.
62
- families = Socket.getaddrinfo(nil, 1, Socket::AF_UNSPEC, Socket::SOCK_STREAM, 0, Socket::AI_PASSIVE)
63
-
64
- listeners = []
65
-
66
- families.each do |af, one, dns, addr|
67
- listeners << TCPServer.new(addr, $port)
68
- $port = listeners.first.addr[1] unless $port != 0
69
- end
70
-
71
- listeners.each do |s|
72
- puts "listen on #{s.addr.inspect}"
73
- end
74
-
75
- # So we replace them with our TCPServer sockets which are all on the same
76
- # (dynamically assigned) port.
77
- server.listeners.each do |s| s.close end
78
- server.listeners.replace listeners
79
- server.config[:Port] = $port
80
- end
81
-
82
- server.config[:MimeTypes]['ics'] = 'text/calendar'
83
- server.config[:MimeTypes]['vcf'] = 'text/directory'
84
-
85
- #--------------------------------------------------------------------------------
86
- # Mount services
87
-
88
- ##### Vcard Birthdays as iCalendar
89
- =begin
90
- $vcf_bday_file = 'vpim-bday.vcf'
91
- $vcf_bday_path = '/vcf/bday.ics'
92
-
93
- class VcfBdayIcsServlet < WEBrick::HTTPServlet::AbstractServlet
94
- def do_GET(req, resp)
95
- cal = Vpim::Icalendar.create
96
-
97
- open($vcf_bday_file) do |vcf|
98
- Vpim::Vcard.decode(vcf).each do |card|
99
- begin
100
- bday = card.birthday
101
- if bday
102
- cal.push Vpim::Icalendar::Vevent.create_yearly(
103
- card.birthday,
104
- "Birthday for #{card['fn'].strip}"
105
- )
106
- $stderr.puts "#{card['fn']} -> bday #{cal.events.last.dtstart}"
107
- end
108
- rescue
109
- $stderr.puts $!
110
- $stderr.puts $!.backtrace.join("\n")
111
- end
112
- end
113
- end
114
-
115
- resp.body = cal.encode
116
- resp['content-type'] = 'text/calendar'
117
-
118
- # Is this necessary, or is it default?
119
- raise WEBrick::HTTPStatus::OK
120
- end
121
- end
122
-
123
- server.mount( $vcf_bday_path, VcfBdayIcsServlet )
124
-
125
- register( "Calendar for all the Birthdays in my vCards", $vcf_bday_path, 'webcal' )
126
- =end
127
-
128
- ##### iCalendar as calendars
129
- # Export local calendars two different ways
130
- =begin
131
- $ical_folder = File.expand_path( "~/Library/Calendars" )
132
-
133
- #
134
- # Here we write a servlet to display all the allowed calendars with
135
- # webcal links, so they open in iCal.
136
- #
137
- $ical_include = /^[A-Z]/
138
- $ical_title = "My Calendars"
139
-
140
- class IcalIcsServlet < WEBrick::HTTPServlet::AbstractServlet
141
- def do_GET(req, resp)
142
- body = ''
143
- # body << @options.inspect
144
-
145
- folder, include, exclude = *@options
146
-
147
- path = req.path_info
148
-
149
- # body << "\n"
150
- # body << "path=#{path.inspect}\n"
151
-
152
- all = Dir.entries(folder).select do |f| f =~ /\.ics$/ end
153
-
154
- if include
155
- all.reject! do |f| !(f =~ include) end
156
- end
157
- if exclude
158
- all.reject! do |f| f =~ exclude end
159
- end
160
-
161
- # body << "#{all.inspect}\n"
162
-
163
- if(path == '')
164
- body << "<ul>\n"
165
- all.each do |f|
166
- n = f.sub('.ics', '')
167
- body << "<li><a href=\"webcal://#{$host}:#{$port}/calfile/#{f}\">#{n}</a>\n"
168
- end
169
- body << "</ul>\n"
170
- end
171
-
172
- resp.body = body
173
- resp['content-type'] = 'text/html'
174
- raise WEBrick::HTTPStatus::OK
175
- end
176
- end
177
-
178
- server.mount( '/calweb', IcalIcsServlet, $ical_folder, $ical_include)
179
-
180
- register( "My Calendars as webcal:// Feeds", '/calweb' )
181
-
182
- #
183
- # We use the WEBrick file servlet to actually serve calendar files.
184
- # FIXME - this means that if you guess someone's calendar name, you can
185
- # download it, despite the rudimentary security.
186
- #
187
- server.mount( '/calfile', WEBrick::HTTPServlet::FileHandler, $ical_folder, :FancyIndexing=>true )
188
-
189
- # For debugging...
190
- register( 'My Calendar Folder', '/calfile' )
191
-
192
- =end
193
-
194
- ##### iCalendar/todo as RSS
195
- =begin
196
- $ics_todo_title = 'My Todo Items as an RSS Feed'
197
- $ics_todo_path = "/ics/todo.rss"
198
-
199
- class IcalTodoRssServlet < WEBrick::HTTPServlet::AbstractServlet
200
- def do_GET(req, resp)
201
- rss = RSS::Maker.make("0.9") do |maker|
202
- title = $ics_todo_title
203
- link = 'http:///'
204
- maker.channel.title = title
205
- maker.channel.link = link
206
- maker.channel.description = title
207
- maker.channel.language = 'en-us'
208
-
209
- # These are required, or RSS::Maker silently returns nil!
210
- maker.image.url = "maker.image.url"
211
- maker.image.title = "maker.image.title"
212
-
213
- Dir[ $ical_folder + "/*.ics" ].each do |file|
214
- # TODO: use the open with a block variant
215
- Vpim::Icalendar.decode(File.open(file)).each do |cal|
216
- cal.todos.each do |todo|
217
- if !todo.status || todo.status.upcase != "COMPLETED"
218
- item = maker.items.new_item
219
- item.title = todo.summary
220
- item.link = todo.properties['url'] || link
221
- item.description = todo.description || todo.summary
222
- end
223
- end
224
- end
225
- end
226
- end
227
-
228
- resp.body = rss.to_s
229
- resp['content-type'] = 'text/xml'
230
-
231
- raise WEBrick::HTTPStatus::OK
232
- end
233
- end
234
-
235
- server.mount( $ics_todo_path, IcalTodoRssServlet )
236
-
237
- register( $ics_todo_title, $ics_todo_path )
238
- =end
239
-
240
- ##### Local calendars
241
-
242
- require "vpim/agent/calendars"
243
-
244
- $ical_folder = File.expand_path( "~/Library/Calendars" )
245
-
246
- class CalendarsServlet < WEBrick::HTTPServlet::AbstractServlet
247
- def do_GET(req, resp)
248
- body = ''
249
- # body << @options.inspect
250
-
251
- folder = *@options
252
-
253
- # TODO Should be longer lived
254
- repo = Vpim::Repo::Apple3.new($ical_folder)
255
- rest = Vpim::Agent::Calendars.new(repo)
256
- path = Vpim::Agent::Path.new(req.request_uri, req.path)
257
-
258
- begin
259
- body, form = rest.get(path)
260
- status = 200
261
- rescue Vpim::Agent::NotFound
262
- body = $!.to_s
263
- form = "text/plain" # should be HTML!
264
- status = 404
265
- end
266
-
267
- resp.status = status
268
- resp.body = body
269
- resp['content-type'] = form
270
- end
271
- end
272
-
273
- server.mount( '/calendars', CalendarsServlet, $ical_folder )
274
-
275
- register( "Calendars", '/calendars' )
276
-
277
- #--------------------------------------------------------------------------------
278
- ## Top-level page.
279
-
280
- $vpim_title = "vAgent for #{$user}"
281
-
282
- class VpimServlet < WEBrick::HTTPServlet::AbstractServlet
283
- def do_GET(req, resp)
284
- body = <<"EOF"
285
- <h1>#{$vpim_title}</h1>
286
-
287
- See:
288
- <ul>
289
- EOF
290
-
291
- $stuff.each do |name,path,protocol|
292
- #body << "<li><a href=\"#{protocol}://#{$host}:#{$port}#{path}\">#{name}</a>\n"
293
- #
294
- # $host is wrong, it lacks the domain - we should derive this from how
295
- # we are called, or just leave it out.
296
- body << "<li><a href=\"#{path}\">#{name}</a>\n"
297
- end
298
-
299
- body << "</ul>\n"
300
-
301
- resp.body = body
302
- resp['content-type'] = 'text/html'
303
- raise WEBrick::HTTPStatus::OK
304
- end
305
- end
306
-
307
- server.mount( '/', VpimServlet )
308
-
309
- #--------------------------------------------------------------------------------
310
- # Run server
311
-
312
- if DNSSD
313
- $services << DNSSD.register($vpim_title, '_http._tcp', 'local', $port, 'path' => '/' )
314
- end
315
-
316
- ['INT', 'TERM'].each do |signal|
317
- trap(signal) do
318
- server.shutdown
319
- $services.each do |s|
320
- s.stop
321
- end
322
- end
323
- end
324
-
325
- server.start
326
-
327
-
@@ -1,292 +0,0 @@
1
- require 'etc'
2
- require 'rss/maker'
3
- require 'socket'
4
- require 'webrick'
5
- require 'vpim/icalendar'
6
- require 'vpim/vcard'
7
-
8
- # Notes on debugging with dnssd API: check system.log, it should give info.
9
-
10
- #require 'pp'
11
- #module Kernel
12
- # def to_pp
13
- # s = PP.pp(self, '')
14
- # s.chomp!
15
- # s
16
- # end
17
- #end
18
-
19
-
20
- #--------------------------------------------------------------------------------
21
- # Load DNSSD support, if possible.
22
- # TODO - should be in net/dns/dnssd
23
- # FIXME - doesn't work with dnssd
24
- @avoid_native = true
25
- begin
26
- if @avoid_native
27
- raise LoadError
28
- else
29
- require 'dnssd'
30
- end
31
- rescue LoadError
32
- begin
33
- require 'net/dns/mdns-sd'
34
- DNSSD = Net::DNS::MDNSSD
35
- rescue LoadError
36
- DNSSD = nil
37
- end
38
- end
39
-
40
- #--------------------------------------------------------------------------------
41
- # Set up server environment.
42
-
43
- # Find the user's name and host.
44
-
45
- require 'etc'
46
-
47
- $user = Etc.getpwuid(Process.uid).gecos
48
- $host = Socket.gethostname
49
-
50
- $services = []
51
-
52
- $stuff = []
53
-
54
- def register(name, path, protocol = 'http')
55
- # $services << DNSSD.register(name, '_http._tcp', 'local', $port, 'path' => path )
56
-
57
- puts "register #{name.inspect} on path #{path.inspect} with #{protocol}"
58
-
59
- $stuff << [name, path, protocol]
60
- end
61
-
62
- # Create a HTTP server, possibly on a dynamic port.
63
- # - Dynamic ports don't actually work well. While it is true we can advertise them,
64
- # non-DNSSD aware clients will store the hostname and port when they subscribe to
65
- # a calendar, but when the server restarts the port will be different. Not good.
66
- $port = 8191
67
-
68
- server = WEBrick::HTTPServer.new( :Port => $port )
69
-
70
- if $port == 0
71
- # Server may have created multiple listeners, all on a different dynamically
72
- # assigned port.
73
- families = Socket.getaddrinfo(nil, 1, Socket::AF_UNSPEC, Socket::SOCK_STREAM, 0, Socket::AI_PASSIVE)
74
-
75
- listeners = []
76
-
77
- families.each do |af, one, dns, addr|
78
- listeners << TCPServer.new(addr, $port)
79
- $port = listeners.first.addr[1] unless $port != 0
80
- end
81
-
82
- listeners.each do |s|
83
- puts "listen on #{s.addr.inspect}"
84
- end
85
-
86
- # So we replace them with our TCPServer sockets which are all on the same
87
- # (dynamically assigned) port.
88
- server.listeners.each do |s| s.close end
89
- server.listeners.replace listeners
90
- server.config[:Port] = $port
91
- end
92
-
93
- server.config[:MimeTypes]['ics'] = 'text/calendar'
94
- server.config[:MimeTypes]['vcf'] = 'text/directory'
95
-
96
- #--------------------------------------------------------------------------------
97
- # Mount services
98
-
99
- ##### Vcard Birthdays as iCalendar
100
-
101
- $vcf_bday_file = 'vpim-bday.vcf'
102
- $vcf_bday_path = '/vcf/bday.ics'
103
-
104
- class VcfBdayIcsServlet < WEBrick::HTTPServlet::AbstractServlet
105
- def do_GET(req, resp)
106
- cal = Vpim::Icalendar.create
107
-
108
- open($vcf_bday_file) do |vcf|
109
- Vpim::Vcard.decode(vcf).each do |card|
110
- begin
111
- bday = card.birthday
112
- if bday
113
- cal.push Vpim::Icalendar::Vevent.create_yearly(
114
- card.birthday,
115
- "Birthday for #{card['fn'].strip}"
116
- )
117
- $stderr.puts "#{card['fn']} -> bday #{cal.events.last.dtstart}"
118
- end
119
- rescue
120
- $stderr.puts $!
121
- $stderr.puts $!.backtrace.join("\n")
122
- end
123
- end
124
- end
125
-
126
- resp.body = cal.encode
127
- resp['content-type'] = 'text/calendar'
128
-
129
- # Is this necessary, or is it default?
130
- raise WEBrick::HTTPStatus::OK
131
- end
132
- end
133
-
134
- server.mount( $vcf_bday_path, VcfBdayIcsServlet )
135
-
136
- register( "Calendar for all the Birthdays in my vCards", $vcf_bday_path, 'webcal' )
137
-
138
- ##### iCalendar as calendars
139
- # Export local calendars two different ways
140
-
141
- $ical_folder = File.expand_path( "~/Library/Calendars" )
142
-
143
- #
144
- # Here we write a servlet to display all the allowed calendars with
145
- # webcal links, so they open in iCal.
146
- #
147
- $ical_include = /^[A-Z]/
148
- $ical_title = "My Calendars"
149
-
150
- class IcalIcsServlet < WEBrick::HTTPServlet::AbstractServlet
151
- def do_GET(req, resp)
152
- body = ''
153
- # body << @options.inspect
154
-
155
- folder, include, exclude = *@options
156
-
157
- path = req.path_info
158
-
159
- # body << "\n"
160
- # body << "path=#{path.inspect}\n"
161
-
162
- all = Dir.entries(folder).select do |f| f =~ /\.ics$/ end
163
-
164
- if include
165
- all.reject! do |f| !(f =~ include) end
166
- end
167
- if exclude
168
- all.reject! do |f| f =~ exclude end
169
- end
170
-
171
- # body << "#{all.inspect}\n"
172
-
173
- if(path == '')
174
- body << "<ul>\n"
175
- all.each do |f|
176
- n = f.sub('.ics', '')
177
- body << "<li><a href=\"webcal://#{$host}:#{$port}/calfile/#{f}\">#{n}</a>\n"
178
- end
179
- body << "</ul>\n"
180
- end
181
-
182
- resp.body = body
183
- resp['content-type'] = 'text/html'
184
- raise WEBrick::HTTPStatus::OK
185
- end
186
- end
187
-
188
- server.mount( '/calweb', IcalIcsServlet, $ical_folder, $ical_include)
189
-
190
- register( "My Calendars as webcal:// Feeds", '/calweb' )
191
-
192
- #
193
- # We use the WEBrick file servlet to actually serve calendar files.
194
- # FIXME - this means that if you guess someone's calendar name, you can
195
- # download it, despite the rudimentary security.
196
- #
197
- server.mount( '/calfile', WEBrick::HTTPServlet::FileHandler, $ical_folder, :FancyIndexing=>true )
198
-
199
- # For debugging...
200
- register( 'My Calendar Folder', '/calfile' )
201
-
202
- ##### iCalendar/todo as RSS
203
-
204
- $ics_todo_title = 'My Todo Items as an RSS Feed'
205
- $ics_todo_path = "/ics/todo.rss"
206
-
207
- class IcalTodoRssServlet < WEBrick::HTTPServlet::AbstractServlet
208
- def do_GET(req, resp)
209
- rss = RSS::Maker.make("0.9") do |maker|
210
- title = $ics_todo_title
211
- link = 'http:///'
212
- maker.channel.title = title
213
- maker.channel.link = link
214
- maker.channel.description = title
215
- maker.channel.language = 'en-us'
216
-
217
- # These are required, or RSS::Maker silently returns nil!
218
- maker.image.url = "maker.image.url"
219
- maker.image.title = "maker.image.title"
220
-
221
- Dir[ $ical_folder + "/*.ics" ].each do |file|
222
- # TODO: use the open with a block variant
223
- Vpim::Icalendar.decode(File.open(file)).each do |cal|
224
- cal.todos.each do |todo|
225
- if !todo.status || todo.status.upcase != "COMPLETED"
226
- item = maker.items.new_item
227
- item.title = todo.summary
228
- item.link = todo.properties['url'] || link
229
- item.description = todo.description || todo.summary
230
- end
231
- end
232
- end
233
- end
234
- end
235
-
236
- resp.body = rss.to_s
237
- resp['content-type'] = 'text/xml'
238
-
239
- raise WEBrick::HTTPStatus::OK
240
- end
241
- end
242
-
243
- server.mount( $ics_todo_path, IcalTodoRssServlet )
244
-
245
- register( $ics_todo_title, $ics_todo_path )
246
-
247
-
248
- #--------------------------------------------------------------------------------
249
- ## Top-level page.
250
-
251
- $vpim_title = "vPim for #{$user}"
252
-
253
- class VpimServlet < WEBrick::HTTPServlet::AbstractServlet
254
- def do_GET(req, resp)
255
- body = <<"EOF"
256
- <h1>#{$vpim_title}</h1>
257
-
258
- You can access:
259
- <ul>
260
- EOF
261
-
262
- $stuff.each do |name,path,protocol|
263
- body << "<li><a href=\"#{protocol}://#{$host}:#{$port}#{path}\">#{name}</a>\n"
264
- end
265
-
266
- body << "</ul>\n"
267
-
268
- resp.body = body
269
- resp['content-type'] = 'text/html'
270
- raise WEBrick::HTTPStatus::OK
271
- end
272
- end
273
-
274
- server.mount( '/', VpimServlet )
275
-
276
- #--------------------------------------------------------------------------------
277
- # Run server
278
-
279
- $services << DNSSD.register($vpim_title, '_http._tcp', 'local', $port, 'path' => '/' )
280
-
281
- ['INT', 'TERM'].each do |signal|
282
- trap(signal) do
283
- server.shutdown
284
- $services.each do |s|
285
- s.stop
286
- end
287
- end
288
- end
289
-
290
- server.start
291
-
292
-