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.
- checksums.yaml +7 -0
- data/CHANGES +504 -0
- data/COPYING +58 -0
- data/README +182 -0
- data/lib/atom.rb +728 -0
- data/lib/plist.rb +22 -0
- data/lib/vpim.rb +13 -0
- data/lib/vpim/address.rb +219 -0
- data/lib/vpim/attachment.rb +102 -0
- data/lib/vpim/date.rb +222 -0
- data/lib/vpim/dirinfo.rb +277 -0
- data/lib/vpim/duration.rb +119 -0
- data/lib/vpim/enumerator.rb +32 -0
- data/lib/vpim/field.rb +614 -0
- data/lib/vpim/icalendar.rb +381 -0
- data/lib/vpim/maker/vcard.rb +16 -0
- data/lib/vpim/property/base.rb +193 -0
- data/lib/vpim/property/common.rb +315 -0
- data/lib/vpim/property/location.rb +38 -0
- data/lib/vpim/property/priority.rb +43 -0
- data/lib/vpim/property/recurrence.rb +69 -0
- data/lib/vpim/property/resources.rb +24 -0
- data/lib/vpim/repo.rb +181 -0
- data/lib/vpim/rfc2425.rb +367 -0
- data/lib/vpim/rrule.rb +591 -0
- data/lib/vpim/vcard.rb +1430 -0
- data/lib/vpim/version.rb +18 -0
- data/lib/vpim/vevent.rb +187 -0
- data/lib/vpim/view.rb +90 -0
- data/lib/vpim/vjournal.rb +58 -0
- data/lib/vpim/vpim.rb +65 -0
- data/lib/vpim/vtodo.rb +103 -0
- data/samples/README.mutt +93 -0
- data/samples/ab-query.rb +57 -0
- data/samples/cmd-itip.rb +156 -0
- data/samples/ex_cpvcard.rb +55 -0
- data/samples/ex_get_vcard_photo.rb +22 -0
- data/samples/ex_mkv21vcard.rb +34 -0
- data/samples/ex_mkvcard.rb +64 -0
- data/samples/ex_mkyourown.rb +29 -0
- data/samples/ics-dump.rb +210 -0
- data/samples/ics-to-rss.rb +84 -0
- data/samples/mutt-aliases-to-vcf.rb +45 -0
- data/samples/osx-wrappers.rb +86 -0
- data/samples/reminder.rb +203 -0
- data/samples/rrule.rb +71 -0
- data/samples/tabbed-file-to-vcf.rb +390 -0
- data/samples/vcf-dump.rb +86 -0
- data/samples/vcf-lines.rb +61 -0
- data/samples/vcf-to-ics.rb +22 -0
- data/samples/vcf-to-mutt.rb +121 -0
- data/test/test_all.rb +17 -0
- data/test/test_date.rb +120 -0
- data/test/test_dur.rb +41 -0
- data/test/test_field.rb +156 -0
- data/test/test_ical.rb +415 -0
- data/test/test_repo.rb +158 -0
- data/test/test_rrule.rb +1030 -0
- data/test/test_vcard.rb +973 -0
- data/test/test_view.rb +79 -0
- metadata +117 -0
@@ -0,0 +1,315 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright (C) 2008 Sam Roberts
|
3
|
+
|
4
|
+
This library is free software; you can redistribute it and/or modify it
|
5
|
+
under the same terms as the ruby language itself, see the file COPYING for
|
6
|
+
details.
|
7
|
+
=end
|
8
|
+
|
9
|
+
require 'vpim/address'
|
10
|
+
require 'vpim/attachment'
|
11
|
+
|
12
|
+
module Vpim
|
13
|
+
class Icalendar
|
14
|
+
module Property
|
15
|
+
|
16
|
+
# Properties common to Vevent, Vtodo, and Vjournal.
|
17
|
+
module Common
|
18
|
+
|
19
|
+
# This property defines the access classification for a calendar
|
20
|
+
# component.
|
21
|
+
#
|
22
|
+
# An access classification is only one component of the general
|
23
|
+
# security system within a calendar application. It provides a method
|
24
|
+
# of capturing the scope of the access the calendar owner intends for
|
25
|
+
# information within an individual calendar entry. The access
|
26
|
+
# classification of an individual iCalendar component is useful when
|
27
|
+
# measured along with the other security components of a calendar
|
28
|
+
# system (e.g., calendar user authentication, authorization, access
|
29
|
+
# rights, access role, etc.). Hence, the semantics of the individual
|
30
|
+
# access classifications cannot be completely defined by this memo
|
31
|
+
# alone. Additionally, due to the "blind" nature of most exchange
|
32
|
+
# processes using this memo, these access classifications cannot serve
|
33
|
+
# as an enforcement statement for a system receiving an iCalendar
|
34
|
+
# object. Rather, they provide a method for capturing the intention of
|
35
|
+
# the calendar owner for the access to the calendar component.
|
36
|
+
#
|
37
|
+
# Property Name: CLASS
|
38
|
+
#
|
39
|
+
# Property Value: one of "PUBLIC", "PRIVATE", "CONFIDENTIAL", default
|
40
|
+
# is "PUBLIC" if no CLASS property is found.
|
41
|
+
def access_class
|
42
|
+
proptoken 'CLASS', ["PUBLIC", "PRIVATE", "CONFIDENTIAL"], "PUBLIC"
|
43
|
+
end
|
44
|
+
|
45
|
+
def created
|
46
|
+
proptime 'CREATED'
|
47
|
+
end
|
48
|
+
|
49
|
+
# Description of the calendar component, or nil if there is no
|
50
|
+
# description.
|
51
|
+
def description
|
52
|
+
proptext 'DESCRIPTION'
|
53
|
+
end
|
54
|
+
|
55
|
+
# Revision sequence number of the calendar component, or nil if there
|
56
|
+
# is no SEQUENCE; property.
|
57
|
+
def sequence
|
58
|
+
propinteger 'SEQUENCE'
|
59
|
+
end
|
60
|
+
|
61
|
+
# The time stamp for this calendar component.
|
62
|
+
def dtstamp
|
63
|
+
proptime 'DTSTAMP'
|
64
|
+
end
|
65
|
+
|
66
|
+
# The start time for this calendar component.
|
67
|
+
def dtstart
|
68
|
+
proptime 'DTSTART'
|
69
|
+
end
|
70
|
+
|
71
|
+
def lastmod
|
72
|
+
proptime 'LAST-MODIFIED'
|
73
|
+
end
|
74
|
+
|
75
|
+
# Return the event organizer, an object of Icalendar::Address (or nil if
|
76
|
+
# there is no ORGANIZER field).
|
77
|
+
def organizer
|
78
|
+
organizer = @properties.field('ORGANIZER')
|
79
|
+
|
80
|
+
if organizer
|
81
|
+
organizer = Icalendar::Address.decode(organizer)
|
82
|
+
end
|
83
|
+
|
84
|
+
organizer.freeze
|
85
|
+
end
|
86
|
+
|
87
|
+
=begin
|
88
|
+
recurid
|
89
|
+
seq
|
90
|
+
=end
|
91
|
+
|
92
|
+
# Status values are not rejected during decoding. However, if the
|
93
|
+
# status is requested, and it's value is not one of the defined
|
94
|
+
# allowable values, an exception is raised.
|
95
|
+
def status
|
96
|
+
case self
|
97
|
+
when Vpim::Icalendar::Vevent
|
98
|
+
proptoken 'STATUS', ['TENTATIVE', 'CONFIRMED', 'CANCELLED']
|
99
|
+
|
100
|
+
when Vpim::Icalendar::Vtodo
|
101
|
+
proptoken 'STATUS', ['NEEDS-ACTION', 'COMPLETED', 'IN-PROCESS', 'CANCELLED']
|
102
|
+
|
103
|
+
when Vpim::Icalendar::Vevent
|
104
|
+
proptoken 'STATUS', ['DRAFT', 'FINAL', 'CANCELLED']
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# TODO - def status? ...
|
109
|
+
|
110
|
+
# TODO - def status= ...
|
111
|
+
|
112
|
+
# Summary description of the calendar component, or nil if there is no
|
113
|
+
# SUMMARY property.
|
114
|
+
def summary
|
115
|
+
proptext 'SUMMARY'
|
116
|
+
end
|
117
|
+
|
118
|
+
# The unique identifier of this calendar component, a string.
|
119
|
+
def uid
|
120
|
+
proptext 'UID'
|
121
|
+
end
|
122
|
+
|
123
|
+
def url
|
124
|
+
propvalue 'URL'
|
125
|
+
end
|
126
|
+
|
127
|
+
# Return an array of attendees, an empty array if there are none. The
|
128
|
+
# attendees are objects of Icalendar::Address. If +uri+ is specified
|
129
|
+
# only the return the attendees with this +uri+.
|
130
|
+
def attendees(uri = nil)
|
131
|
+
attendees = @properties.enum_by_name('ATTENDEE').map { |a| Icalendar::Address.decode(a) }
|
132
|
+
attendees.freeze
|
133
|
+
if uri
|
134
|
+
attendees.select { |a| a == uri }
|
135
|
+
else
|
136
|
+
attendees
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Return true if the +uri+, usually a mailto: URI, is an attendee.
|
141
|
+
def attendee?(uri)
|
142
|
+
attendees.include? uri
|
143
|
+
end
|
144
|
+
|
145
|
+
# This property defines the categories for a calendar component.
|
146
|
+
#
|
147
|
+
# Property Name: CATEGORIES
|
148
|
+
#
|
149
|
+
# Value Type: TEXT
|
150
|
+
#
|
151
|
+
# Ruby Type: Array of String
|
152
|
+
#
|
153
|
+
# This property is used to specify categories or subtypes of the
|
154
|
+
# calendar component. The categories are useful in searching for a
|
155
|
+
# calendar component of a particular type and category.
|
156
|
+
def categories
|
157
|
+
proptextlistarray 'CATEGORIES'
|
158
|
+
end
|
159
|
+
|
160
|
+
def comments
|
161
|
+
proptextarray 'COMMENT'
|
162
|
+
end
|
163
|
+
|
164
|
+
def contacts
|
165
|
+
proptextarray 'CONTACT'
|
166
|
+
end
|
167
|
+
|
168
|
+
# An Array of attachments, see Attachment for more information.
|
169
|
+
def attachments
|
170
|
+
@properties.enum_by_name('ATTACH').map do |f|
|
171
|
+
attachment = Attachment.decode(f, 'uri', 'FMTTYPE')
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
module Set
|
179
|
+
|
180
|
+
# Properties common to Vevent, Vtodo, and Vjournal.
|
181
|
+
module Common
|
182
|
+
|
183
|
+
# Set the access class of the component, see Icalendar::Property::Common#access_class.
|
184
|
+
def access_class(token)
|
185
|
+
set_token 'CLASS', ["PUBLIC", "PRIVATE", "CONFIDENTIAL"], "PUBLIC", token
|
186
|
+
end
|
187
|
+
|
188
|
+
# Set the creation time, see Icalendar::Property::Common#created
|
189
|
+
def created(time)
|
190
|
+
set_datetime 'CREATED', time
|
191
|
+
end
|
192
|
+
|
193
|
+
# Set the description, see Icalendar::Property::Common#description.
|
194
|
+
def description(text)
|
195
|
+
set_text 'DESCRIPTION', text
|
196
|
+
end
|
197
|
+
|
198
|
+
# Set the sequence number, see Icalendar::Property::Common#sequence.
|
199
|
+
# is no SEQUENCE; property.
|
200
|
+
def sequence(int)
|
201
|
+
set_integer 'SEQUENCE', int
|
202
|
+
end
|
203
|
+
|
204
|
+
# Set the timestamp, see Icalendar::Property::Common#timestamp.
|
205
|
+
def dtstamp(time)
|
206
|
+
set_datetime 'DTSTAMP', time
|
207
|
+
self
|
208
|
+
end
|
209
|
+
|
210
|
+
# The start time or date, see Icalendar::Property::Common#dtstart.
|
211
|
+
def dtstart(start)
|
212
|
+
set_date_or_datetime 'DTSTART', 'DATE-TIME', start
|
213
|
+
self
|
214
|
+
end
|
215
|
+
|
216
|
+
# Set the last modification time, see Icalendar::Property::Common#lastmod.
|
217
|
+
def lastmod(time)
|
218
|
+
set_datetime 'LAST-MODIFIED', time
|
219
|
+
self
|
220
|
+
end
|
221
|
+
|
222
|
+
# Set the event organizer, an Icalendar::Address, see Icalendar::Property::Common#organizer.
|
223
|
+
#
|
224
|
+
# Without an +adr+ it yields an Icalendar::Address that is a copy of
|
225
|
+
# the current organizer (if any), allowing it to be modified.
|
226
|
+
def organizer(adr=nil) #:yield: organizer
|
227
|
+
unless adr
|
228
|
+
adr = @comp.organizer
|
229
|
+
if adr
|
230
|
+
adr = adr.copy
|
231
|
+
else
|
232
|
+
adr = Icalendar::Address.create
|
233
|
+
end
|
234
|
+
yield adr
|
235
|
+
end
|
236
|
+
set_address('ORGANIZER', adr)
|
237
|
+
self
|
238
|
+
end
|
239
|
+
|
240
|
+
=begin
|
241
|
+
# Status values are not rejected during decoding. However, if the
|
242
|
+
# status is requested, and it's value is not one of the defined
|
243
|
+
# allowable values, an exception is raised.
|
244
|
+
def status
|
245
|
+
case self
|
246
|
+
when Vpim::Icalendar::Vevent
|
247
|
+
proptoken 'STATUS', ['TENTATIVE', 'CONFIRMED', 'CANCELLED']
|
248
|
+
|
249
|
+
when Vpim::Icalendar::Vtodo
|
250
|
+
proptoken 'STATUS', ['NEEDS-ACTION', 'COMPLETED', 'IN-PROCESS', 'CANCELLED']
|
251
|
+
|
252
|
+
when Vpim::Icalendar::Vevent
|
253
|
+
proptoken 'STATUS', ['DRAFT', 'FINAL', 'CANCELLED']
|
254
|
+
end
|
255
|
+
end
|
256
|
+
=end
|
257
|
+
|
258
|
+
# Set summary description of component, see Icalendar::Property::Common#summary.
|
259
|
+
def summary(text)
|
260
|
+
set_text 'SUMMARY', text
|
261
|
+
end
|
262
|
+
|
263
|
+
# Set the unique identifier of this calendar component, see Icalendar::Property::Common#uid.
|
264
|
+
def uid(uid)
|
265
|
+
set_text 'UID', uid
|
266
|
+
end
|
267
|
+
|
268
|
+
def url(url)
|
269
|
+
set_text 'URL', url
|
270
|
+
end
|
271
|
+
|
272
|
+
# Add an attendee Address, see Icalendar::Property::Common#attendees.
|
273
|
+
def add_attendee(adr)
|
274
|
+
add_address('ATTENDEE', adr)
|
275
|
+
end
|
276
|
+
|
277
|
+
# Set the categories, see Icalendar::Property::Common#attendees.
|
278
|
+
#
|
279
|
+
# If +cats+ is provided, the categories are set to cats, either a
|
280
|
+
# String or an Array of String. Otherwise, and array of the existing
|
281
|
+
# category strings is yielded, and it can be modified.
|
282
|
+
def categories(cats = nil) #:yield: categories
|
283
|
+
unless cats
|
284
|
+
cats = @comp.categories
|
285
|
+
yield cats
|
286
|
+
end
|
287
|
+
# TODO - strip the strings
|
288
|
+
set_text_list('CATEGORIES', cats)
|
289
|
+
end
|
290
|
+
|
291
|
+
# Set the comment, see Icalendar::Property::Common#comments.
|
292
|
+
def comment(value)
|
293
|
+
set_text 'COMMENT', value
|
294
|
+
end
|
295
|
+
|
296
|
+
=begin
|
297
|
+
def contacts
|
298
|
+
proptextarray 'CONTACT'
|
299
|
+
end
|
300
|
+
|
301
|
+
# An Array of attachments, see Attachment for more information.
|
302
|
+
def attachments
|
303
|
+
@properties.enum_by_name('ATTACH').map do |f|
|
304
|
+
attachment = Attachment.decode(f, 'uri', 'FMTTYPE')
|
305
|
+
end
|
306
|
+
end
|
307
|
+
=end
|
308
|
+
|
309
|
+
end
|
310
|
+
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright (C) 2008 Sam Roberts
|
3
|
+
|
4
|
+
This library is free software; you can redistribute it and/or modify it
|
5
|
+
under the same terms as the ruby language itself, see the file COPYING for
|
6
|
+
details.
|
7
|
+
=end
|
8
|
+
|
9
|
+
module Vpim
|
10
|
+
class Icalendar
|
11
|
+
module Property
|
12
|
+
module Location
|
13
|
+
# Physical location information relevant to the component, or nil if
|
14
|
+
# there is no LOCATION property.
|
15
|
+
def location
|
16
|
+
proptext 'LOCATION'
|
17
|
+
end
|
18
|
+
|
19
|
+
# Array of Float, +[ latitude, longitude]+.
|
20
|
+
#
|
21
|
+
# North of the equator is positive latitude, east of the meridian is
|
22
|
+
# positive longitude.
|
23
|
+
#
|
24
|
+
# See RFC2445 for more info... there are lots of special cases.
|
25
|
+
def geo
|
26
|
+
prop = @properties.detect { |f| f.name? 'GEO' }
|
27
|
+
if prop
|
28
|
+
prop = Vpim.decode_list(prop.value_raw, ';') do |item| item.to_f end
|
29
|
+
end
|
30
|
+
prop
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright (C) 2008 Sam Roberts
|
3
|
+
|
4
|
+
This library is free software; you can redistribute it and/or modify it
|
5
|
+
under the same terms as the ruby language itself, see the file COPYING for
|
6
|
+
details.
|
7
|
+
=end
|
8
|
+
|
9
|
+
module Vpim
|
10
|
+
class Icalendar
|
11
|
+
module Property
|
12
|
+
module Priority
|
13
|
+
|
14
|
+
# +priority+ is a number from 1 to 9, with 1 being the highest
|
15
|
+
# priority, 9 being the lowest. 0 means "no priority", equivalent to
|
16
|
+
# not specifying the PRIORITY field.
|
17
|
+
#
|
18
|
+
# The other integer values are reserved by RFC2445.
|
19
|
+
#
|
20
|
+
# TODO
|
21
|
+
# - methods to compare priorities?
|
22
|
+
# - return as class Priority, with #to_i, and #to_s, and appropriate
|
23
|
+
# comparison operators?
|
24
|
+
def priority
|
25
|
+
p = @properties.detect { |f| f.name? 'PRIORITY' }
|
26
|
+
|
27
|
+
if !p
|
28
|
+
p = 0
|
29
|
+
else
|
30
|
+
p = p.value.to_i
|
31
|
+
|
32
|
+
if( p < 0 || p > 9 )
|
33
|
+
raise Vpim::InvalidEncodingError, 'Invalid priority #{@priority} - it must be 0-9!'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
p
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright (C) 2008 Sam Roberts
|
3
|
+
|
4
|
+
This library is free software; you can redistribute it and/or modify it
|
5
|
+
under the same terms as the ruby language itself, see the file COPYING for
|
6
|
+
details.
|
7
|
+
=end
|
8
|
+
|
9
|
+
require "enumerator"
|
10
|
+
|
11
|
+
module Vpim
|
12
|
+
class Icalendar
|
13
|
+
module Property
|
14
|
+
|
15
|
+
# Occurrences are calculated from DTSTART and RRULE. If there is no
|
16
|
+
# RRULE, the component occurs only once, at the start time.
|
17
|
+
#
|
18
|
+
# Limitations:
|
19
|
+
#
|
20
|
+
# Only a single RRULE: is currently supported, this is the most common
|
21
|
+
# case.
|
22
|
+
module Recurrence
|
23
|
+
def rrule #:nodoc:
|
24
|
+
start = dtstart
|
25
|
+
unless start
|
26
|
+
raise ArgumentError, "Components without a DTSTART don't have occurrences!"
|
27
|
+
end
|
28
|
+
Vpim::Rrule.new(start, propvalue('RRULE'))
|
29
|
+
end
|
30
|
+
|
31
|
+
# The times this components occurs. If a block is not provided, returns
|
32
|
+
# an enumerator.
|
33
|
+
#
|
34
|
+
# Occurrences may be infinite, +dountil+ can be provided to limit the
|
35
|
+
# iterations, see Rrule#each.
|
36
|
+
def occurrences(dountil = nil, &block) #:yield: occurrence time
|
37
|
+
rr = rrule
|
38
|
+
unless block_given?
|
39
|
+
return Enumerable::Enumerator.new(self, :occurrences, dountil)
|
40
|
+
end
|
41
|
+
|
42
|
+
rr.each(dountil, &block)
|
43
|
+
end
|
44
|
+
|
45
|
+
alias occurences occurrences #:nodoc: backwards compatibility
|
46
|
+
|
47
|
+
# True if this components occurs in a time period later than +t0+, but
|
48
|
+
# earlier than +t1+.
|
49
|
+
def occurs_in?(t0, t1)
|
50
|
+
# TODO - deprecate this, its a hack
|
51
|
+
occurrences(t1).detect do |tend|
|
52
|
+
if respond_to? :duration
|
53
|
+
tend += duration || 0
|
54
|
+
end
|
55
|
+
tend >= t0
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def rdates #:nodoc:
|
60
|
+
# TODO - this is a hack, remove it
|
61
|
+
Vpim.decode_date_time_list(propvalue('RDATE'))
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
|