vpim-rails-reinteractive 0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/CHANGES +504 -0
  2. data/COPYING +58 -0
  3. data/README +182 -0
  4. data/lib/atom.rb +728 -0
  5. data/lib/plist.rb +22 -0
  6. data/lib/vpim.rb +13 -0
  7. data/lib/vpim/address.rb +219 -0
  8. data/lib/vpim/attachment.rb +102 -0
  9. data/lib/vpim/date.rb +222 -0
  10. data/lib/vpim/dirinfo.rb +277 -0
  11. data/lib/vpim/duration.rb +119 -0
  12. data/lib/vpim/enumerator.rb +32 -0
  13. data/lib/vpim/field.rb +614 -0
  14. data/lib/vpim/icalendar.rb +386 -0
  15. data/lib/vpim/maker/vcard.rb +16 -0
  16. data/lib/vpim/property/base.rb +193 -0
  17. data/lib/vpim/property/common.rb +315 -0
  18. data/lib/vpim/property/location.rb +38 -0
  19. data/lib/vpim/property/priority.rb +43 -0
  20. data/lib/vpim/property/recurrence.rb +69 -0
  21. data/lib/vpim/property/resources.rb +24 -0
  22. data/lib/vpim/repo.rb +181 -0
  23. data/lib/vpim/rfc2425.rb +372 -0
  24. data/lib/vpim/rrule.rb +598 -0
  25. data/lib/vpim/vcard.rb +1429 -0
  26. data/lib/vpim/version.rb +18 -0
  27. data/lib/vpim/vevent.rb +187 -0
  28. data/lib/vpim/view.rb +90 -0
  29. data/lib/vpim/vjournal.rb +58 -0
  30. data/lib/vpim/vpim.rb +65 -0
  31. data/lib/vpim/vtodo.rb +103 -0
  32. data/samples/README.mutt +93 -0
  33. data/samples/ab-query.rb +57 -0
  34. data/samples/cmd-itip.rb +156 -0
  35. data/samples/ex_cpvcard.rb +55 -0
  36. data/samples/ex_get_vcard_photo.rb +22 -0
  37. data/samples/ex_mkv21vcard.rb +34 -0
  38. data/samples/ex_mkvcard.rb +64 -0
  39. data/samples/ex_mkyourown.rb +29 -0
  40. data/samples/ics-dump.rb +210 -0
  41. data/samples/ics-to-rss.rb +84 -0
  42. data/samples/mutt-aliases-to-vcf.rb +45 -0
  43. data/samples/osx-wrappers.rb +86 -0
  44. data/samples/reminder.rb +203 -0
  45. data/samples/rrule.rb +71 -0
  46. data/samples/tabbed-file-to-vcf.rb +390 -0
  47. data/samples/vcf-dump.rb +86 -0
  48. data/samples/vcf-lines.rb +61 -0
  49. data/samples/vcf-to-ics.rb +22 -0
  50. data/samples/vcf-to-mutt.rb +121 -0
  51. data/test/test_all.rb +17 -0
  52. data/test/test_date.rb +120 -0
  53. data/test/test_dur.rb +41 -0
  54. data/test/test_field.rb +156 -0
  55. data/test/test_ical.rb +415 -0
  56. data/test/test_repo.rb +158 -0
  57. data/test/test_rrule.rb +1030 -0
  58. data/test/test_vcard.rb +973 -0
  59. data/test/test_view.rb +79 -0
  60. metadata +135 -0
@@ -0,0 +1,203 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $-w = true
4
+
5
+ require 'ubygems' rescue "ignored"
6
+
7
+ require 'getoptlong'
8
+ require 'pp'
9
+ require 'plist'
10
+
11
+ require 'vpim/repo'
12
+
13
+ $stdout.sync = true
14
+ $stderr.sync = true
15
+
16
+ HELP =<<EOF
17
+ Usage: #{$0} [where]
18
+
19
+ Shows events and todos occuring soon.
20
+
21
+ By default, the Apple iCal v3 calendars are used, but if a location where
22
+ .ics files is specified, any calendars found there will be used.
23
+
24
+ Options
25
+ -h,--help Print this helpful message.
26
+ -n,--days N How many of the next days are considered to be "soon", default
27
+ is seven.
28
+ -v,--verbose Print more information about upcoming events.
29
+ EOF
30
+
31
+ opt_debug = nil
32
+ opt_verbose = nil
33
+ opt_days = 7
34
+
35
+ opts = GetoptLong.new(
36
+ [ "--help", "-h", GetoptLong::NO_ARGUMENT ],
37
+ [ "--days", "-n", GetoptLong::REQUIRED_ARGUMENT ],
38
+ [ "--verbose", "-v", GetoptLong::NO_ARGUMENT ],
39
+ [ "--debug", "-d", GetoptLong::NO_ARGUMENT ]
40
+ )
41
+
42
+ opts.each do |opt, arg|
43
+ case opt
44
+ when "--help" then
45
+ puts HELP
46
+ exit 0
47
+
48
+ when "--days" then
49
+ opt_days = arg.to_i
50
+
51
+ when "--verbose" then
52
+ opt_verbose = true
53
+
54
+ when "--debug" then
55
+ opt_verbose = true
56
+ opt_debug = true
57
+ end
58
+ end
59
+
60
+ calendars = []
61
+
62
+ if ARGV.length > 0
63
+ Vpim::Repo::Directory.each(ARGV.first) do |cal|
64
+ calendars << cal
65
+ end
66
+ else
67
+ Vpim::Repo::Ical3.each() do |cal|
68
+ calendars << cal
69
+ end
70
+ end
71
+
72
+ if opt_debug
73
+ pp ARGV
74
+ pp calendars
75
+ end
76
+
77
+ SECSPERDAY = (24 * 60 * 60)
78
+
79
+ t0 = Time.new.to_a
80
+ t0[0] = t0[1] = t0[2] = 0 # sec,min,hour = 0
81
+ t0 = Time.zone.local(*t0)
82
+ t1 = t0 + opt_days * SECSPERDAY
83
+
84
+ if opt_debug
85
+ puts "to: #{t0}"
86
+ puts "t1: #{t1}"
87
+ end
88
+
89
+ if opt_verbose
90
+ puts "Events in the next #{opt_days} days:"
91
+ end
92
+
93
+ # Collect all events, then all todos.
94
+ all_events = []
95
+ all_todos = []
96
+
97
+ calendars.each do |cal|
98
+ if opt_debug; puts cal.name; end
99
+
100
+ begin
101
+ cal.events.each do |e|
102
+ begin
103
+ if opt_debug; pp e; end
104
+ if e.occurs_in?(t0, t1)
105
+ if e.summary
106
+ all_events.push(e)
107
+ end
108
+ end
109
+ rescue
110
+ $stderr.puts "error in #{cal.name} (\"#{e.summary}\"): #{$!.to_s}"
111
+ end
112
+ end
113
+
114
+ all_todos.concat(cal.todos)
115
+ end
116
+ end
117
+
118
+ puts
119
+
120
+ def start_of_first_occurrence(t0, t1, e)
121
+ e.occurrences(t1) do |t|
122
+ # An event might start before t0, but end after it..., in which case
123
+ # we are still interested.
124
+ if (t + (e.duration || 0)) >= t0
125
+ return t
126
+ end
127
+ end
128
+ nil
129
+ end
130
+
131
+ all_events.sort! do |lhs, rhs|
132
+ start_of_first_occurrence(t0, t1, lhs) <=> start_of_first_occurrence(t0, t1, rhs)
133
+ end
134
+
135
+ all_events.each do |e|
136
+ puts "#{e.summary}:"
137
+
138
+ if opt_verbose
139
+ if e.description; puts " description=#{e.description}"; end
140
+ if e.comments; puts " comment=#{e.comments.first}"; end
141
+ if e.location; puts " location=#{e.location}"; end
142
+ if e.status; puts " status=#{e.status}"; end
143
+ if e.dtstart; puts " dtstart=#{e.dtstart}"; end
144
+ if e.duration; puts " duration=#{Vpim::Duration.new(e.duration).to_s}"; end
145
+ end
146
+
147
+ i = 1
148
+ e.occurrences.each_until(t1).each do |t|
149
+ # An event might start before t0, but end after it..., in which case
150
+ # we are still interested.
151
+ dstr = ''
152
+ if e.duration
153
+ d = e.duration
154
+ dstr = " for #{Vpim::Duration.new(e.duration).to_s}"
155
+ end
156
+
157
+ if (t + (e.duration || 0)) >= t0
158
+ puts " ##{i} on #{t}#{dstr}"
159
+ i += 1
160
+ end
161
+ end
162
+ end
163
+
164
+ =begin
165
+ def fix_priority(vtodo)
166
+ p = vtodo.priority
167
+ if !p
168
+ p = 10
169
+
170
+ end
171
+ =end
172
+
173
+ all_todos.sort! do |x,y|
174
+ x = x.priority
175
+ y = y.priority
176
+
177
+ # 0 means no priority, put these last, not first
178
+ x = 10 if x == 0
179
+ y = 10 if y == 0
180
+
181
+ x <=> y
182
+ end
183
+
184
+ priorities = [
185
+ 'no importance',
186
+ 'very important',
187
+ 'very important',
188
+ 'very important',
189
+ 'important',
190
+ 'important',
191
+ 'important',
192
+ 'not important',
193
+ 'not important',
194
+ 'not important'
195
+ ]
196
+
197
+ all_todos.each do |e|
198
+ status = e.status || 'Todo'
199
+ if status != 'COMPLETED'
200
+ puts "#{status.capitalize}: #{e.summary}" # (#{priorities[e.priority]})"
201
+ end
202
+ end
203
+
data/samples/rrule.rb ADDED
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $-w = true
4
+ $:.unshift File.dirname($0) + "/../lib"
5
+
6
+ require 'vpim/rrule'
7
+ require 'getoptlong'
8
+ require 'parsedate'
9
+
10
+ HELP =<<EOF
11
+ Usage: #{$0} [options] rrule
12
+
13
+ Options
14
+ -h,--help Print this helpful message.
15
+ -t,--start Start time for recurrence rule, defaults to current time.
16
+
17
+ Examples:
18
+
19
+ FREQ=DAILY;COUNT=10
20
+ FREQ=DAILY;UNTIL=19971224T000000Z
21
+ FREQ=DAILY;INTERVAL=2
22
+ FREQ=DAILY;INTERVAL=10;COUNT=5
23
+
24
+ Demonstrate DST time change:
25
+
26
+ #{$0} --start '2004-04-03 02:00' 'FREQ=daily;count=3'
27
+ #{$0} --start '2004-10-30 02:00' 'FREQ=daily;count=3'
28
+
29
+ Note: In the US DST starts at 2AM, on the first Sunday of April, and reverts
30
+ at 2AM on the last Sunday of October.
31
+
32
+ EOF
33
+
34
+ dtstart = Time.new
35
+
36
+ opts = GetoptLong.new(
37
+ [ "--help", "-h", GetoptLong::NO_ARGUMENT ],
38
+ [ "--start", "-t", GetoptLong::REQUIRED_ARGUMENT]
39
+ )
40
+
41
+ opts.each do |opt, arg|
42
+ case opt
43
+ when "--help" then
44
+ puts HELP
45
+ exit 0
46
+
47
+ when "--start" then
48
+ date = ParseDate.parsedate(arg)
49
+ date.pop
50
+ date.pop
51
+ dtstart = Time.zone.local(*date)
52
+ end
53
+ end
54
+
55
+ if ARGV.length < 1
56
+ puts "no rrule specified, try -h!\n"
57
+ exit 1
58
+ end
59
+
60
+ puts "Start: #{Vpim.encode_date_time(dtstart)}"
61
+
62
+ ARGV.each do |rule|
63
+ rrule = Vpim::Rrule.new(dtstart, rule)
64
+
65
+ puts "Rule: #{rule}"
66
+
67
+ rrule.each_with_index do |t, count|
68
+ puts format("count=%3d %s", count, t.to_s)
69
+ end
70
+ end
71
+
@@ -0,0 +1,390 @@
1
+ #
2
+ # Filename: tabbed_file_to_vcards.rb
3
+ # Author: Dane G. Avilla
4
+ # Description:
5
+ # This script takes a tab-delimited text file with address info and attempts
6
+ # to parse each
7
+ # line of the file into a VCard.
8
+ #
9
+ # Usage: ruby tabbed_file_to_vcards.rb ./contacts.txt > vcards.vcf
10
+ #
11
+ # This command will create vcards and save them into vcards.vcf.
12
+ #
13
+ # License: Same as Ruby.
14
+ #
15
+
16
+ require 'vpim/vcard'
17
+
18
+ #
19
+ # Opens a file and attempts to parse out vcards. It is meant to work on a
20
+ # tab-delimited file with column names in the first line, followed by
21
+ # any number of records on the following lines.
22
+ #
23
+ class VCardParser
24
+
25
+ #
26
+ # Pass in a filename as a string, and get an array of VCard objects back.
27
+ #
28
+ def vcards_from_txt_file(filename)
29
+ #puts "Parsing input file #{filename}"
30
+ vcards = []
31
+ first_line = true
32
+ VCardField.reset_custom_fields
33
+ IO.foreach(filename) { |line|
34
+ #puts "Parsing line: #{line}"
35
+ if first_line == true
36
+ @headers = headers_from_line(line)
37
+ first_line = false
38
+ else
39
+ vcards << vcard_from_line(line)
40
+ end
41
+ }
42
+ vcards
43
+ end
44
+
45
+ protected
46
+ def headers_from_line(a_line)
47
+ a_line.upcase.split("\t")
48
+ end
49
+
50
+ def fields_from_line(a_line)
51
+ field_arr = headers_from_line(a_line)
52
+ fields = {}
53
+ @headers.each_index { |index|
54
+ fields[@headers[index]]= field_arr[index]
55
+ }
56
+ fields
57
+ end
58
+
59
+ def vcard_from_line(a_line)
60
+ #puts "vcard_from_line"
61
+ # Parse the line from a tab-delimited text file.
62
+ # The tricky part is that there may
63
+ # be fields in the txt file which have commas between opening and closing
64
+ # quotes, so don't just split on ','.
65
+
66
+ # Get a hash of field names and values
67
+ fields = fields_from_line(a_line)
68
+ #puts "FirstName: " + fields["FIRST_NAME"]
69
+ # 1. Look for the pattern /\".*,.*\"/
70
+ # 2. If found, save that pattern, and then substitute it with a
71
+ # dynamic placeholder.
72
+
73
+ # 3. Split the line on commas.
74
+
75
+ # 4. For each item in the split, replace the substituted pattern
76
+ # with the source pattern.
77
+
78
+ #p fields
79
+
80
+ # At this point, we should have an array of string values matching
81
+ # the order of @headers. Construct a VCard using the header keys and
82
+ # the parsed values
83
+ vcard = Vpim::Vcard.create
84
+
85
+ # Add the name field
86
+ vcard << VCardField.create_n(fields["LAST_NAME"], fields["FIRST_NAME"],
87
+ fields["MIDDLE_NAME"], fields["TITLE"], fields["SUFFIX"])
88
+ # Add the formal name display field
89
+ vcard << VCardField.create_fn(fields["LAST_NAME"], fields["FIRST_NAME"],
90
+ fields["MIDDLE_NAME"], fields["TITLE"], fields["SUFFIX"])
91
+ # Add Company & Department info
92
+ vcard << VCardField.create_org(fields["COMPANY"], fields["DEPARTMENT"])
93
+ # Add Job Title info
94
+ vcard << VCardField.create_job_title(fields["JOB_TITLE"])
95
+ # Add Phone Numbers
96
+ vcard << VCardField.create_work_fax(fields["BUSINESS_FAX"])
97
+ vcard << VCardField.create_work_phone(fields["BUSINESS_PHONE"])
98
+ vcard << VCardField.create_work_phone(fields["BUSINESS_PHONE_2"])
99
+ vcard << VCardField.create_home_fax(fields["HOME_FAX"])
100
+ vcard << VCardField.create_home_phone(fields["HOME_PHONE"])
101
+ vcard << VCardField.create_home_phone(fields["HOME_PHONE_2"])
102
+ vcard << VCardField.create_cell_phone(fields["MOBILE_PHONE"])
103
+ vcard << VCardField.create_pager(fields["PAGER"])
104
+ vcard << VCardField.create_custom_phone(fields["OTHER_PHONE"], "other")
105
+ # Add Business Address
106
+ vcard << VCardField.create_business_address(
107
+ fields["BUSINESS_STREET"],
108
+ fields["BUSINESS_STREET_2"],
109
+ fields["BUSINESS_STREET_3"],
110
+ fields["BUSINESS_CITY"],
111
+ fields["BUSINESS_STATE"],
112
+ fields["BUSINESS_POSTAL_CODE"],
113
+ fields["BUSINESS_COUNTRY"]
114
+ )
115
+ # Add Home Address
116
+ vcard << VCardField.create_home_address(
117
+ fields["HOME_STREET"],
118
+ fields["HOME_STREET_2"],
119
+ fields["HOME_STREET_3"],
120
+ fields["HOME_CITY"],
121
+ fields["HOME_STATE"],
122
+ fields["HOME_POSTAL_CODE"],
123
+ fields["HOME_COUNTRY"]
124
+ )
125
+ # Add Other Address
126
+ vcard << VCardField.create_other_address(
127
+ "Sample Other Address",
128
+ fields["OTHER_STREET"],
129
+ fields["OTHER_STREET_2"],
130
+ fields["OTHER_STREET_3"],
131
+ fields["OTHER_CITY"],
132
+ fields["OTHER_STATE"],
133
+ fields["OTHER_POSTAL_CODE"],
134
+ fields["OTHER_COUNTRY"]
135
+ )
136
+
137
+ # Add Emails
138
+ vcard << VCardField.create_work_email(fields["E-MAIL_ADDRESS"])
139
+ vcard << VCardField.create_home_email(fields["E-MAIL_2_ADDRESS"])
140
+ vcard << VCardField.create_other_email(fields["E-MAIL_3_ADDRESS"], "other")
141
+
142
+ # Add a note
143
+ vcard << VCardField.create_note(fields["NOTES"])
144
+
145
+ vcard
146
+ end
147
+ end
148
+
149
+ #
150
+ # Subclass of Vpim::DirectoryInfo::Field adds a number of helpful methods for
151
+ # creating VCard fields.
152
+ #
153
+ class VCardField < Vpim::DirectoryInfo::Field
154
+ def VCardField.reset_custom_fields
155
+ @@custom_number = 1
156
+ end
157
+
158
+ #
159
+ # Create a name field: "N"
160
+ #
161
+ def VCardField.create_n (last, first=nil, middle=nil, prefix=nil, suffix=nil)
162
+ VCardField.create('N', "#{last};#{first};#{middle};#{prefix};#{suffix}")
163
+ end
164
+
165
+ protected
166
+ def VCardField.valid_string(a_str)
167
+ return a_str != nil && a_str.length > 0
168
+ end
169
+
170
+ public
171
+
172
+ #
173
+ # Create a formal name field: "FN"
174
+ #
175
+ def VCardField.create_fn (last, first=nil, middle=nil, prefix=nil, suffix=nil)
176
+ name = ""
177
+ if valid_string(prefix) then name << "#{prefix} " end
178
+ if valid_string(first) then name << "#{first} " end
179
+ if valid_string(middle) then name << "#{middle} " end
180
+ if valid_string(last) then name << "#{last} " end
181
+ if valid_string(suffix) then name << "#{suffix} " end
182
+ VCardField.create('FN', "#{name}")
183
+ end
184
+
185
+ #
186
+ # Create a formal name field: "ORG"
187
+ #
188
+ def VCardField.create_org (organization_name, department_name=nil)
189
+ VCardField.create("ORG", "#{organization_name};#{department_name}")
190
+ end
191
+
192
+ #
193
+ # Create a title field: "TITLE"
194
+ #
195
+ def VCardField.create_job_title(title)
196
+ VCardField.create("TITLE", title)
197
+ end
198
+
199
+ #
200
+ # Create an email field: "EMAIL" with type="INTERNET"
201
+ #
202
+ # For _type_, use Ruby symbols :WORK or :HOME.
203
+ #
204
+ def VCardField.create_internet_email(address, type=:WORK, preferred_email=false)
205
+ if preferred_email == true
206
+ VCardField.create("EMAIL", address,
207
+ "type" => ["INTERNET", type.to_s, "pref"])
208
+ else
209
+ VCardField.create("EMAIL", address,
210
+ "type" => ["INTERNET", type.to_s])
211
+ end
212
+ end
213
+
214
+ protected
215
+ def VCardField.next_custom_name
216
+ name = "item#{@@custom_number}"
217
+ @@custom_number = @@custom_number + 1
218
+ name
219
+ end
220
+
221
+ def VCardField.create_phone(phone_num, is_preferred = false, type_arr = ["WORK"],
222
+ custom_name = nil)
223
+
224
+ field_name = ""
225
+ if custom_name != nil
226
+ field_name << next_custom_name
227
+ field_name << "."
228
+ end
229
+
230
+ # Flatten the array so we can add additional items to it.
231
+ type_arr = [type_arr].flatten
232
+ # If this phone number is preferred, then add that into the type array.
233
+ if is_preferred
234
+ type_arr << "pref"
235
+ end
236
+ # Create the TEL field.
237
+ ret_val = [VCardField.create("#{field_name}TEL", phone_num, "type" => type_arr)]
238
+ # If we need a custom field . . .
239
+ if custom_name != nil
240
+ ret_val << VCardField.create("#{field_name}X-ABLabel", custom_name)
241
+ end
242
+ ret_val
243
+ end
244
+
245
+ public
246
+ def VCardField.create_note(note_text)
247
+ VCardField.create("NOTE", note_text)
248
+ end
249
+
250
+ def VCardField.create_custom_phone(phone_number, custom_name, is_preferred = false)
251
+ VCardField.create_phone(phone_number, is_preferred, ["HOME"], custom_name)
252
+ end
253
+
254
+ def VCardField.create_pager(pager_number, is_preferred = false)
255
+ VCardField.create_phone(pager_number, is_preferred, ["PAGER"])
256
+ end
257
+
258
+ def VCardField.create_work_fax(fax_number, is_preferred = false)
259
+ VCardField.create_phone(fax_number, is_preferred, ["FAX", "WORK"])
260
+ end
261
+
262
+ def VCardField.create_work_phone(phone_number, is_preferred = false)
263
+ VCardField.create_phone(phone_number, is_preferred, ["WORK"])
264
+ end
265
+
266
+ def VCardField.create_home_fax(fax_number, is_preferred = false)
267
+ VCardField.create_phone(fax_number, is_preferred, ["FAX", "HOME"])
268
+ end
269
+
270
+ def VCardField.create_home_phone(phone_number, is_preferred = false)
271
+ VCardField.create_phone(phone_number, is_preferred, ["HOME"])
272
+ end
273
+
274
+ def VCardField.create_cell_phone(phone_number, is_preferred = false)
275
+ VCardField.create_phone(phone_number, is_preferred, ["CELL"])
276
+ end
277
+
278
+ def VCardField.create_other_address(
279
+ address_label,
280
+ street,
281
+ street2 = "",
282
+ street3 = "",
283
+ city = "",
284
+ state = "",
285
+ postal_code = "",
286
+ country = "",
287
+ is_preferred = false
288
+ )
289
+ VCardField.create_address(street, street2, street3, city, state,
290
+ postal_code, country, is_preferred, ["HOME"], address_label)
291
+ end
292
+
293
+ def VCardField.create_home_address(
294
+ street,
295
+ street2 = "",
296
+ street3 = "",
297
+ city = "",
298
+ state = "",
299
+ postal_code = "",
300
+ country = "",
301
+ is_preferred = false
302
+ )
303
+ VCardField.create_address(street, street2, street3, city, state,
304
+ postal_code, country, is_preferred, ["HOME"])
305
+ end
306
+
307
+ def VCardField.create_business_address(
308
+ street,
309
+ street2 = "",
310
+ street3 = "",
311
+ city = "",
312
+ state = "",
313
+ postal_code = "",
314
+ country = "",
315
+ is_preferred = false
316
+ )
317
+ VCardField.create_address(street, street2, street3, city, state,
318
+ postal_code, country, is_preferred, ["WORK"])
319
+ end
320
+
321
+ def VCardField.create_work_email(address, is_preferred = false)
322
+ VCardField.create_email(address, is_preferred, ["WORK"])
323
+ end
324
+
325
+ def VCardField.create_home_email(address, is_preferred = false)
326
+ VCardField.create_email(address, is_preferred, ["HOME"])
327
+ end
328
+
329
+ def VCardField.create_other_email(address, custom_name, is_preferred = false)
330
+ VCardField.create_email(address, is_preferred, ["WORK"], custom_name)
331
+ end
332
+
333
+ protected
334
+ def VCardField.create_email(address, is_preferred, type_arr = ["WORK"], custom_name = nil)
335
+ name = ""
336
+ if custom_name != nil
337
+ name << next_custom_name
338
+ name << "."
339
+ end
340
+ if is_preferred
341
+ type_arr << "pref"
342
+ end
343
+ ret_val = [VCardField.create("#{name}EMAIL", address, "type" => type_arr)]
344
+ if custom_name != nil
345
+ ret_val << VCardField.create("#{name}X-ABLabel", custom_name)
346
+ end
347
+ ret_val
348
+ end
349
+
350
+ def VCardField.create_address(
351
+ street,
352
+ street2 = "",
353
+ street3 = "",
354
+ city = "",
355
+ state = "",
356
+ postal_code = "",
357
+ country = "",
358
+ is_preferred = false,
359
+ type_arr = ["WORK"],
360
+ other_label = nil)
361
+ # Addresses need custom names, so get the next custom name for this
362
+ # VCard
363
+ name = next_custom_name
364
+ # Construct the address string by making an array of the fields, and
365
+ # then joining them with ';' as the separator.
366
+ address_str = [street, street2, street3, city, state, postal_code, country]
367
+ # If this is preferred, add that type.
368
+ if is_preferred
369
+ type_arr << "pref"
370
+ end
371
+ # Return an array with two lines, one defining the address, the second
372
+ # defining something else . . . is this the locale? Not sure, but this
373
+ # is how Mac OS X 10.3.6 exports address fields -> VCards.
374
+ fields = [
375
+ VCardField.create("#{name}.ADR", address_str.join(';'), "type" => type_arr),
376
+ VCardField.create("#{name}.X-ABADR", "us"),
377
+ ]
378
+ if other_label != nil
379
+ fields << VCardField.create("#{name}.X-ABLabel", "#{other_label}")
380
+ end
381
+ fields
382
+ end
383
+ end
384
+
385
+ parser = VCardParser.new
386
+ cards = parser.vcards_from_txt_file(ARGV[0])
387
+ #puts ""
388
+ cards.each { |card|
389
+ puts card.to_s
390
+ }