Class: Virginity::Vcard
Overview
rfc 2426, vCard MIME Directory Profile
Defined Under Namespace
Modules: Patching
Classes: NameHandler
Constant Summary
collapse
- EMPTY =
"BEGIN:VCARD\nN:;;;;\nVERSION:3.0\nEND:VCARD\n"
- VCARD_REGEX =
/^[\ \t]*VCARD[\ \t]*$/i
- VERSION21 =
/^VERSION\:2\.1(\s*)$/i
- END_VCARD =
/^END\:VCARD\s*$/i
- CRLF =
a vCard 2.1 string representation of this vCard if :windows_line_endings => true then lines end with rn otherwise with n
"\r\n"
- IGNORE_IN_SUBSET_COMPARISON =
are all fields also present or supersets in other?
%w(BEGIN END FN)
- SINGLETON_FIELDS =
%w(N FN BEGIN END VERSION)
- ADR =
"ADR"
- BDAY =
"BDAY"
- CATEGORIES =
"CATEGORIES"
- EMAIL =
"EMAIL"
- IMPP =
"IMPP"
- LOGO =
"LOGO"
- NICKNAME =
"NICKNAME"
- TEL =
"TEL"
- NOTE =
"NOTE"
- ORG =
"ORG"
- PHOTO =
"PHOTO"
- TITLE =
"TITLE"
- URL =
"URL"
- XABRELATEDNAMES =
"X-ABRELATEDNAMES"
- XABDATE =
"X-ABDATE"
- XANNIVERSARY =
"X-ANNIVERSARY"
Virginity::VcardCleaning::NAME, Virginity::VcardCleaning::RSTRIPPABLE_FIELDS, Virginity::VcardCleaning::VERSION, Virginity::VcardCleaning::VERSION30, Virginity::VcardCleaning::X_ABUID, Virginity::VcardCleaning::X_IRMC_LUID
DirectoryInformation::LF
Virginity::Vcard21::Reader::LATIN1, Virginity::Vcard21::Reader::UNSUPPORTED_CONTROL_CHARS
Constants included
from Query
Query::COLON, Query::COMMA, Query::EQUALS, Query::GROUP, Query::KEY, Query::NAME, Query::PARAM_NAME, Query::PARAM_VALUE, Query::SEMICOLON
Instance Attribute Summary
#lines
Class Method Summary
collapse
Instance Method Summary
collapse
Methods included from Encodings
#binary?, #to_ascii, #to_binary, #to_default, #to_default!, #verify_utf8ness
Methods included from Patching
#patch!
#add_category, #category_values, #in_category?, #remove_category, #tag, #tags, #tags=
#clean!, #clean_adrs!, #clean_categories!, #clean_dates!, #clean_multivalue_fields!, #clean_name!, #clean_orgs!, #clean_same_value_fields!, #clean_version!, #convert_custom_osx_field_to_param!, #convert_xabadrs_to_param!, #convert_xablabels_to_param!, #max_one_name!, #remove_duplicate_lines!, #remove_empty_fields!, #remove_extra_logos!, #remove_extra_photos!, #remove_singleton_groups!, #remove_subset_addresses!, #remove_subsets_of_structured_fields!, #remove_x_abuids!, #remove_x_irmc_luids!, #reset_empty_formatted_name!, #rstrip_text_fields!, #strip_structured_fields!, #unpack_categories!, #unpack_field!, #unpack_list!, #unpack_nicknames!
#==, #delete, #delete_content_line, #encode, #eql?, #pretty_print, #superset_of?, #unfolded
#convert_base64_to_b!, #convert_charsets!, #fix_vcard21_line!, #from_vcard21, #guess_charset!, #guess_charset_for_part!, #line21_parts, #lines_from_vcard21, #read_21_line, #reencode_quoted_printable!
Methods included from Query
decode_query, #find_first, #first_match, #line_matches_query?, #lines_with_name, params, #query, #where
Constructor Details
#initialize(lines = EMPTY, options = {}) ⇒ Vcard
Returns a new instance of Vcard.
Class Method Details
.diff(old, new) ⇒ Object
30
31
32
|
# File 'lib/virginity/vcard.rb', line 30
def self.diff(old, new)
Patching::diff(old, new)
end
|
.fields_from_broken_vcard(vcard_as_string) ⇒ Object
.fix_and_clean(vcard_as_string) ⇒ Object
NB. this only works for vCard 3.0, not for 2.1!
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
# File 'lib/virginity/fixes.rb', line 192
def self.fix_and_clean(vcard_as_string)
fixes ||= []
lines = fields_from_broken_vcard(vcard_as_string)
v = Virginity::Vcard.new(lines)
v.super_clean!
valid_utf8?(v)
v
rescue EncodingError
if !fixes.include?(:faulty_qp)
newcard = Fixes::fix_faulty_qp_chars(vcard_as_string)
fixes << :faulty_qp
elsif !fixes.include?(:guess_latin1)
newcard = Fixes::guess_latin1(lines)
fixes << :guess_latin1
else
File.open("illegal_sequence_#{vcard_as_string.hash}.vcf", "wb") do |f|
f.puts Virginity::Vcard.new(vcard_as_string).super_clean!
end
raise
end
vcard_as_string = newcard
retry
rescue Virginity::InvalidEncoding, Virginity::Vcard21::ParseError => e
if !fixes.include?(:fix_folding)
vcard_as_string = Fixes::unfold_wrongly_folded_lines(vcard_as_string)
fixes << :fix_folding
retry
elsif !fixes.include?(:weird_mac_16bit_encoding_that_is_not_utf16) && vcard_as_string.include?("\000")
vcard_as_string.gsub!("\000", "")
fixes << :weird_mac_16bit_encoding_that_is_not_utf16
retry
else
raise
end
end
|
.from_vcard(vcf, options = {}) ⇒ Object
77
78
79
|
# File 'lib/virginity/vcard.rb', line 77
def self.from_vcard(vcf, options = {})
parse(vcf, options)
end
|
.from_vcard21(vcf, options = {}) ⇒ Object
import vcard21 and convert it to 3.0
58
59
60
61
62
63
64
|
# File 'lib/virginity/vcard.rb', line 58
def self.from_vcard21(vcf, options = {})
verify_utf8ness vcf
vcard = new(lines_from_vcard21(vcf, options), options)
vcard.clean_version!
rescue => error
raise InvalidVcard, error.message
end
|
.list(vcf, options = {}) ⇒ Object
returns an array of Vcards for a string of concatenated vcards
103
104
105
106
107
|
# File 'lib/virginity/vcard.rb', line 103
def self.list(vcf, options = {})
vcards_in_list(vcf).map do |v|
from_vcard(v, options)
end
end
|
.load_all_from(filename, options = {}) ⇒ Object
81
82
83
|
# File 'lib/virginity/vcard.rb', line 81
def self.load_all_from(filename, options = {})
list(File.read(filename), options)
end
|
.parse(vcf, options = {}) ⇒ Object
67
68
69
70
71
72
73
74
75
|
# File 'lib/virginity/vcard.rb', line 67
def self.parse(vcf, options = {})
vcf = vcf.to_s
verify_utf8ness vcf
if vcf =~ VERSION21
from_vcard21(vcf, options)
else
new(vcf, options)
end
end
|
.valid_utf8?(v) ⇒ Boolean
181
182
183
184
185
186
187
188
189
|
# File 'lib/virginity/fixes.rb', line 181
def self.valid_utf8?(v)
if v.to_s.dup.force_encoding(Encoding::UTF_8).valid_encoding?
true
else
false
end
rescue EncodingError
return false
end
|
.vcards_in_list(vcf) ⇒ Object
split a given string of concatenated vcards to an array containing one vcard per element
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
# File 'lib/virginity/vcard.rb', line 87
def self.vcards_in_list(vcf)
s = StringScanner.new(vcf)
array = []
while !s.eos?
if v = s.scan_until(END_VCARD)
v.lstrip!
array << v
else
puts s.peek(100)
break
end
end
array
end
|
Instance Method Details
#<<(line) ⇒ Object
Also known as:
push
add a field, returns the vcard
136
137
138
139
|
# File 'lib/virginity/vcard.rb', line 136
def <<(line)
add_field(line)
self
end
|
#add(name) ⇒ Object
183
184
185
186
187
|
# File 'lib/virginity/vcard.rb', line 183
def add(name)
add_field(name + ":") do |field|
yield field if block_given?
end
end
|
#add_email(address = nil) ⇒ Object
189
190
191
192
193
194
|
# File 'lib/virginity/vcard.rb', line 189
def add_email(address = nil)
add(EMAIL) do |email|
email.address = address.to_s
yield email if block_given?
end
end
|
#add_field(line) {|field| ... } ⇒ Object
add a field and return it if a block is given, then the new field is yielded so it can be changed
126
127
128
129
130
131
132
133
|
# File 'lib/virginity/vcard.rb', line 126
def add_field(line)
end_vcard = @lines.pop
raise InvalidVcard, "there is no last line? ('END:VCARD')" if end_vcard.nil?
@lines << (field = Field.parse(line))
@lines << end_vcard
yield field if block_given?
field
end
|
#add_telephone(number = nil) ⇒ Object
196
197
198
199
200
201
|
# File 'lib/virginity/vcard.rb', line 196
def add_telephone(number = nil)
add(TEL) do |tel|
tel.number = number.to_s
yield tel if block_given?
end
end
|
#addresses ⇒ Object
220
|
# File 'lib/virginity/vcard.rb', line 220
def addresses; lines_with_name(ADR); end
|
#anniversaries ⇒ Object
241
|
# File 'lib/virginity/vcard.rb', line 241
def anniversaries; lines_with_name(XANNIVERSARY); end
|
#assimilate_fields_from!(other) ⇒ Object
import all fields except N, FN, and VERSION from other (another Vcard) duplicate fields are deduped
174
175
176
177
178
179
180
181
|
# File 'lib/virginity/vcard.rb', line 174
def assimilate_fields_from!(other)
other.fields.each do |field|
next if SINGLETON_FIELDS.include? field.name.upcase
push(field)
end
clean_same_value_fields!
self
end
|
#birthdays ⇒ Object
221
|
# File 'lib/virginity/vcard.rb', line 221
def birthdays; lines_with_name(BDAY); end
|
#categories ⇒ Object
222
|
# File 'lib/virginity/vcard.rb', line 222
def categories; lines_with_name(CATEGORIES); end
|
#custom_im_fields ⇒ Object
234
|
# File 'lib/virginity/vcard.rb', line 234
def custom_im_fields; @lines.select{|line| line.is_a? Virginity::Vcard::CustomImField}; end
|
#dates ⇒ Object
239
|
# File 'lib/virginity/vcard.rb', line 239
def dates; lines_with_name(XABDATE); end
|
#deep_copy ⇒ Object
117
118
119
|
# File 'lib/virginity/vcard.rb', line 117
def deep_copy
Marshal::load(Marshal::dump(self))
end
|
#emails ⇒ Object
223
|
# File 'lib/virginity/vcard.rb', line 223
def emails; lines_with_name(EMAIL); end
|
#impps ⇒ Object
224
|
# File 'lib/virginity/vcard.rb', line 224
def impps; lines_with_name(IMPP); end
|
#inspect ⇒ Object
109
110
111
|
# File 'lib/virginity/vcard.rb', line 109
def inspect
super.chomp(">") + " name=" + name.to_s.inspect + ">"
end
|
#logos ⇒ Object
225
|
# File 'lib/virginity/vcard.rb', line 225
def logos; lines_with_name(LOGO); end
|
#name ⇒ Object
203
204
205
|
# File 'lib/virginity/vcard.rb', line 203
def name
@name ||= NameHandler.new(self)
end
|
#nicknames ⇒ Object
226
|
# File 'lib/virginity/vcard.rb', line 226
def nicknames; lines_with_name(NICKNAME); end
|
#notes ⇒ Object
228
|
# File 'lib/virginity/vcard.rb', line 228
def notes; lines_with_name(NOTE); end
|
#organizations ⇒ Object
Also known as:
organisations
229
|
# File 'lib/virginity/vcard.rb', line 229
def organizations; lines_with_name(ORG); end
|
#photos ⇒ Object
231
|
# File 'lib/virginity/vcard.rb', line 231
def photos; lines_with_name(PHOTO); end
|
237
|
# File 'lib/virginity/vcard.rb', line 237
def related_names; lines_with_name(XABRELATEDNAMES); end
|
#subset_of?(other) ⇒ Boolean
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
|
# File 'lib/virginity/vcard.rb', line 152
def subset_of?(other)
fields.all? do |field|
if IGNORE_IN_SUBSET_COMPARISON.include?(field.name)
true
else
other.lines_with_name(field.name).any? do |f|
begin
f.raw_value == field.raw_value or field.subset_of?(f)
rescue NoMethodError
false
end
end
end
end
end
|
#telephones ⇒ Object
227
|
# File 'lib/virginity/vcard.rb', line 227
def telephones; lines_with_name(TEL); end
|
#titles ⇒ Object
232
|
# File 'lib/virginity/vcard.rb', line 232
def titles; lines_with_name(TITLE); end
|
#to_vcard21(options = {}) ⇒ Object
145
146
147
148
|
# File 'lib/virginity/vcard.rb', line 145
def to_vcard21(options = {})
line_ending = options[:windows_line_endings] ? CRLF : LF
fields.map { |field| field.encode21(options) }.join(line_ending)
end
|
#urls ⇒ Object
233
|
# File 'lib/virginity/vcard.rb', line 233
def urls; lines_with_name(URL); end
|