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,156 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $-w = true
4
+ $:.unshift File.dirname($0) + '/../lib'
5
+
6
+ require 'getoptlong'
7
+
8
+ require 'vpim/icalendar'
9
+ require 'vpim/duration'
10
+
11
+ include Vpim
12
+
13
+ # TODO - $0 is the full path, fix it.
14
+ HELP =<<EOF
15
+ Usage: #{$0} <invitation.ics>
16
+
17
+ Options
18
+ -h,--help Print this helpful message.
19
+ -d,--debug Print debug information.
20
+
21
+ -m,--my-addrs My email addresses, a REGEX.
22
+ Examples:
23
+ EOF
24
+
25
+ opt_debug = nil
26
+ opt_print = true
27
+
28
+ # Ways to get this:
29
+ # Use a --mutt option, and steal it from muttrc,
30
+ # from $USER, $LOGNAME,, from /etc/passwd...
31
+ opt_myaddrs = nil
32
+
33
+ opts = GetoptLong.new(
34
+ [ "--help", "-h", GetoptLong::NO_ARGUMENT ],
35
+
36
+ [ "--myaddrs", "-m", GetoptLong::REQUIRED_ARGUMENT ],
37
+
38
+ [ "--accept", "-a", GetoptLong::REQUIRED_ARGUMENT ],
39
+ [ "--reject", "-r", GetoptLong::REQUIRED_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 "--debug" then
50
+ require 'pp'
51
+ opt_debug = true
52
+
53
+ when "--myaddrs" then
54
+ opt_myaddrs = Regexp.new(arg, 'i')
55
+ end
56
+ end
57
+
58
+ if ARGV.length < 1
59
+ puts "no input files specified, try -h!\n"
60
+ exit 1
61
+ end
62
+
63
+ ARGV.each do |file|
64
+ cals = Vpim::Icalendar.decode(File.open(file))
65
+
66
+ cals.each do |cal|
67
+ if opt_debug
68
+ puts "vCalendar: version=#{cal.version/10.0} producer='#{cal.producer}'"
69
+ if cal.protocol; puts " protocol-method=#{cal.protocol}"; end
70
+ end
71
+
72
+ events = cal.events
73
+
74
+ if events.size != 1
75
+ raise "!! #{events.size} calendar events is more than 1!"
76
+ end
77
+
78
+ events.each do |e|
79
+ summary = e.summary || e.comment || ''
80
+
81
+ case cal.protocol.upcase
82
+ when 'PUBLISH'
83
+ puts "Notification of: #{summary}"
84
+
85
+ when 'REQUEST'
86
+ puts "Request for: #{summary}"
87
+
88
+ when 'REPLY'
89
+
90
+ else
91
+ raise "!! unhandled protocol type #{cal.protocol}!"
92
+ end
93
+
94
+ puts "Organized by: #{e.organizer.to_s}"
95
+
96
+ # TODO - spec as hours/mins/secs
97
+ e.occurrences.each_with_index do |t, i|
98
+ if(i < 1)
99
+ puts "At time: #{t}" +( e.duration ? " for #{Duration.secs(e.duration).to_s}" : '' )
100
+ else
101
+ puts "... and others"
102
+ break
103
+ end
104
+ end
105
+
106
+ if e.location; puts "Located at: #{e.location}"; end
107
+
108
+ if e.description
109
+ puts finish="-- Description --"
110
+ puts e.description
111
+ end
112
+
113
+ if e.comments
114
+ puts finish="-- Comment --"
115
+ puts " comment=#{e.comments}"
116
+ end
117
+
118
+ if e.attendees.first
119
+
120
+ puts finish="-- Attendees --"
121
+
122
+ e.attendees.each_with_index do |a,i|
123
+ puts "#{i} #{a.to_s}"
124
+ if !opt_myaddrs || a.uri =~ opt_myaddrs
125
+ puts " participation-status: #{a.partstat ? a.partstat.downcase : 'unknown'}"
126
+ puts " response-requested? #{a.rsvp ? 'yes' : 'no'}"
127
+ end
128
+ end
129
+ end
130
+
131
+ if finish
132
+ puts '-' * finish.length
133
+ end
134
+
135
+ if opt_debug
136
+ if e.status; puts " status=#{e.status}"; end
137
+ puts " uid=#{e.uid}"
138
+ puts " dtstamp=#{e.dtstamp.to_s}"
139
+ puts " dtstart=#{e.dtstart.to_s}"
140
+ if e.dtend; puts " dtend=#{e.dtend.to_s}"; end
141
+ if e.rrule; puts " rrule=#{e.rrule}"; end
142
+ end
143
+ end
144
+
145
+ todos = cal.todos
146
+ todos.each do |e|
147
+ s = e.status ? " (#{e.status})" : ''
148
+ puts "Todo#{s}: #{e.summary}"
149
+ end
150
+
151
+ if opt_debug
152
+ pp cals
153
+ end
154
+ end
155
+ end
156
+
@@ -0,0 +1,55 @@
1
+ require 'vpim/vcard'
2
+
3
+ ORIGINAL =<<'---'
4
+ BEGIN:VCARD
5
+ VERSION:3.0
6
+ FN:Jimmy Death
7
+ N:Death;Jimmy;;Dr.;
8
+ TEL:+416 123 1111
9
+ TEL;type=home,pref:+416 123 2222
10
+ TEL;type=work,fax:+416+123+3333
11
+ EMAIL;type=work:drdeath@work.com
12
+ EMAIL;type=pref:drdeath@home.net
13
+ NOTE:Do not call.
14
+ END:VCARD
15
+ ---
16
+
17
+ original = Vpim::Vcard.decode(ORIGINAL).first
18
+
19
+ puts original
20
+
21
+ modified = Vpim::Vcard::Maker.make2 do |maker|
22
+ # Set the fullname field to use family-given name order.
23
+ maker.name do |n|
24
+ n.fullname = "#{original.name.family} #{original.name.given}"
25
+ end
26
+
27
+ # Copy original fields, with some changes:
28
+ # - set only work email addresses and telephone numbers to be preferred.
29
+ # - don't copy notes
30
+ maker.copy(original) do |field|
31
+ if field.name? 'EMAIL'
32
+ field = field.copy
33
+ field.pref = field.type? 'work'
34
+ end
35
+ if field.name? 'TEL'
36
+ field = field.copy
37
+ field.pref = field.type? 'work'
38
+ end
39
+ if field.name? 'NOTE'
40
+ field = nil
41
+ end
42
+ field
43
+ end
44
+ end
45
+
46
+ puts '---'
47
+ puts modified
48
+
49
+ Vpim::Vcard::Maker.make2(modified) do |maker|
50
+ maker.nickname = "Your Last Friend"
51
+ end
52
+
53
+ puts '---'
54
+ puts modified
55
+
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+ require 'vpim/vcard'
4
+
5
+ vcf = open(ARGV[0] || 'data/vcf/Sam Roberts.vcf')
6
+
7
+ card = Vpim::Vcard.decode(vcf).first
8
+
9
+ card.photos.each_with_index do |photo, i|
10
+ file = "_photo_#{i}."
11
+
12
+ if photo.format
13
+ file += photo.format.gsub('/', '_')
14
+ else
15
+ # You are your own if PHOTO doesn't include a format. AddressBook.app
16
+ # exports TIFF, for example, but doesn't specify that.
17
+ file += 'tiff'
18
+ end
19
+
20
+ open(file, 'w').write photo.to_s
21
+ end
22
+
@@ -0,0 +1,34 @@
1
+ # Note that while most version 3.0 vCards should be valid 2.1 vCards, they
2
+ # aren't guaranteed to be. vCard 2.1 is reasonably well supported on decode,
3
+ # I'm not sure how well it works on encode.
4
+ #
5
+ # Most things should work, but you should test whether this works with your 2.1
6
+ # vCard decoder. Also, avoid base64 encoding, or do it manually.
7
+ require 'vpim/vcard'
8
+
9
+ # Create a new 2.1 vCard.
10
+ card21 = Vpim::DirectoryInfo.create(
11
+ [
12
+ Vpim::DirectoryInfo::Field.create('VERSION', '2.1')
13
+ ], 'VCARD')
14
+
15
+ Vpim::Vcard::Maker.make2(card21) do |maker|
16
+ maker.name do |n|
17
+ n.prefix = 'Dr.'
18
+ n.given = 'Jimmy'
19
+ n.family = 'Death'
20
+ end
21
+
22
+ end
23
+
24
+ puts card21
25
+
26
+ # Copy and modify a 2.1 vCard, preserving it's version.
27
+ mod21 = Vpim::Vcard::Maker.make2(Vpim::DirectoryInfo.create([], 'VCARD')) do |maker|
28
+ maker.copy card21
29
+ maker.nickname = 'some name'
30
+ end
31
+
32
+ puts '---'
33
+ puts mod21
34
+
@@ -0,0 +1,64 @@
1
+ require 'vpim/vcard'
2
+
3
+ card = Vpim::Vcard::Maker.make2 do |maker|
4
+ maker.add_name do |name|
5
+ name.prefix = 'Dr.'
6
+ name.given = 'Jimmy'
7
+ name.family = 'Death'
8
+ end
9
+
10
+ maker.add_addr do |addr|
11
+ addr.preferred = true
12
+ addr.location = 'work'
13
+ addr.street = '12 Last Row, 13th Section'
14
+ addr.locality = 'City of Lost Children'
15
+ addr.country = 'Cinema'
16
+ end
17
+
18
+ maker.add_addr do |addr|
19
+ addr.location = [ 'home', 'zoo' ]
20
+ addr.delivery = [ 'snail', 'stork', 'camel' ]
21
+ addr.street = '12 Last Row, 13th Section'
22
+ addr.locality = 'City of Lost Children'
23
+ addr.country = 'Cinema'
24
+ end
25
+
26
+ maker.nickname = "The Good Doctor"
27
+
28
+ maker.birthday = Date.today
29
+
30
+ maker.add_photo do |photo|
31
+ photo.link = 'http://example.com/image.png'
32
+ end
33
+
34
+ maker.add_photo do |photo|
35
+ photo.image = "File.open('drdeath.jpg').read # a fake string, real data is too large :-)"
36
+ photo.type = 'jpeg'
37
+ end
38
+
39
+ maker.add_tel('416 123 1111')
40
+
41
+ maker.add_tel('416 123 2222') { |t| t.location = 'home'; t.preferred = true }
42
+
43
+ maker.add_impp('joe') do |impp|
44
+ impp.preferred = 'yes'
45
+ impp.location = 'mobile'
46
+ end
47
+
48
+ maker.add_x_aim('example') do |xaim|
49
+ xaim.location = 'row12'
50
+ end
51
+
52
+ maker.add_tel('416-123-3333') do |tel|
53
+ tel.location = 'work'
54
+ tel.capability = 'fax'
55
+ end
56
+
57
+ maker.add_email('drdeath@work.com') { |e| e.location = 'work' }
58
+
59
+ maker.add_email('drdeath@home.net') { |e| e.preferred = 'yes' }
60
+
61
+ end
62
+
63
+ puts card
64
+
@@ -0,0 +1,29 @@
1
+ require 'vpim/vcard'
2
+
3
+ module Vpim
4
+ class Vcard
5
+ class Maker
6
+ # Add a user-defined field, X-MY-OWN:.
7
+ #
8
+ # This can be done both to encode custom fields, or to add support for
9
+ # fields that Vcard::Maker doesn't support. In the latter case, please
10
+ # submit your methods so I can add them to vPim.
11
+ def add_my_own(value)
12
+ @card << Vpim::DirectoryInfo::Field.create( 'X-MY-OWN', value.to_str );
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+
19
+ card = Vpim::Vcard.create # ... or load from somewhere
20
+
21
+ Vpim::Vcard::Maker.make2(card) do |m|
22
+ m.add_name do |n|
23
+ n.given = 'Given'
24
+ end
25
+ m.add_my_own 'my value'
26
+ end
27
+
28
+ puts card
29
+
@@ -0,0 +1,210 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Calendars are in ~/Library/Calendars/
4
+
5
+ $-w = true
6
+ $:.unshift File.dirname($0) + '/../lib'
7
+
8
+ require 'getoptlong'
9
+ require 'pp'
10
+ require 'open-uri'
11
+
12
+ require 'vpim/icalendar'
13
+ require 'vpim/duration'
14
+
15
+ include Vpim
16
+
17
+ HELP =<<EOF
18
+ Usage: #{$0} <vcard>...
19
+
20
+ Options
21
+ -h,--help Print this helpful message.
22
+ -n,--node Dump as nodes.
23
+ -d,--debug Print debug information.
24
+ -m,--metro Convert metro.
25
+
26
+ Examples:
27
+ EOF
28
+
29
+ opt_debug = nil
30
+ opt_node = false
31
+
32
+ opts = GetoptLong.new(
33
+ [ "--help", "-h", GetoptLong::NO_ARGUMENT ],
34
+ [ "--node", "-n", GetoptLong::NO_ARGUMENT ],
35
+ [ "--debug", "-d", GetoptLong::NO_ARGUMENT ]
36
+ )
37
+
38
+ opts.each do |opt, arg|
39
+ case opt
40
+ when "--help" then
41
+ puts HELP
42
+ exit 0
43
+
44
+ when "--node" then
45
+ opt_node = true
46
+
47
+ when "--debug" then
48
+ opt_debug = true
49
+ end
50
+ end
51
+
52
+ if ARGV.length < 1
53
+ puts "no input files specified, try -h!\n"
54
+ exit 1
55
+ end
56
+
57
+ if opt_node
58
+
59
+ ARGV.each do |file|
60
+ tree = Vpim.expand(Vpim.decode(File.open(file).read(nil)))
61
+ pp tree
62
+ end
63
+
64
+ exit 0
65
+ end
66
+
67
+ def v2s(v)
68
+ case v
69
+ when Vpim::Icalendar::Attachment
70
+ if v.binary
71
+ "#{v.format.inspect} binary #{v.binary.inspect}"
72
+ else
73
+ s = "#{v.format.inspect} uri #{v.uri.inspect}"
74
+ begin
75
+ s << " #{v.value.gets.inspect}..."
76
+ rescue
77
+ s << " (#{$!.class})"
78
+ end
79
+ end
80
+ else
81
+ v #.inspect
82
+ end
83
+ end
84
+
85
+
86
+ def puts_properties(c)
87
+ [
88
+ :access_class,
89
+ :attachments,
90
+ :categories,
91
+ :comments,
92
+ :completed,
93
+ :contacts,
94
+ :created,
95
+ :description,
96
+ :dtend,
97
+ :dtstamp,
98
+ :dtstart,
99
+ :due,
100
+ :geo,
101
+ :location,
102
+ :organizer,
103
+ :percent_complete,
104
+ :priority,
105
+ :sequence,
106
+ :status,
107
+ :summary,
108
+ :transparency,
109
+ :uid,
110
+ :url,
111
+ ].each do |m|
112
+ if c.respond_to? m
113
+ v = c.send(m)
114
+ case v
115
+ when Array
116
+ v.each_with_index do |v,i|
117
+ puts " #{m}[#{i}]=<#{v2s v}>"
118
+ end
119
+ else
120
+ if v
121
+ puts " #{m}=<#{v2s v}>"
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ begin
128
+ if c.duration; puts " duration=#{Duration.secs(c.duration).to_s}"; end
129
+ rescue NoMethodError
130
+ end
131
+
132
+ c.attendees.each_with_index do |a,i|
133
+ puts " attendee[#{i}]=#{a.to_s}"
134
+ puts " role=#{a.role.upcase} participation-status=#{a.partstat.upcase} rsvp?=#{a.rsvp ? 'yes' : 'no'}"
135
+ end
136
+
137
+ [
138
+ 'RRULE',
139
+ 'RDATE',
140
+ 'EXRULE',
141
+ 'EXDATE',
142
+ ].each do |m|
143
+ c.propvaluearray(m).each_with_index do |v,i|
144
+ puts " #{m}[#{i}]=<#{v.to_s}>"
145
+
146
+ case
147
+ when i == 1 && m != 'RRULE'
148
+ # Anything that isn't an RRULE isn't supported at all.
149
+ puts " ==> #{m} is unsupported!"
150
+ when i == 2 && m == 'RRULE'
151
+ # If there was more than 1 RRULE, its not supported.
152
+ puts " ==> More than one RRULE is unsupported!"
153
+ end
154
+ end
155
+ end
156
+
157
+ begin
158
+ c.occurrences.each_with_index do |t, i|
159
+ if(i < 10)
160
+ puts " #{i+1} -> #{t}"
161
+ else
162
+ puts " ..."
163
+ break;
164
+ end
165
+ end
166
+ rescue ArgumentError
167
+ # No occurrences.
168
+ end
169
+
170
+ end
171
+
172
+ ARGV.each do |file|
173
+ puts "===> ", file
174
+ cals = Vpim::Icalendar.decode(
175
+ (file == "-") ? $stdin : open(file)
176
+ )
177
+
178
+ cals.each_with_index do |cal, i|
179
+ if i > 0
180
+ puts
181
+ end
182
+
183
+ puts "Icalendar[#{i}]:"
184
+ puts " version=#{cal.version/10.0}"
185
+ puts " producer=#{cal.producer}"
186
+
187
+ if cal.protocol; puts " protocol=#{cal.protocol}"; end
188
+
189
+ events = cal.events
190
+
191
+ cal.components.each_with_index do |c, i|
192
+ puts " #{c.class.to_s.sub(/.*::/,'')}[#{i}]:"
193
+
194
+ begin
195
+ puts_properties(c)
196
+ rescue => e
197
+ cb = e.backtrace
198
+ pp e
199
+ print cb.shift, ":", e.message, " (", e.class, ")\n"
200
+ cb.each{|c| print "\tfrom ", c, "\n"}
201
+ exit 1
202
+ end
203
+ end
204
+
205
+ if opt_debug
206
+ pp cals
207
+ end
208
+ end
209
+ end
210
+
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Call with --print to print RSS to stdout, otherwise it runs as a WEBrick
4
+ # servelet on port 8080.
5
+ #
6
+ # This comes from an idea of Dave Thomas' that he described here:
7
+ #
8
+ # http://pragprog.com/pragdave/Tech/Blog/ToDos.rdoc
9
+ #
10
+ # He generously sent me his code, and I reimplemented it with vPim and rss/maker.
11
+ #
12
+ # RSS Content-Types:
13
+ #
14
+ # RSS 1.0 -> application/rdf+xml
15
+ # RSS 2.0 -> text/xml
16
+ # RSS 0.9 -> text/xml
17
+ # ATOM -> application/xml
18
+
19
+ require 'rss/maker'
20
+ require 'vpim/icalendar'
21
+
22
+ class IcalToRss
23
+ def initialize(calendars, title, link, language = 'en-us')
24
+ @rss = RSS::Maker.make("0.9") do |maker|
25
+ maker.channel.title = title
26
+ maker.channel.link = link
27
+ maker.channel.description = title
28
+ maker.channel.language = language
29
+
30
+ # These are required, or RSS::Maker silently returns nil!
31
+ maker.image.url = "maker.image.url"
32
+ maker.image.title = "maker.image.title"
33
+
34
+ calendars.each do |file|
35
+ Vpim::Icalendar.decode(File.open(file)).each do |cal|
36
+ cal.todos.each do |todo|
37
+ if !todo.status || todo.status.upcase != "COMPLETED"
38
+ item = maker.items.new_item
39
+ item.title = todo.summary
40
+ item.link = todo.properties['url'] || link
41
+ item.description = todo.description || todo.summary
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ def to_rss
50
+ @rss.to_s
51
+ end
52
+ end
53
+
54
+ TITLE = "Sam's ToDo List"
55
+ LINK = "http://ensemble.local/~sam"
56
+
57
+ if ARGV[0] == "--print"
58
+
59
+ puts IcalToRss.new( Dir[ "/Users/sam/Library/Calendars/*.ics" ], TITLE, LINK ).to_rss
60
+
61
+ else
62
+
63
+ require 'webrick'
64
+
65
+ class IcalRssTodoServlet < WEBrick::HTTPServlet::AbstractServlet
66
+ def do_GET(req, resp)
67
+ resp.body = IcalToRss.new( Dir[ "/Users/sam/Library/Calendars/*.ics" ], TITLE, LINK ).to_rss
68
+ resp['content-type'] = 'text/xml'
69
+ raise WEBrick::HTTPStatus::OK
70
+ end
71
+ end
72
+
73
+ server = WEBrick::HTTPServer.new( :Port => 8080 )
74
+
75
+ server.mount( '/', IcalRssTodoServlet )
76
+
77
+ ['INT', 'TERM'].each { |signal|
78
+ trap(signal) { server.shutdown }
79
+ }
80
+
81
+ server.start
82
+
83
+ end
84
+
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $-w = true
4
+ $:.unshift File.dirname($0) + '/../lib'
5
+
6
+ require 'vpim/vcard'
7
+
8
+ ARGV.each do |file|
9
+
10
+ File.open(file).each do |line|
11
+
12
+ if line =~ /\s*alias\s+(\w+)\s+(.*)/
13
+ nick = $1
14
+ rhs = $2
15
+ email = nil
16
+ name = nil
17
+
18
+ case rhs
19
+ when /(.*)<(.*)>/
20
+ email = $2
21
+ name = $1
22
+ else
23
+ email = rhs
24
+ name = nick
25
+ nick = nil
26
+ end
27
+
28
+ card = Vpim::Vcard::Maker.make2 do |maker|
29
+ # don't have the broken-down name, we'll have to leave it blank
30
+ maker.name { |n| n.fullname = name }
31
+
32
+ # Set preferred, its the only one...
33
+ maker.add_email( email ) { |e| e.preferred = true }
34
+
35
+ maker.nickname = nick if nick
36
+
37
+ # mark as auto-generated, it makes it easier to see them
38
+ maker.add_field( Vpim::DirectoryInfo::Field.create('note', "auto-generated-from-mutt-aliases") )
39
+ end
40
+
41
+ puts card.to_s
42
+ end
43
+ end
44
+ end
45
+