class Vpim::Vcard
A vCard, a specialization of a directory info object.
The vCard format is specified by:
-
RFC2426: vCard MIME Directory Profile (vCard 3.0)
-
RFC2425: A MIME Content-Type for Directory Information
This implements vCard 3.0, but it is also capable of working with vCard 2.1 if used with care.
All line values can be accessed with #value, #values, or even by iterating through #lines. Line types that don't have specific support and non-standard line types (“X-MY-SPECIAL”, for example) will be returned as a String, with any base64 or quoted-printable encoding removed.
Specific support exists to return more useful values for the standard vCard types, where appropriate.
The wrapper functions (#birthday, nicknames, emails, etc.) exist partially as an API convenience, and partially as a place to document the values returned for the more complex types, like PHOTO and EMAIL.
For types that do not sensibly occur multiple times (like BDAY or GEO), sometimes a wrapper exists only to return a single line, using value. However, if you find the need, you can still call values to get all the lines, and both the singular and plural forms will eventually be implemented.
For more information see:
-
RFC2426: vCard MIME Directory Profile (vCard 3.0)
-
RFC2425: A MIME Content-Type for Directory Information
-
vCard2.1: vCard 2.1 Specifications
vCards are usually transmitted in files with .vcf
extensions.
Examples¶ ↑
-
ex_mkvcard.txt: example of creating a vCard
-
ex_cpvcard.txt: example of copying and them modifying a vCard
-
ex_mkv21vcard.txt: example of creating version 2.1 vCard
-
mutt-aliases-to-vcf.txt: convert a mutt aliases file to vCards
-
ex_get_vcard_photo.txt: pull photo data from a vCard
-
ab-query.txt: query the OS X Address Book to find vCards
-
vcf-to-mutt.txt: query vCards for matches, output in formats useful with Mutt (see README.mutt for details)
-
tabbed-file-to-vcf.txt: convert a tab-delimited file to vCards, a (small but) complete application contributed by Dane G. Avilla, thanks!
-
vcf-to-ics.txt: example of how to create calendars of birthdays from vCards
-
vcf-dump.txt: utility for dumping contents of .vcf files
Public Class Methods
Create a vCard 3.0 object with the minimum required fields, plus any
fields
you want in the card (they can also be added later).
# File lib/vpim/vcard.rb, line 632 def Vcard.create(fields = [] ) fields.unshift Field.create('VERSION', "3.0") super(fields, 'VCARD') end
Decode a collection of vCards into an array of Vcard objects.
card
can be either a String or an IO object.
Since vCards are self-delimited (by a BEGIN:vCard and an END:vCard), multiple vCards can be concatenated into a single directory info object. They may or may not be related. For example, AddressBook.app (the OS X contact manager) will export multiple selected cards in this format.
Input data will be converted from unicode if it is detected. The heuristic is based on the first bytes in the string:
-
0xEF 0xBB 0xBF: UTF-8 with a BOM, the BOM is stripped
-
0xFE 0xFF: UTF-16 with a BOM (big-endian), the BOM is stripped and string is converted to UTF-8
-
0xFF 0xFE: UTF-16 with a BOM (little-endian), the BOM is stripped and string is converted to UTF-8
-
0x00 'B' or 0x00 'b': UTF-16 (big-endian), the string is converted to UTF-8
-
'B' 0x00 or 'b' 0x00: UTF-16 (little-endian), the string is converted to UTF-8
If you know that you have only one vCard, then you can decode that single vCard by doing something like:
vcard = Vcard.decode(card_data).first
Note: Should the import encoding be remembered, so that it can be reencoded in the same format?
# File lib/vpim/vcard.rb, line 663 def Vcard.decode(card) if card.respond_to? :to_str string = card.to_str elsif card.respond_to? :read string = card.read(nil) else raise ArgumentError, "Vcard.decode cannot be called with a #{card.type}" end string.force_encoding "BINARY" case string when /^\xEF\xBB\xBF/ string = string.sub("\xEF\xBB\xBF", '') when /^\xFE\xFF/ arr = string.unpack('n*') arr.shift string = arr.pack('U*') when /^\xFF\xFE/ arr = string.unpack('v*') arr.shift string = arr.pack('U*') when /^\x00B/i string = string.unpack('n*').pack('U*') when /^B\x00/i string = string.unpack('v*').pack('U*') end string.force_encoding "utf-8" entities = Vpim.expand(Vpim.decode(string)) # Since all vCards must have a begin/end, the top-level should consist # entirely of entities/arrays, even if its a single vCard. if entities.detect { |e| ! e.kind_of? Array } raise "Not a valid vCard" end vcards = [] for e in entities vcards.push(new(e.flatten, 'VCARD')) end vcards end
Public Instance Methods
The value of the field named name
, optionally limited to
fields of type type
. If no match is found, nil is returned, if
multiple matches are found, the first match to have one of its type values
be 'PREF' (preferred) is returned, otherwise the first match is
returned.
FIXME - this will become an alias for value.
# File lib/vpim/vcard.rb, line 716 def [](name, type=nil) fields = enum_by_name(name).find_all { |f| type == nil || f.type?(type) } valued = fields.select { |f| f.value != '' } if valued.first fields = valued end # limit to preferred, if possible pref = fields.select { |f| f.pref? } if pref.first fields = pref end fields.first ? fields.first.value : nil end
The CATEGORIES values, an array of String. A wrapper around value('CATEGORIES').
# File lib/vpim/vcard.rb, line 830 def categories value('CATEGORIES') end
The GEO value, an Array of two Floats, +[ latitude, longitude]+. North of the equator is positive latitude, east of the meridian is positive longitude. See RFC2445 for more info, there are lots of special cases and RFC2445's description is more complete thant RFC2426.
# File lib/vpim/vcard.rb, line 851 def geo value('GEO') end
Return an Array of KEY Vpim::Vcard::Line#value, or yield each Vpim::Vcard::Line#value if a block is given. A wrapper around values('KEY').
KEY is a public key or authentication certificate associated with the object that the vCard represents. It is not commonly used, but could contain a X.509 or PGP certificate.
See Attachment for a description of the value.
# File lib/vpim/vcard.rb, line 863 def keys(&proc) #:yield: Line.value values('KEY', &proc) end
With no block, returns an Array of Line. If
name
is specified, the Array will only contain the +Line+s
with that name
. The Array may be empty.
If a block is given, each Line will be yielded instead of being returned in an Array.
# File lib/vpim/vcard.rb, line 599 def lines(name=nil) #:yield: Line # FIXME - this would be much easier if #lines was #each, and there was a # different #lines that returned an Enumerator that used #each unless block_given? map do |f| if( !name || f.name?(name) ) f2l(f) else nil end end.compact else each do |f| if( !name || f.name?(name) ) line = f2l(f) if line yield line end end end self end end
Return an Array of LOGO Vpim::Vcard::Line#value, or yield each Vpim::Vcard::Line#value if a block is given. A wrapper around values('LOGO').
LOGO is a graphic image of a logo associated with the object the vCard represents. Its not common, but would probably be equivalent to the logo on a printed card.
See Attachment for a description of the value.
# File lib/vpim/vcard.rb, line 875 def logos(&proc) #:yield: Line.value values('LOGO', &proc) end
Make changes to a vCard.
Yields a Vpim::Vcard::Maker that can be used to modify this vCard.
# File lib/vpim/vcard.rb, line 998 def make #:yield: maker Vpim::Vcard::Maker.make2(self) do |maker| yield maker end end
The N and FN as a Name object.
N is required for a vCards, this raises InvalidEncodingError if there is no N so it cannot return nil.
# File lib/vpim/vcard.rb, line 885 def name value('N') || raise(Vpim::InvalidEncodingError, "Missing mandatory N field") end
The first NICKNAME value, nil if there are none.
# File lib/vpim/vcard.rb, line 890 def nickname v = value('NICKNAME') v = v.first if v v end
The NICKNAME values, an array of String. The array may be empty.
# File lib/vpim/vcard.rb, line 897 def nicknames values('NICKNAME').flatten.uniq end
The NOTE value, a String. A wrapper around value('NOTE').
# File lib/vpim/vcard.rb, line 902 def note value('NOTE') end
The ORG value, an Array of String. The first string is the organization, subsequent strings are departments within the organization. A wrapper around value('ORG').
# File lib/vpim/vcard.rb, line 909 def org value('ORG') end
Return an Array of PHOTO Vpim::Vcard::Line#value, or yield each Vpim::Vcard::Line#value if a block is given. A wrapper around values('PHOTO').
PHOTO is an image or photograph information that annotates some aspect of the object the vCard represents. Commonly there is one PHOTO, and it is a photo of the person identified by the vCard.
See Attachment for a description of the value.
# File lib/vpim/vcard.rb, line 921 def photos(&proc) #:yield: Line.value values('PHOTO', &proc) end
Return an Array of SOUND Vpim::Vcard::Line#value, or yield each Vpim::Vcard::Line#value if a block is given. A wrapper around values('SOUND').
SOUND is digital sound content information that annotates some aspect of the vCard. By default this type is used to specify the proper pronunciation of the name associated with the vCard. It is not commonly used. Also, note that there is no mechanism available to specify that the SOUND is being used for anything other than the default.
See Attachment for a description of the value.
# File lib/vpim/vcard.rb, line 943 def sounds(&proc) #:yield: Line.value values('SOUND', &proc) end
The TITLE value, a text string specifying the job title, functional position, or function of the object the card represents. A wrapper around value('TITLE').
# File lib/vpim/vcard.rb, line 965 def title value('TITLE') end
The URL value, a Attachment::Uri. A wrapper around value('URL').
# File lib/vpim/vcard.rb, line 972 def url value('URL') end
The URL values, an Attachment::Uri. A wrapper around values('URL').
# File lib/vpim/vcard.rb, line 977 def urls values('URL') end
Return the Vpim::Vcard::Line#value for a
specific name
, and optionally for a specific
type
.
If no line with the name
(and, optionally, type
)
exists, nil is returned.
If multiple lines exist, the order of preference is:
-
lines with values over lines without
-
lines with a type of 'pref' over lines without
If multiple lines are equally preferred, then the first line will be returned.
This is most useful when looking for a line that can not occur multiple times, or when the line can occur multiple times, and you want to pick the first preferred line of a specific type. See values if you need to access all the lines.
Note that the type
field parameter is used for different
purposes by the various kinds of vCard lines, but for the addressing lines
(ADR, LABEL, TEL, EMAIL) it is has a reasonably consistent usage. Each
addressing line can occur multiple times, and a type
of
'pref' indicates that a particular line is the preferred line.
Other type
values tend to indicate some information about the
location ('home', 'work', …) or some detail about the
address ('cell', 'fax', 'voice', …). See the
methods for the specific types of line for information about supported
types and their meaning.
# File lib/vpim/vcard.rb, line 760 def value(name, type = nil) v = nil fields = enum_by_name(name).find_all { |f| type == nil || f.type?(type) } valued = fields.select { |f| f.value != '' } if valued.first fields = valued end pref = fields.select { |f| f.pref? } if pref.first fields = pref end if fields.first line = begin Line.decode(@@decode, self, fields.first) rescue Vpim::InvalidEncodingError end if line return line.value end end nil end
A variant of lines that only iterates over specific Line names. Since the name is known, only the Vpim::Vcard::Line#value is returned or yielded.
# File lib/vpim/vcard.rb, line 792 def values(name) unless block_given? lines(name).map { |line| line.value } else lines(name) { |line| yield line.value } end end
The VERSION multiplied by 10 as an Integer. For example, a VERSION:2.1 vCard would have a version of 21, and a VERSION:3.0 vCard would have a version of 30.
VERSION is required for a vCard, this raises InvalidEncodingError if there is no VERSION so it cannot return nil.
# File lib/vpim/vcard.rb, line 987 def version v = value('VERSION') unless v raise Vpim::InvalidEncodingError, 'Invalid vCard - it has no version field!' end v end