xing-vpim 0.658.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/CHANGES +504 -0
  2. data/COPYING +58 -0
  3. data/README +182 -0
  4. data/bin/reminder +203 -0
  5. data/bin/rrule +71 -0
  6. data/lib/atom.rb +728 -0
  7. data/lib/atom/pub.rb +206 -0
  8. data/lib/atom/version.rb +9 -0
  9. data/lib/atom/xml/parser.rb +305 -0
  10. data/lib/plist.rb +22 -0
  11. data/lib/plist/generator.rb +224 -0
  12. data/lib/plist/parser.rb +225 -0
  13. data/lib/vpim.rb +13 -0
  14. data/lib/vpim/address.rb +219 -0
  15. data/lib/vpim/attachment.rb +102 -0
  16. data/lib/vpim/date.rb +222 -0
  17. data/lib/vpim/dirinfo.rb +277 -0
  18. data/lib/vpim/duration.rb +119 -0
  19. data/lib/vpim/enumerator.rb +32 -0
  20. data/lib/vpim/field.rb +614 -0
  21. data/lib/vpim/icalendar.rb +381 -0
  22. data/lib/vpim/maker/vcard.rb +16 -0
  23. data/lib/vpim/property/base.rb +193 -0
  24. data/lib/vpim/property/common.rb +315 -0
  25. data/lib/vpim/property/location.rb +49 -0
  26. data/lib/vpim/property/priority.rb +43 -0
  27. data/lib/vpim/property/recurrence.rb +69 -0
  28. data/lib/vpim/property/resources.rb +24 -0
  29. data/lib/vpim/repo.rb +181 -0
  30. data/lib/vpim/rfc2425.rb +367 -0
  31. data/lib/vpim/rrule.rb +591 -0
  32. data/lib/vpim/time.rb +40 -0
  33. data/lib/vpim/vcard.rb +1429 -0
  34. data/lib/vpim/version.rb +18 -0
  35. data/lib/vpim/vevent.rb +188 -0
  36. data/lib/vpim/view.rb +90 -0
  37. data/lib/vpim/vjournal.rb +58 -0
  38. data/lib/vpim/vpim.rb +65 -0
  39. data/lib/vpim/vtodo.rb +103 -0
  40. data/samples/README.mutt +93 -0
  41. data/samples/ab-query.rb +57 -0
  42. data/samples/cmd-itip.rb +156 -0
  43. data/samples/ex_cpvcard.rb +55 -0
  44. data/samples/ex_get_vcard_photo.rb +22 -0
  45. data/samples/ex_mkv21vcard.rb +34 -0
  46. data/samples/ex_mkvcard.rb +64 -0
  47. data/samples/ex_mkyourown.rb +29 -0
  48. data/samples/ics-dump.rb +210 -0
  49. data/samples/ics-to-rss.rb +84 -0
  50. data/samples/mutt-aliases-to-vcf.rb +45 -0
  51. data/samples/osx-wrappers.rb +86 -0
  52. data/samples/reminder.rb +203 -0
  53. data/samples/rrule.rb +71 -0
  54. data/samples/tabbed-file-to-vcf.rb +390 -0
  55. data/samples/vcf-dump.rb +86 -0
  56. data/samples/vcf-lines.rb +61 -0
  57. data/samples/vcf-to-ics.rb +22 -0
  58. data/samples/vcf-to-mutt.rb +121 -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 +415 -0
  64. data/test/test_repo.rb +158 -0
  65. data/test/test_rrule.rb +1030 -0
  66. data/test/test_vcard.rb +973 -0
  67. data/test/test_view.rb +79 -0
  68. metadata +132 -0
data/lib/plist.rb ADDED
@@ -0,0 +1,22 @@
1
+ #--
2
+ ##############################################################
3
+ # Copyright 2006, Ben Bleything <ben@bleything.net> and #
4
+ # Patrick May <patrick@hexane.org> #
5
+ # #
6
+ # Distributed under the MIT license. #
7
+ ##############################################################
8
+ #++
9
+ # = Plist
10
+ #
11
+ # This is the main file for plist. Everything interesting happens in Plist and Plist::Emit.
12
+
13
+ require 'base64'
14
+ require 'cgi'
15
+ require 'stringio'
16
+
17
+ require 'plist/generator'
18
+ require 'plist/parser'
19
+
20
+ module Plist
21
+ VERSION = '3.0.0'
22
+ end
@@ -0,0 +1,224 @@
1
+ #--###########################################################
2
+ # Copyright 2006, Ben Bleything <ben@bleything.net> and #
3
+ # Patrick May <patrick@hexane.org> #
4
+ # #
5
+ # Distributed under the MIT license. #
6
+ ##############################################################
7
+ #++
8
+ # See Plist::Emit.
9
+ module Plist
10
+ # === Create a plist
11
+ # You can dump an object to a plist in one of two ways:
12
+ #
13
+ # * <tt>Plist::Emit.dump(obj)</tt>
14
+ # * <tt>obj.to_plist</tt>
15
+ # * This requires that you mixin the <tt>Plist::Emit</tt> module, which is already done for +Array+ and +Hash+.
16
+ #
17
+ # The following Ruby classes are converted into native plist types:
18
+ # Array, Bignum, Date, DateTime, Fixnum, Float, Hash, Integer, String, Symbol, Time, true, false
19
+ # * +Array+ and +Hash+ are both recursive; their elements will be converted into plist nodes inside the <array> and <dict> containers (respectively).
20
+ # * +IO+ (and its descendants) and +StringIO+ objects are read from and their contents placed in a <data> element.
21
+ # * User classes may implement +to_plist_node+ to dictate how they should be serialized; otherwise the object will be passed to <tt>Marshal.dump</tt> and the result placed in a <data> element.
22
+ #
23
+ # For detailed usage instructions, refer to USAGE[link:files/docs/USAGE.html] and the methods documented below.
24
+ module Emit
25
+ # Helper method for injecting into classes. Calls <tt>Plist::Emit.dump</tt> with +self+.
26
+ def to_plist(envelope = true)
27
+ return Plist::Emit.dump(self, envelope)
28
+ end
29
+
30
+ # Helper method for injecting into classes. Calls <tt>Plist::Emit.save_plist</tt> with +self+.
31
+ def save_plist(filename)
32
+ Plist::Emit.save_plist(self, filename)
33
+ end
34
+
35
+ # The following Ruby classes are converted into native plist types:
36
+ # Array, Bignum, Date, DateTime, Fixnum, Float, Hash, Integer, String, Symbol, Time
37
+ #
38
+ # Write us (via RubyForge) if you think another class can be coerced safely into one of the expected plist classes.
39
+ #
40
+ # +IO+ and +StringIO+ objects are encoded and placed in <data> elements; other objects are <tt>Marshal.dump</tt>'ed unless they implement +to_plist_node+.
41
+ #
42
+ # The +envelope+ parameters dictates whether or not the resultant plist fragment is wrapped in the normal XML/plist header and footer. Set it to false if you only want the fragment.
43
+ def self.dump(obj, envelope = true)
44
+ output = plist_node(obj)
45
+
46
+ output = wrap(output) if envelope
47
+
48
+ return output
49
+ end
50
+
51
+ # Writes the serialized object's plist to the specified filename.
52
+ def self.save_plist(obj, filename)
53
+ File.open(filename, 'wb') do |f|
54
+ f.write(obj.to_plist)
55
+ end
56
+ end
57
+
58
+ private
59
+ def self.plist_node(element)
60
+ output = ''
61
+
62
+ if element.respond_to? :to_plist_node
63
+ output << element.to_plist_node
64
+ else
65
+ case element
66
+ when Array
67
+ if element.empty?
68
+ output << "<array/>\n"
69
+ else
70
+ output << tag('array') {
71
+ element.collect {|e| plist_node(e)}
72
+ }
73
+ end
74
+ when Hash
75
+ if element.empty?
76
+ output << "<dict/>\n"
77
+ else
78
+ inner_tags = []
79
+
80
+ element.keys.sort.each do |k|
81
+ v = element[k]
82
+ inner_tags << tag('key', CGI::escapeHTML(k.to_s))
83
+ inner_tags << plist_node(v)
84
+ end
85
+
86
+ output << tag('dict') {
87
+ inner_tags
88
+ }
89
+ end
90
+ when true, false
91
+ output << "<#{element}/>\n"
92
+ when Time
93
+ output << tag('date', element.utc.strftime('%Y-%m-%dT%H:%M:%SZ'))
94
+ when Date # also catches DateTime
95
+ output << tag('date', element.strftime('%Y-%m-%dT%H:%M:%SZ'))
96
+ when String, Symbol, Fixnum, Bignum, Integer, Float
97
+ output << tag(element_type(element), CGI::escapeHTML(element.to_s))
98
+ when IO, StringIO
99
+ element.rewind
100
+ contents = element.read
101
+ # note that apple plists are wrapped at a different length then
102
+ # what ruby's base64 wraps by default.
103
+ # I used #encode64 instead of #b64encode (which allows a length arg)
104
+ # because b64encode is b0rked and ignores the length arg.
105
+ data = "\n"
106
+ Base64::encode64(contents).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" }
107
+ output << tag('data', data)
108
+ else
109
+ output << comment( 'The <data> element below contains a Ruby object which has been serialized with Marshal.dump.' )
110
+ data = "\n"
111
+ Base64::encode64(Marshal.dump(element)).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" }
112
+ output << tag('data', data )
113
+ end
114
+ end
115
+
116
+ return output
117
+ end
118
+
119
+ def self.comment(content)
120
+ return "<!-- #{content} -->\n"
121
+ end
122
+
123
+ def self.tag(type, contents = '', &block)
124
+ out = nil
125
+
126
+ if block_given?
127
+ out = IndentedString.new
128
+ out << "<#{type}>"
129
+ out.raise_indent
130
+
131
+ out << block.call
132
+
133
+ out.lower_indent
134
+ out << "</#{type}>"
135
+ else
136
+ out = "<#{type}>#{contents.to_s}</#{type}>\n"
137
+ end
138
+
139
+ return out.to_s
140
+ end
141
+
142
+ def self.wrap(contents)
143
+ output = ''
144
+
145
+ output << '<?xml version="1.0" encoding="UTF-8"?>' + "\n"
146
+ output << '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' + "\n"
147
+ output << '<plist version="1.0">' + "\n"
148
+
149
+ output << contents
150
+
151
+ output << '</plist>' + "\n"
152
+
153
+ return output
154
+ end
155
+
156
+ def self.element_type(item)
157
+ return case item
158
+ when String, Symbol: 'string'
159
+ when Fixnum, Bignum, Integer: 'integer'
160
+ when Float: 'real'
161
+ else
162
+ raise "Don't know about this data type... something must be wrong!"
163
+ end
164
+ end
165
+ private
166
+ class IndentedString #:nodoc:
167
+ attr_accessor :indent_string
168
+
169
+ @@indent_level = 0
170
+
171
+ def initialize(str = "\t")
172
+ @indent_string = str
173
+ @contents = ''
174
+ end
175
+
176
+ def to_s
177
+ return @contents
178
+ end
179
+
180
+ def raise_indent
181
+ @@indent_level += 1
182
+ end
183
+
184
+ def lower_indent
185
+ @@indent_level -= 1 if @@indent_level > 0
186
+ end
187
+
188
+ def <<(val)
189
+ if val.is_a? Array
190
+ val.each do |f|
191
+ self << f
192
+ end
193
+ else
194
+ # if it's already indented, don't bother indenting further
195
+ unless val =~ /\A#{@indent_string}/
196
+ indent = @indent_string * @@indent_level
197
+
198
+ @contents << val.gsub(/^/, indent)
199
+ else
200
+ @contents << val
201
+ end
202
+
203
+ # it already has a newline, don't add another
204
+ @contents << "\n" unless val =~ /\n$/
205
+ end
206
+ end
207
+ end
208
+ end
209
+ end
210
+
211
+ # we need to add this so sorting hash keys works properly
212
+ class Symbol #:nodoc:
213
+ def <=> (other)
214
+ self.to_s <=> other.to_s
215
+ end
216
+ end
217
+
218
+ class Array #:nodoc:
219
+ include Plist::Emit
220
+ end
221
+
222
+ class Hash #:nodoc:
223
+ include Plist::Emit
224
+ end
@@ -0,0 +1,225 @@
1
+ #--###########################################################
2
+ # Copyright 2006, Ben Bleything <ben@bleything.net> and #
3
+ # Patrick May <patrick@hexane.org> #
4
+ # #
5
+ # Distributed under the MIT license. #
6
+ ##############################################################
7
+ #++
8
+ # Plist parses Mac OS X xml property list files into ruby data structures.
9
+ #
10
+ # === Load a plist file
11
+ # This is the main point of the library:
12
+ #
13
+ # r = Plist::parse_xml( filename_or_xml )
14
+ module Plist
15
+ # Note that I don't use these two elements much:
16
+ #
17
+ # + Date elements are returned as DateTime objects.
18
+ # + Data elements are implemented as Tempfiles
19
+ #
20
+ # Plist::parse_xml will blow up if it encounters a data element.
21
+ # If you encounter such an error, or if you have a Date element which
22
+ # can't be parsed into a Time object, please send your plist file to
23
+ # plist@hexane.org so that I can implement the proper support.
24
+ def Plist::parse_xml( filename_or_xml )
25
+ listener = Listener.new
26
+ #parser = REXML::Parsers::StreamParser.new(File.new(filename), listener)
27
+ parser = StreamParser.new(filename_or_xml, listener)
28
+ parser.parse
29
+ listener.result
30
+ end
31
+
32
+ class Listener
33
+ #include REXML::StreamListener
34
+
35
+ attr_accessor :result, :open
36
+
37
+ def initialize
38
+ @result = nil
39
+ @open = Array.new
40
+ end
41
+
42
+
43
+ def tag_start(name, attributes)
44
+ @open.push PTag::mappings[name].new
45
+ end
46
+
47
+ def text( contents )
48
+ @open.last.text = contents if @open.last
49
+ end
50
+
51
+ def tag_end(name)
52
+ last = @open.pop
53
+ if @open.empty?
54
+ @result = last.to_ruby
55
+ else
56
+ @open.last.children.push last
57
+ end
58
+ end
59
+ end
60
+
61
+ class StreamParser
62
+ def initialize( filename_or_xml, listener )
63
+ @filename_or_xml = filename_or_xml
64
+ @listener = listener
65
+ end
66
+
67
+ TEXT = /([^<]+)/
68
+ XMLDECL_PATTERN = /<\?xml\s+(.*?)\?>*/um
69
+ DOCTYPE_PATTERN = /\s*<!DOCTYPE\s+(.*?)(\[|>)/um
70
+ COMMENT_START = /\A<!--/u
71
+ COMMENT_END = /.*?-->/um
72
+
73
+
74
+ def parse
75
+ plist_tags = PTag::mappings.keys.join('|')
76
+ start_tag = /<(#{plist_tags})([^>]*)>/i
77
+ end_tag = /<\/(#{plist_tags})[^>]*>/i
78
+
79
+ require 'strscan'
80
+
81
+ contents = (
82
+ if (File.exists? @filename_or_xml)
83
+ File.open(@filename_or_xml) {|f| f.read}
84
+ else
85
+ @filename_or_xml
86
+ end
87
+ )
88
+
89
+ @scanner = StringScanner.new( contents )
90
+ until @scanner.eos?
91
+ if @scanner.scan(COMMENT_START)
92
+ @scanner.scan(COMMENT_END)
93
+ elsif @scanner.scan(XMLDECL_PATTERN)
94
+ elsif @scanner.scan(DOCTYPE_PATTERN)
95
+ elsif @scanner.scan(start_tag)
96
+ @listener.tag_start(@scanner[1], nil)
97
+ if (@scanner[2] =~ /\/$/)
98
+ @listener.tag_end(@scanner[1])
99
+ end
100
+ elsif @scanner.scan(TEXT)
101
+ @listener.text(@scanner[1])
102
+ elsif @scanner.scan(end_tag)
103
+ @listener.tag_end(@scanner[1])
104
+ else
105
+ raise "Unimplemented element"
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ class PTag
112
+ @@mappings = { }
113
+ def PTag::mappings
114
+ @@mappings
115
+ end
116
+
117
+ def PTag::inherited( sub_class )
118
+ key = sub_class.to_s.downcase
119
+ key.gsub!(/^plist::/, '' )
120
+ key.gsub!(/^p/, '') unless key == "plist"
121
+
122
+ @@mappings[key] = sub_class
123
+ end
124
+
125
+ attr_accessor :text, :children
126
+ def initialize
127
+ @children = Array.new
128
+ end
129
+
130
+ def to_ruby
131
+ raise "Unimplemented: " + self.class.to_s + "#to_ruby on #{self.inspect}"
132
+ end
133
+ end
134
+
135
+ class PList < PTag
136
+ def to_ruby
137
+ children.first.to_ruby if children.first
138
+ end
139
+ end
140
+
141
+ class PDict < PTag
142
+ def to_ruby
143
+ dict = Hash.new
144
+ key = nil
145
+
146
+ children.each do |c|
147
+ if key.nil?
148
+ key = c.to_ruby
149
+ else
150
+ dict[key] = c.to_ruby
151
+ key = nil
152
+ end
153
+ end
154
+
155
+ dict
156
+ end
157
+ end
158
+
159
+ class PKey < PTag
160
+ def to_ruby
161
+ CGI::unescapeHTML(text || '')
162
+ end
163
+ end
164
+
165
+ class PString < PTag
166
+ def to_ruby
167
+ CGI::unescapeHTML(text || '')
168
+ end
169
+ end
170
+
171
+ class PArray < PTag
172
+ def to_ruby
173
+ children.collect do |c|
174
+ c.to_ruby
175
+ end
176
+ end
177
+ end
178
+
179
+ class PInteger < PTag
180
+ def to_ruby
181
+ text.to_i
182
+ end
183
+ end
184
+
185
+ class PTrue < PTag
186
+ def to_ruby
187
+ true
188
+ end
189
+ end
190
+
191
+ class PFalse < PTag
192
+ def to_ruby
193
+ false
194
+ end
195
+ end
196
+
197
+ class PReal < PTag
198
+ def to_ruby
199
+ text.to_f
200
+ end
201
+ end
202
+
203
+ require 'date'
204
+ class PDate < PTag
205
+ def to_ruby
206
+ DateTime.parse(text)
207
+ end
208
+ end
209
+
210
+ require 'base64'
211
+ class PData < PTag
212
+ def to_ruby
213
+ data = Base64.decode64(text.gsub(/\s+/, ''))
214
+
215
+ begin
216
+ return Marshal.load(data)
217
+ rescue Exception => e
218
+ io = StringIO.new
219
+ io.write data
220
+ io.rewind
221
+ return io
222
+ end
223
+ end
224
+ end
225
+ end