vpim 0.16 → 0.17
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.
- data/lib/vpim/agent/plist.rb +86 -0
- data/lib/vpim/date.rb +1 -3
- data/lib/vpim/date.rb~ +198 -0
- data/lib/vpim/dirinfo.rb +47 -15
- data/lib/vpim/dirinfo.rb~ +242 -0
- data/lib/vpim/duration.rb +1 -3
- data/lib/vpim/duration.rb~ +121 -0
- data/lib/vpim/enumerator.rb +1 -3
- data/lib/vpim/enumerator.rb~ +29 -0
- data/lib/vpim/field.rb +141 -56
- data/lib/vpim/field.rb~ +594 -0
- data/lib/vpim/icalendar.rb +10 -16
- data/lib/vpim/icalendar.rb~ +548 -0
- data/lib/vpim/maker/vcard.rb +124 -46
- data/lib/vpim/maker/vcard.rb~ +382 -0
- data/lib/vpim/rfc2425.rb +30 -17
- data/lib/vpim/rfc2425.rb~ +246 -0
- data/lib/vpim/rrule.rb +2 -4
- data/lib/vpim/rrule.rb~ +482 -0
- data/lib/vpim/time.rb +1 -3
- data/lib/vpim/time.rb~ +42 -0
- data/lib/vpim/vcard.rb +84 -18
- data/lib/vpim/vcard.rb~ +232 -0
- data/lib/vpim/vevent.rb +1 -3
- data/lib/vpim/vevent.rb~ +381 -0
- data/lib/vpim/vpim.rb +61 -29
- data/lib/vpim/vpim.rb~ +61 -29
- metadata +16 -2
data/lib/vpim/maker/vcard.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
=begin
|
2
|
-
|
3
|
-
|
4
|
-
Copyright (C) 2005 Sam Roberts
|
2
|
+
Copyright (C) 2006 Sam Roberts
|
5
3
|
|
6
4
|
This library is free software; you can redistribute it and/or modify it
|
7
5
|
under the same terms as the ruby language itself, see the file COPYING for
|
@@ -11,49 +9,67 @@
|
|
11
9
|
require 'vpim/vcard'
|
12
10
|
|
13
11
|
module Vpim
|
14
|
-
module Maker
|
12
|
+
module Maker #:nodoc:
|
15
13
|
# A helper class to assist in building a vCard.
|
16
14
|
#
|
17
|
-
#
|
18
|
-
#
|
15
|
+
# Examples:
|
16
|
+
# - link:ex_mkvcard.txt: example of creating a vCard
|
17
|
+
# - link:ex_cpvcard.txt: example of copying and them modifying a vCard
|
18
|
+
# - link:ex_mkv21vcard.txt: example of creating version 2.1 vCard
|
19
19
|
class Vcard
|
20
|
-
# Make a vCard
|
20
|
+
# Make a vCard.
|
21
|
+
#
|
22
|
+
# Yields +maker+, a Vpim::Maker::Vcard which allows fields to be added to
|
23
|
+
# +card+, and returns +card+, a Vpim::Vcard.
|
21
24
|
#
|
22
|
-
#
|
25
|
+
# If +card+ is nil or not provided a new Vpim::Vcard is created and the
|
26
|
+
# fields are added to it.
|
27
|
+
#
|
28
|
+
# Defaults:
|
29
|
+
# - vCards must have both an N: and an FN: field, #make2 will fail if there
|
30
|
+
# is no FN: field in the +card+ when your block is finished adding fields.
|
31
|
+
# - If there is an FN: field, but no N: field, N: will be set from the information
|
32
|
+
# in FN:, see Vcard::Name#preformatted for more information.
|
33
|
+
# - vCards must have a VERSION: field. If one does not exist when your block is
|
34
|
+
# is finished adding fields then it will be set to 3.0.
|
35
|
+
def Vcard.make2(card = Vpim::Vcard.create, &block) # :yields: maker
|
36
|
+
new(nil, card).make(&block)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Deprecated, use #make2.
|
23
40
|
#
|
24
|
-
#
|
25
|
-
|
26
|
-
|
41
|
+
# If set, the FN: field will be set to +full_name+. Otherwise, FN: will
|
42
|
+
# be set from the values in #add_name.
|
43
|
+
def Vcard.make(full_name = nil, &block) # :yields: maker
|
44
|
+
new(full_name, Vpim::Vcard.create).make(&block)
|
27
45
|
end
|
28
46
|
|
29
47
|
def make # :nodoc:
|
30
48
|
yield self
|
31
|
-
|
32
|
-
raise Vpim::InvalidEncodingError, 'It is mandatory to have a
|
49
|
+
unless @card['N']
|
50
|
+
raise Vpim::InvalidEncodingError, 'It is mandatory to have a name field, see #add_name.'
|
51
|
+
end
|
52
|
+
unless @card['FN']
|
53
|
+
@card << Vpim::DirectoryInfo::Field.create('FN', Vpim::Vcard::Name.new(@card['N'], '').formatted)
|
54
|
+
end
|
55
|
+
unless @card['VERSION']
|
56
|
+
@card << Vpim::DirectoryInfo::Field.create('VERSION', "3.0")
|
33
57
|
end
|
34
58
|
@card
|
35
59
|
end
|
36
60
|
|
37
61
|
private
|
38
62
|
|
39
|
-
def initialize(full_name) # :nodoc:
|
40
|
-
@card = Vpim::Vcard::create
|
41
|
-
|
42
|
-
|
43
|
-
|
63
|
+
def initialize(full_name, card) # :nodoc:
|
64
|
+
@card = card || Vpim::Vcard::create
|
65
|
+
if full_name
|
66
|
+
@card << Vpim::DirectoryInfo::Field.create('FN', full_name )
|
67
|
+
end
|
44
68
|
end
|
45
69
|
|
46
70
|
public
|
47
71
|
|
48
|
-
# Add
|
49
|
-
def add_field(field)
|
50
|
-
@card << field
|
51
|
-
end
|
52
|
-
|
53
|
-
# Add a name field, N.
|
54
|
-
#
|
55
|
-
# Warning: This is the only mandatory field, besides the full name, which
|
56
|
-
# is added from Vcard.make's +full_name+.
|
72
|
+
# Add a name field, N:.
|
57
73
|
#
|
58
74
|
# Attributes of N are:
|
59
75
|
# - family: family name
|
@@ -64,6 +80,10 @@ module Vpim
|
|
64
80
|
#
|
65
81
|
# All attributes are optional.
|
66
82
|
#
|
83
|
+
# Warning: This is the only mandatory field besides the full name, FN,
|
84
|
+
# but FN: can be set in #make, and if not set will be constucted as the
|
85
|
+
# string "#{prefix} #{given} #{additional} #{family}, #{suffix}".
|
86
|
+
#
|
67
87
|
# FIXME: is it possible to deduce given/family from the full_name?
|
68
88
|
#
|
69
89
|
# FIXME: Each attribute can currently only have a single String value.
|
@@ -76,13 +96,23 @@ module Vpim
|
|
76
96
|
'N',
|
77
97
|
x.map { |s| s ? s.to_str : '' }
|
78
98
|
)
|
79
|
-
@initialized_N = true
|
80
99
|
self
|
81
100
|
end
|
82
101
|
|
83
|
-
# Add a
|
102
|
+
# Add a full name field, FN.
|
84
103
|
#
|
85
|
-
#
|
104
|
+
# Normally the FN field value is derived from the N: field value, but
|
105
|
+
# it can be explicitly set.
|
106
|
+
def fullname=(fullname)
|
107
|
+
if @card.field('FN')
|
108
|
+
raise Vpim::InvalidEncodingError, "Not allowed to add more than one FN field to a vCard."
|
109
|
+
end
|
110
|
+
@card << Vpim::DirectoryInfo::Field.create( 'FN', fullname );
|
111
|
+
end
|
112
|
+
|
113
|
+
# Add a address field, ADR:.
|
114
|
+
#
|
115
|
+
# Attributes of ADR: that describe the address are:
|
86
116
|
# - pobox: post office box
|
87
117
|
# - extended: seldom used, its not clear what it is for
|
88
118
|
# - street: street address, multiple components should be separated by a comma, ','
|
@@ -99,9 +129,9 @@ module Vpim
|
|
99
129
|
# All attributes are optional. #location and #home can be set to arrays of
|
100
130
|
# strings.
|
101
131
|
#
|
102
|
-
# TODO
|
132
|
+
# TODO - Add #label to support LABEL.
|
103
133
|
#
|
104
|
-
# FIXME
|
134
|
+
# FIXME - Need to escape specials in the String.
|
105
135
|
def add_addr # :yield: adr
|
106
136
|
x = Struct.new(
|
107
137
|
:location, :preferred, :delivery,
|
@@ -124,12 +154,12 @@ module Vpim
|
|
124
154
|
self
|
125
155
|
end
|
126
156
|
|
127
|
-
# Add a telephone number field, TEL
|
157
|
+
# Add a telephone number field, TEL:.
|
128
158
|
#
|
129
159
|
# +number+ is supposed to be a "X.500 Telephone Number" according to RFC 2426, if you happen
|
130
160
|
# to be familiar with that. Otherwise, anything that looks like a phone number should be OK.
|
131
161
|
#
|
132
|
-
# Attributes of TEL are:
|
162
|
+
# Attributes of TEL: are:
|
133
163
|
# - location: home, work, msg, cell, car, pager - often used, can be set to other values
|
134
164
|
# - preferred: true - often used, set if this is the preferred telephone number
|
135
165
|
# - capability: voice,fax,video,bbs,modem,isdn,pcs - fax is useful, the others are rarely used
|
@@ -153,9 +183,9 @@ module Vpim
|
|
153
183
|
self
|
154
184
|
end
|
155
185
|
|
156
|
-
# Add a email address field, EMAIL
|
186
|
+
# Add a email address field, EMAIL:.
|
157
187
|
#
|
158
|
-
# Attributes of EMAIL are:
|
188
|
+
# Attributes of EMAIL: are:
|
159
189
|
# - location: home, work - often used, can be set to other values
|
160
190
|
# - preferred: true - often used, set if this is the preferred email address
|
161
191
|
# - protocol: internet,x400 - internet is the default, set this for other kinds
|
@@ -179,12 +209,12 @@ module Vpim
|
|
179
209
|
self
|
180
210
|
end
|
181
211
|
|
182
|
-
# Add a nickname field, NICKNAME
|
212
|
+
# Add a nickname field, NICKNAME:.
|
183
213
|
def nickname=(nickname)
|
184
214
|
@card << Vpim::DirectoryInfo::Field.create( 'NICKNAME', nickname );
|
185
215
|
end
|
186
216
|
|
187
|
-
# Add a birthday field, BDAY
|
217
|
+
# Add a birthday field, BDAY:.
|
188
218
|
#
|
189
219
|
# +birthday+ must be a time or date object.
|
190
220
|
#
|
@@ -205,10 +235,10 @@ TODO - need text=() implemented in Field
|
|
205
235
|
end
|
206
236
|
=end
|
207
237
|
|
208
|
-
# Add an instant-messaging/point of presence address field, IMPP
|
238
|
+
# Add an instant-messaging/point of presence address field, IMPP:. The address
|
209
239
|
# is a URL, with the syntax depending on the protocol.
|
210
240
|
#
|
211
|
-
# Attributes of IMPP are:
|
241
|
+
# Attributes of IMPP: are:
|
212
242
|
# - preferred: true - set if this is the preferred address
|
213
243
|
# - location: home, work, mobile - location of address
|
214
244
|
# - purpose: personal,business - purpose of communications
|
@@ -220,7 +250,7 @@ TODO - need text=() implemented in Field
|
|
220
250
|
# the user to know the URL for their own address, hopefully not too much
|
221
251
|
# of a burden.
|
222
252
|
#
|
223
|
-
# IMPP is defined in draft-jennings-impp-vcard-04.txt. It refers to the
|
253
|
+
# IMPP: is defined in draft-jennings-impp-vcard-04.txt. It refers to the
|
224
254
|
# URI scheme of a number of messaging protocols, but doesn't give
|
225
255
|
# references to all of them:
|
226
256
|
# - "xmpp" indicates to use XMPP, draft-saintandre-xmpp-uri-06.txt
|
@@ -250,13 +280,13 @@ TODO - need text=() implemented in Field
|
|
250
280
|
self
|
251
281
|
end
|
252
282
|
|
253
|
-
# Add an
|
283
|
+
# Add an X-AIM: account name where +xaim+ is an AIM screen name.
|
254
284
|
#
|
255
285
|
# I don't know if this is conventional, or supported by anything other
|
256
286
|
# than AddressBook.app, but an example is:
|
257
287
|
# X-AIM;type=HOME;type=pref:exampleaccount
|
258
288
|
#
|
259
|
-
# Attributes of X-AIM are:
|
289
|
+
# Attributes of X-AIM: are:
|
260
290
|
# - preferred: true - set if this is the preferred address
|
261
291
|
# - location: home, work, mobile - location of address
|
262
292
|
#
|
@@ -281,10 +311,10 @@ TODO - need text=() implemented in Field
|
|
281
311
|
end
|
282
312
|
|
283
313
|
|
284
|
-
# Add a photo field, PHOTO
|
314
|
+
# Add a photo field, PHOTO:.
|
285
315
|
#
|
286
|
-
# Attributes of PHOTO are:
|
287
|
-
# - image: set to image data to
|
316
|
+
# Attributes of PHOTO: are:
|
317
|
+
# - image: set to image data to include inline
|
288
318
|
# - link: set to the URL of the image data
|
289
319
|
# - type: string identifying the image type, supposed to be an "IANA registered image format",
|
290
320
|
# or a non-registered image format (usually these start with an x-)
|
@@ -331,6 +361,54 @@ TODO - need text=() implemented in Field
|
|
331
361
|
self
|
332
362
|
end
|
333
363
|
|
364
|
+
# Add a Field, +field+.
|
365
|
+
def add_field(field)
|
366
|
+
fieldname = field.name.upcase
|
367
|
+
case
|
368
|
+
when [ 'BEGIN', 'END' ].include?(fieldname)
|
369
|
+
raise Vpim::InvalidEncodingError, "Not allowed to manually add #{field.name} to a vCard."
|
370
|
+
|
371
|
+
when [ 'VERSION', 'N', 'FN' ].include?(fieldname)
|
372
|
+
if @card.field(fieldname)
|
373
|
+
raise Vpim::InvalidEncodingError, "Not allowed to add more than one #{fieldname} to a vCard."
|
374
|
+
end
|
375
|
+
@card << field
|
376
|
+
|
377
|
+
else
|
378
|
+
@card << field
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
# Copy the fields from +card+ into self using #add_field. If a block is
|
383
|
+
# provided, each Field from +card+ is yielded. The block should return a
|
384
|
+
# Field to add, or nil. The Field doesn't have to be the one yielded,
|
385
|
+
# allowing the field to be copied and modified (see Field#copy) before adding, or
|
386
|
+
# not added at all if the block yields nil.
|
387
|
+
#
|
388
|
+
# The vCard fields BEGIN: and END: aren't copied, and VERSION:, N:, and FN: are copied
|
389
|
+
# only if the card doesn't have them already.
|
390
|
+
def copy(card) # :yields: Field
|
391
|
+
card.each do |field|
|
392
|
+
fieldname = field.name.upcase
|
393
|
+
case
|
394
|
+
when [ 'BEGIN', 'END' ].include?(fieldname)
|
395
|
+
# Never copy these
|
396
|
+
|
397
|
+
when [ 'VERSION', 'N', 'FN' ].include?(fieldname) && @card.field(fieldname)
|
398
|
+
# Copy these only if they don't already exist.
|
399
|
+
|
400
|
+
else
|
401
|
+
if block_given?
|
402
|
+
field = yield field
|
403
|
+
end
|
404
|
+
|
405
|
+
if field
|
406
|
+
add_field(field)
|
407
|
+
end
|
408
|
+
end
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
334
412
|
end
|
335
413
|
end
|
336
414
|
end
|
@@ -0,0 +1,382 @@
|
|
1
|
+
=begin
|
2
|
+
$Id: vcard.rb,v 1.7 2005/02/04 21:09:34 sam Exp $
|
3
|
+
|
4
|
+
Copyright (C) 2006 Sam Roberts
|
5
|
+
|
6
|
+
This library is free software; you can redistribute it and/or modify it
|
7
|
+
under the same terms as the ruby language itself, see the file COPYING for
|
8
|
+
details.
|
9
|
+
=end
|
10
|
+
|
11
|
+
require 'vpim/vcard'
|
12
|
+
|
13
|
+
module Vpim
|
14
|
+
module Maker
|
15
|
+
# A helper class to assist in building a vCard.
|
16
|
+
#
|
17
|
+
# Examples:
|
18
|
+
# - link:ex_mkvcard.txt: an example of making a vCard
|
19
|
+
# - link:ex_cpvcard.txt: an example of copying and modifying a vCard
|
20
|
+
#
|
21
|
+
# Note - The Maker module is modelled after rss/maker, but if a Vcard was
|
22
|
+
# mutable these methods could be added to Vpim::Vcard. Hm.
|
23
|
+
class Vcard
|
24
|
+
# Make a vCard for +full_name+.
|
25
|
+
#
|
26
|
+
# Yields +card+, a Vpim::Maker::Vcard to which fields can be added, and returns a Vpim::Vcard.
|
27
|
+
#
|
28
|
+
# Note that calling #add_name is required, all other fields are optional.
|
29
|
+
def Vcard.make(full_name, &block) # :yields: +card+
|
30
|
+
new(full_name).make(&block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def make # :nodoc:
|
34
|
+
yield self
|
35
|
+
unless @card['N']
|
36
|
+
raise Vpim::InvalidEncodingError, 'It is mandatory to have a name field, see #add_name.'
|
37
|
+
end
|
38
|
+
@card
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def initialize(full_name) # :nodoc:
|
44
|
+
@card = Vpim::Vcard::create
|
45
|
+
@card << Vpim::DirectoryInfo::Field.create('FN', full_name )
|
46
|
+
# pp @card
|
47
|
+
end
|
48
|
+
|
49
|
+
public
|
50
|
+
|
51
|
+
# Add an arbitrary Field, +field+.
|
52
|
+
def add_field(field)
|
53
|
+
fieldname = field.name.upcase
|
54
|
+
case
|
55
|
+
when [ 'BEGIN', 'END', 'VERSION' ].include?(fieldname)
|
56
|
+
raise Vpim::InvalidEncodingError, "Not allowed to manually add #{field.name} to a vCard."
|
57
|
+
|
58
|
+
when [ 'N', 'FN' ].include?(fieldname)
|
59
|
+
if @card.field(fieldname)
|
60
|
+
raise Vpim::InvalidEncodingError, "Not allowed to add more than one #{fieldname} to a vCard."
|
61
|
+
end
|
62
|
+
@card << field
|
63
|
+
|
64
|
+
else
|
65
|
+
@card << field
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Copy the fields from +card+ into self using #add_field. If a block is
|
70
|
+
# provided, each Field from +card+ is yielded. The block should return a
|
71
|
+
# Field to add, or nil. The Field doesn't have to be the one yielded,
|
72
|
+
# this allows modified fields to be copied in (use Field#copy), or fields
|
73
|
+
# to be filtered out (if the block yields nil).
|
74
|
+
#
|
75
|
+
# The vCard fields BEGIN, END, VERSION aren't copied, and N and FN aren't copied
|
76
|
+
# if the target already has them
|
77
|
+
def copy(card) # :yields: Field
|
78
|
+
card.each do |field|
|
79
|
+
fieldname = field.name.upcase
|
80
|
+
case
|
81
|
+
when [ 'BEGIN', 'END', 'VERSION' ].include?(fieldname)
|
82
|
+
# Never copy these
|
83
|
+
|
84
|
+
when [ 'N', 'FN' ].include?(fieldname) && @card.field(fieldname)
|
85
|
+
# Copy these only if they don't already exist.
|
86
|
+
|
87
|
+
else
|
88
|
+
if block_given?
|
89
|
+
field = yield field
|
90
|
+
end
|
91
|
+
|
92
|
+
if field
|
93
|
+
add_field(field)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Add a name field, N.
|
100
|
+
#
|
101
|
+
# Warning: This is the only mandatory field, besides the full name, which
|
102
|
+
# is added from Vcard.make's +full_name+.
|
103
|
+
#
|
104
|
+
# Attributes of N are:
|
105
|
+
# - family: family name
|
106
|
+
# - given: given name
|
107
|
+
# - additional: additional names
|
108
|
+
# - prefix: such as "Ms." or "Dr."
|
109
|
+
# - suffix: such as "BFA", or "Sensei"
|
110
|
+
#
|
111
|
+
# All attributes are optional.
|
112
|
+
#
|
113
|
+
# FIXME: is it possible to deduce given/family from the full_name?
|
114
|
+
#
|
115
|
+
# FIXME: Each attribute can currently only have a single String value.
|
116
|
+
#
|
117
|
+
# FIXME: Need to escape specials in the String.
|
118
|
+
def add_name # :yield: n
|
119
|
+
x = Struct.new(:family, :given, :additional, :prefix, :suffix).new
|
120
|
+
yield x
|
121
|
+
@card << Vpim::DirectoryInfo::Field.create(
|
122
|
+
'N',
|
123
|
+
x.map { |s| s ? s.to_str : '' }
|
124
|
+
)
|
125
|
+
self
|
126
|
+
end
|
127
|
+
|
128
|
+
# Add a address field, ADR.
|
129
|
+
#
|
130
|
+
# Attributes of ADR that describe the address are:
|
131
|
+
# - pobox: post office box
|
132
|
+
# - extended: seldom used, its not clear what it is for
|
133
|
+
# - street: street address, multiple components should be separated by a comma, ','
|
134
|
+
# - locality: usually the city
|
135
|
+
# - region: usually the province or state
|
136
|
+
# - postalcode: postal code
|
137
|
+
# - country: country name, no standard for country naming is specified
|
138
|
+
#
|
139
|
+
# Attributes that describe how the address is used, and customary values, are:
|
140
|
+
# - location: home, work - often used, can be set to other values
|
141
|
+
# - preferred: true - often used, set if this is the preferred address
|
142
|
+
# - delivery: postal, parcel, dom (domestic), intl (international) - rarely used
|
143
|
+
#
|
144
|
+
# All attributes are optional. #location and #home can be set to arrays of
|
145
|
+
# strings.
|
146
|
+
#
|
147
|
+
# TODO: Add #label to support LABEL.
|
148
|
+
#
|
149
|
+
# FIXME: Need to escape specials in the String.
|
150
|
+
def add_addr # :yield: adr
|
151
|
+
x = Struct.new(
|
152
|
+
:location, :preferred, :delivery,
|
153
|
+
:pobox, :extended, :street, :locality, :region, :postalcode, :country
|
154
|
+
).new
|
155
|
+
yield x
|
156
|
+
|
157
|
+
values = x.to_a[3, 7].map { |s| s ? s.to_str : '' }
|
158
|
+
|
159
|
+
# All these attributes go into the TYPE parameter.
|
160
|
+
params = [ x[:location], x[:delivery] ]
|
161
|
+
params << 'pref' if x[:preferred]
|
162
|
+
params = params.flatten.uniq.compact.map { |s| s.to_str }
|
163
|
+
|
164
|
+
paramshash = {}
|
165
|
+
|
166
|
+
paramshash['type'] = params if params.first
|
167
|
+
|
168
|
+
@card << Vpim::DirectoryInfo::Field.create( 'ADR', values, paramshash)
|
169
|
+
self
|
170
|
+
end
|
171
|
+
|
172
|
+
# Add a telephone number field, TEL.
|
173
|
+
#
|
174
|
+
# +number+ is supposed to be a "X.500 Telephone Number" according to RFC 2426, if you happen
|
175
|
+
# to be familiar with that. Otherwise, anything that looks like a phone number should be OK.
|
176
|
+
#
|
177
|
+
# Attributes of TEL are:
|
178
|
+
# - location: home, work, msg, cell, car, pager - often used, can be set to other values
|
179
|
+
# - preferred: true - often used, set if this is the preferred telephone number
|
180
|
+
# - capability: voice,fax,video,bbs,modem,isdn,pcs - fax is useful, the others are rarely used
|
181
|
+
#
|
182
|
+
# All attributes are optional, and so is the block.
|
183
|
+
def add_tel(number) # :yield: tel
|
184
|
+
params = {}
|
185
|
+
if block_given?
|
186
|
+
x = Struct.new( :location, :preferred, :capability ).new
|
187
|
+
|
188
|
+
yield x
|
189
|
+
|
190
|
+
x[:preferred] = 'pref' if x[:preferred]
|
191
|
+
|
192
|
+
types = x.to_a.flatten.uniq.compact.map { |s| s.to_str }
|
193
|
+
|
194
|
+
params['type'] = types if types.first
|
195
|
+
end
|
196
|
+
|
197
|
+
@card << Vpim::DirectoryInfo::Field.create( 'TEL', number, params)
|
198
|
+
self
|
199
|
+
end
|
200
|
+
|
201
|
+
# Add a email address field, EMAIL.
|
202
|
+
#
|
203
|
+
# Attributes of EMAIL are:
|
204
|
+
# - location: home, work - often used, can be set to other values
|
205
|
+
# - preferred: true - often used, set if this is the preferred email address
|
206
|
+
# - protocol: internet,x400 - internet is the default, set this for other kinds
|
207
|
+
#
|
208
|
+
# All attributes are optional, and so is the block.
|
209
|
+
def add_email(email) # :yield: email
|
210
|
+
params = {}
|
211
|
+
if block_given?
|
212
|
+
x = Struct.new( :location, :preferred, :protocol ).new
|
213
|
+
|
214
|
+
yield x
|
215
|
+
|
216
|
+
x[:preferred] = 'pref' if x[:preferred]
|
217
|
+
|
218
|
+
types = x.to_a.flatten.uniq.compact.map { |s| s.to_str }
|
219
|
+
|
220
|
+
params['type'] = types if types.first
|
221
|
+
end
|
222
|
+
|
223
|
+
@card << Vpim::DirectoryInfo::Field.create( 'EMAIL', email, params)
|
224
|
+
self
|
225
|
+
end
|
226
|
+
|
227
|
+
# Add a nickname field, NICKNAME.
|
228
|
+
def nickname=(nickname)
|
229
|
+
@card << Vpim::DirectoryInfo::Field.create( 'NICKNAME', nickname );
|
230
|
+
end
|
231
|
+
|
232
|
+
# Add a birthday field, BDAY.
|
233
|
+
#
|
234
|
+
# +birthday+ must be a time or date object.
|
235
|
+
#
|
236
|
+
# Warning: It may confuse both humans and software if you add multiple
|
237
|
+
# birthdays.
|
238
|
+
def birthday=(birthday)
|
239
|
+
if !birthday.respond_to? :month
|
240
|
+
raise Vpim::InvalidEncodingError, 'birthday doesn\'t have #month, so it is not a date or time object.'
|
241
|
+
end
|
242
|
+
@card << Vpim::DirectoryInfo::Field.create( 'BDAY', birthday );
|
243
|
+
end
|
244
|
+
=begin
|
245
|
+
TODO - need text=() implemented in Field
|
246
|
+
|
247
|
+
# Add a note field, NOTE. It can contain newlines, they will be escaped.
|
248
|
+
def note=(note)
|
249
|
+
@card << Vpim::DirectoryInfo::Field.create( 'NOTE', note );
|
250
|
+
end
|
251
|
+
=end
|
252
|
+
|
253
|
+
# Add an instant-messaging/point of presence address field, IMPP. The address
|
254
|
+
# is a URL, with the syntax depending on the protocol.
|
255
|
+
#
|
256
|
+
# Attributes of IMPP are:
|
257
|
+
# - preferred: true - set if this is the preferred address
|
258
|
+
# - location: home, work, mobile - location of address
|
259
|
+
# - purpose: personal,business - purpose of communications
|
260
|
+
#
|
261
|
+
# All attributes are optional, and so is the block.
|
262
|
+
#
|
263
|
+
# The URL syntaxes for the messaging schemes is fairly complicated, so I
|
264
|
+
# don't try and build the URLs here, maybe in the future. This forces
|
265
|
+
# the user to know the URL for their own address, hopefully not too much
|
266
|
+
# of a burden.
|
267
|
+
#
|
268
|
+
# IMPP is defined in draft-jennings-impp-vcard-04.txt. It refers to the
|
269
|
+
# URI scheme of a number of messaging protocols, but doesn't give
|
270
|
+
# references to all of them:
|
271
|
+
# - "xmpp" indicates to use XMPP, draft-saintandre-xmpp-uri-06.txt
|
272
|
+
# - "irc" or "ircs" indicates to use IRC, draft-butcher-irc-url-04.txt
|
273
|
+
# - "sip" indicates to use SIP/SIMPLE, RFC 3261
|
274
|
+
# - "im" or "pres" indicates to use a CPIM or CPP gateway, RFC 3860 and RFC 3859
|
275
|
+
# - "ymsgr" indicates to use yahoo
|
276
|
+
# - "msn" might indicate to use Microsoft messenger
|
277
|
+
# - "aim" indicates to use AOL
|
278
|
+
#
|
279
|
+
def add_impp(url) # :yield: impp
|
280
|
+
params = {}
|
281
|
+
|
282
|
+
if block_given?
|
283
|
+
x = Struct.new( :location, :preferred, :purpose ).new
|
284
|
+
|
285
|
+
yield x
|
286
|
+
|
287
|
+
x[:preferred] = 'pref' if x[:preferred]
|
288
|
+
|
289
|
+
types = x.to_a.flatten.uniq.compact.map { |s| s.to_str }
|
290
|
+
|
291
|
+
params['type'] = types if types.first
|
292
|
+
end
|
293
|
+
|
294
|
+
@card << Vpim::DirectoryInfo::Field.create( 'IMPP', url, params)
|
295
|
+
self
|
296
|
+
end
|
297
|
+
|
298
|
+
# Add an Apple style AIM account name, +xaim+ is an AIM screen name.
|
299
|
+
#
|
300
|
+
# I don't know if this is conventional, or supported by anything other
|
301
|
+
# than AddressBook.app, but an example is:
|
302
|
+
# X-AIM;type=HOME;type=pref:exampleaccount
|
303
|
+
#
|
304
|
+
# Attributes of X-AIM are:
|
305
|
+
# - preferred: true - set if this is the preferred address
|
306
|
+
# - location: home, work, mobile - location of address
|
307
|
+
#
|
308
|
+
# All attributes are optional, and so is the block.
|
309
|
+
def add_x_aim(xaim) # :yield: xaim
|
310
|
+
params = {}
|
311
|
+
|
312
|
+
if block_given?
|
313
|
+
x = Struct.new( :location, :preferred ).new
|
314
|
+
|
315
|
+
yield x
|
316
|
+
|
317
|
+
x[:preferred] = 'pref' if x[:preferred]
|
318
|
+
|
319
|
+
types = x.to_a.flatten.uniq.compact.map { |s| s.to_str }
|
320
|
+
|
321
|
+
params['type'] = types if types.first
|
322
|
+
end
|
323
|
+
|
324
|
+
@card << Vpim::DirectoryInfo::Field.create( 'X-AIM', xaim, params)
|
325
|
+
self
|
326
|
+
end
|
327
|
+
|
328
|
+
|
329
|
+
# Add a photo field, PHOTO.
|
330
|
+
#
|
331
|
+
# Attributes of PHOTO are:
|
332
|
+
# - image: set to image data to inclue inline
|
333
|
+
# - link: set to the URL of the image data
|
334
|
+
# - type: string identifying the image type, supposed to be an "IANA registered image format",
|
335
|
+
# or a non-registered image format (usually these start with an x-)
|
336
|
+
#
|
337
|
+
# An error will be raised if neither image or link is set, or if both image
|
338
|
+
# and link is set.
|
339
|
+
#
|
340
|
+
# Setting type is optional for a link image, because either the URL, the
|
341
|
+
# image file extension, or a HTTP Content-Type may specify the type. If
|
342
|
+
# it's not a link, setting type is mandatory, though it can be set to an
|
343
|
+
# empty string, <code>''</code>, if the type is unknown.
|
344
|
+
#
|
345
|
+
# TODO - I'm not sure about this API. I'm thinking maybe it should be
|
346
|
+
# #add_photo(image, type), and that I should detect when the image is a
|
347
|
+
# URL, and make type mandatory if it wasn't a URL.
|
348
|
+
def add_photo # :yield: photo
|
349
|
+
x = Struct.new(:image, :link, :type).new
|
350
|
+
yield x
|
351
|
+
if x[:image] && x[:link]
|
352
|
+
raise Vpim::InvalidEncodingError, 'Image is not allowed to be both inline and a link.'
|
353
|
+
end
|
354
|
+
|
355
|
+
value = x[:image] || x[:link]
|
356
|
+
|
357
|
+
if !value
|
358
|
+
raise Vpim::InvalidEncodingError, 'A image link or inline data must be provided.'
|
359
|
+
end
|
360
|
+
|
361
|
+
params = {}
|
362
|
+
|
363
|
+
# Don't set type to the empty string.
|
364
|
+
params['type'] = x[:type] if( x[:type] && x[:type].length > 0 )
|
365
|
+
|
366
|
+
if x[:link]
|
367
|
+
params['value'] = 'uri'
|
368
|
+
else # it's inline, base-64 encode it
|
369
|
+
params['encoding'] = :b64
|
370
|
+
if !x[:type]
|
371
|
+
raise Vpim::InvalidEncodingError, 'Inline image data must have it\'s type set.'
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
@card << Vpim::DirectoryInfo::Field.create( 'PHOTO', value, params )
|
376
|
+
self
|
377
|
+
end
|
378
|
+
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|