vpim2 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+