vpim2 0.0.1

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 (61) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +504 -0
  3. data/COPYING +58 -0
  4. data/README +182 -0
  5. data/lib/atom.rb +728 -0
  6. data/lib/plist.rb +22 -0
  7. data/lib/vpim.rb +13 -0
  8. data/lib/vpim/address.rb +219 -0
  9. data/lib/vpim/attachment.rb +102 -0
  10. data/lib/vpim/date.rb +222 -0
  11. data/lib/vpim/dirinfo.rb +277 -0
  12. data/lib/vpim/duration.rb +119 -0
  13. data/lib/vpim/enumerator.rb +32 -0
  14. data/lib/vpim/field.rb +614 -0
  15. data/lib/vpim/icalendar.rb +381 -0
  16. data/lib/vpim/maker/vcard.rb +16 -0
  17. data/lib/vpim/property/base.rb +193 -0
  18. data/lib/vpim/property/common.rb +315 -0
  19. data/lib/vpim/property/location.rb +38 -0
  20. data/lib/vpim/property/priority.rb +43 -0
  21. data/lib/vpim/property/recurrence.rb +69 -0
  22. data/lib/vpim/property/resources.rb +24 -0
  23. data/lib/vpim/repo.rb +181 -0
  24. data/lib/vpim/rfc2425.rb +367 -0
  25. data/lib/vpim/rrule.rb +591 -0
  26. data/lib/vpim/vcard.rb +1430 -0
  27. data/lib/vpim/version.rb +18 -0
  28. data/lib/vpim/vevent.rb +187 -0
  29. data/lib/vpim/view.rb +90 -0
  30. data/lib/vpim/vjournal.rb +58 -0
  31. data/lib/vpim/vpim.rb +65 -0
  32. data/lib/vpim/vtodo.rb +103 -0
  33. data/samples/README.mutt +93 -0
  34. data/samples/ab-query.rb +57 -0
  35. data/samples/cmd-itip.rb +156 -0
  36. data/samples/ex_cpvcard.rb +55 -0
  37. data/samples/ex_get_vcard_photo.rb +22 -0
  38. data/samples/ex_mkv21vcard.rb +34 -0
  39. data/samples/ex_mkvcard.rb +64 -0
  40. data/samples/ex_mkyourown.rb +29 -0
  41. data/samples/ics-dump.rb +210 -0
  42. data/samples/ics-to-rss.rb +84 -0
  43. data/samples/mutt-aliases-to-vcf.rb +45 -0
  44. data/samples/osx-wrappers.rb +86 -0
  45. data/samples/reminder.rb +203 -0
  46. data/samples/rrule.rb +71 -0
  47. data/samples/tabbed-file-to-vcf.rb +390 -0
  48. data/samples/vcf-dump.rb +86 -0
  49. data/samples/vcf-lines.rb +61 -0
  50. data/samples/vcf-to-ics.rb +22 -0
  51. data/samples/vcf-to-mutt.rb +121 -0
  52. data/test/test_all.rb +17 -0
  53. data/test/test_date.rb +120 -0
  54. data/test/test_dur.rb +41 -0
  55. data/test/test_field.rb +156 -0
  56. data/test/test_ical.rb +415 -0
  57. data/test/test_repo.rb +158 -0
  58. data/test/test_rrule.rb +1030 -0
  59. data/test/test_vcard.rb +973 -0
  60. data/test/test_view.rb +79 -0
  61. metadata +117 -0
@@ -0,0 +1,93 @@
1
+
2
+ ** cmd-itip.rb
3
+
4
+ This script pretty-prints iTIP calendar invitations, often sent by email using iMIP
5
+ as text/calendar objects.
6
+
7
+ Download the latest vPim from:
8
+
9
+ http://rubyforge.org/projects/vpim/
10
+
11
+ It requires Ruby to be installed.
12
+
13
+ Install vpim:
14
+
15
+ tar -xzf vpim-XX.tgz
16
+ cd vpim-XX
17
+ ruby install.rb config
18
+ ruby install.rb setup
19
+ sudo ruby install.rb install
20
+
21
+ Install cmd-itip.rb into your path, perhaps without the extension.
22
+
23
+ cp samples/cmd-itip.rb ~/bin/cmd-itip
24
+ chmod +x ~/bin/cmd-itip
25
+
26
+ Modify your ~/.mailcap or /etc/mailcap files to call cmd-itip, add a line like:
27
+
28
+ text/calendar; cmd-itip --myaddr "sroberts@" %s; copiousoutput
29
+
30
+ If you give a REGEX to --myaddr to tell cmd-itip your email addresses, cmd-itip
31
+ will avoid printing some information on the attendees to an invitation.
32
+
33
+ Modify muttrc to autoview calendars with a command like:
34
+
35
+ auto_view text/calendar
36
+
37
+ Notes on Notes;
38
+
39
+ Because Domino sends a close-to-unreadable text/plain attachment along with the
40
+ text/calendar in a multipart/alternative, and the text/plain is first in the
41
+ alternatives, the garbage will be at the top, and the nicely printed calendar
42
+ at the bottom. Because of this, I reorder the view preference so the calendar
43
+ invitation is clearly printed at the top of the message with a muttrc command
44
+ like:
45
+
46
+ alternative_order text/calendar text/plain
47
+
48
+ Domino also includes the calendar twice in the mail message, so you'll see it
49
+ twice, I don't know what to do about that.
50
+
51
+ Notes on application/octet-stream:
52
+
53
+ Some calendar programs, such as Apple's Mail.app, wrongly send iCalendar attachments
54
+ with a content-type of application/octet-stream. In order to be processed correctly, use
55
+ the mutt 1.5 or later capability to lookup the correct MIME content-type based on the
56
+ file extension. Put this in your muttrc file:
57
+
58
+ mime_lookup application/octet-stream
59
+
60
+ and ensure /etc/mime.types or ~/.mime.types contains:
61
+
62
+ text/calendar ics
63
+
64
+
65
+
66
+ ** vcf-to-mutt.rb
67
+
68
+ This script searches a set of vCards can output the results as a Mutt query response,
69
+ or a Mutt aliases file.
70
+
71
+ It used to support querying the OS X Address Book, but that is better done with lbdb, see
72
+ http://www.spinnaker.de/lbdb/.
73
+
74
+ To install, you must:
75
+
76
+ 1 - install vPim (see README)
77
+
78
+ 3 - copy vcf-to-mutt into a directory in your path, such
79
+ as ~/bin, and chmod +x vcf-to-mutt.rb to make it executable.
80
+
81
+ 4 - Put in your muttrc file (either ~/.muttrc or ~/.mutt/muttrc) a line such as:
82
+
83
+ set query_command = "vcf-to-mutt.rb '%s'"
84
+
85
+ 5 - The query command ("Q") will query the address book, control-t will give you auto-completion
86
+ of email addresses, see the Mutt manual page.
87
+
88
+
89
+ ** mutt-aliases-to-vcf.rb
90
+
91
+ This script converts a mutt aliases file into a vCard file.
92
+
93
+
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $-w = true
4
+ $:.unshift File.dirname($0) + '/../lib'
5
+
6
+ require 'osx-wrappers'
7
+
8
+ require 'getoptlong'
9
+ require 'vpim/vcard'
10
+ require 'osx-wrappers'
11
+
12
+ HELP =<<EOF
13
+ Usage: ab-query.rb [--me] [--all]
14
+
15
+ Queries the OS X Address Book for vCards.
16
+
17
+ -h, --help print this helpful message
18
+ -m, --me list my vCard
19
+ -a, --all list all vCards
20
+ EOF
21
+
22
+ opts = GetoptLong.new(
23
+ [ "--help", "-h", GetoptLong::NO_ARGUMENT ],
24
+ [ "--me", "-m", GetoptLong::NO_ARGUMENT ],
25
+ [ "--all", "-a", GetoptLong::NO_ARGUMENT ]
26
+ )
27
+
28
+ abook = nil
29
+
30
+ opts.each do |opt, arg|
31
+ case opt
32
+ when "--help" then
33
+ puts HELP
34
+ exit 0
35
+
36
+ when "--all" then
37
+ abook = OSX::ABAddressBook.sharedAddressBook unless abook
38
+
39
+ abook.people.to_a.each {
40
+ |person|
41
+
42
+ puts person.vCard
43
+ }
44
+
45
+ when "--me" then
46
+ abook = OSX::ABAddressBook.sharedAddressBook unless abook
47
+
48
+ puts abook.me.vCard
49
+ end
50
+ end
51
+
52
+
53
+ unless abook
54
+ puts HELP
55
+ exit 1
56
+ end
57
+
@@ -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
+