mumboe-vpim 0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +510 -0
- data/COPYING +58 -0
- data/README +185 -0
- data/lib/vpim/address.rb +219 -0
- data/lib/vpim/agent/atomize.rb +104 -0
- data/lib/vpim/agent/base.rb +73 -0
- data/lib/vpim/agent/calendars.rb +173 -0
- data/lib/vpim/agent/handler.rb +26 -0
- data/lib/vpim/agent/ics.rb +161 -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 +384 -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 +261 -0
- data/lib/vpim/rfc2425.rb +367 -0
- data/lib/vpim/rrule.rb +591 -0
- data/lib/vpim/time.rb +40 -0
- data/lib/vpim/vcard.rb +1456 -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/lib/vpim.rb +13 -0
- data/samples/README.mutt +93 -0
- data/samples/ab-query.rb +57 -0
- data/samples/agent.ru +10 -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 +209 -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_agent_atomize.rb +84 -0
- data/test/test_agent_calendars.rb +128 -0
- data/test/test_agent_ics.rb +96 -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 +437 -0
- data/test/test_misc.rb +13 -0
- data/test/test_repo.rb +129 -0
- data/test/test_rrule.rb +1030 -0
- data/test/test_vcard.rb +973 -0
- data/test/test_view.rb +79 -0
- metadata +140 -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
|
+
|
@@ -0,0 +1,24 @@
|
|
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
|
+
|
13
|
+
module Resources
|
14
|
+
|
15
|
+
def resources
|
16
|
+
proptextlistarray 'RESOURCES'
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|