mumboe-vpim 0.7
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/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,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 | 
            +
            }
         | 
    
        data/samples/vcf-dump.rb
    ADDED
    
    | @@ -0,0 +1,86 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            $-w = true
         | 
| 4 | 
            +
            $:.unshift File.dirname($0) + '/../lib'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            require 'pp'
         | 
| 7 | 
            +
            require 'getoptlong'
         | 
| 8 | 
            +
            require 'vpim/vcard'
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            HELP =<<EOF
         | 
| 11 | 
            +
            Usage: #{$0} <vcard>...
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            Options
         | 
| 14 | 
            +
              -h,--help      Print this helpful message.
         | 
| 15 | 
            +
              -n,--name      Print the vCard name.
         | 
| 16 | 
            +
              -d,--debug     Print debug information.
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            Examples:
         | 
| 19 | 
            +
            EOF
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            opt_name  = nil
         | 
| 22 | 
            +
            opt_debug = nil
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            opts = GetoptLong.new(
         | 
| 25 | 
            +
              [ "--help",    "-h",              GetoptLong::NO_ARGUMENT ],
         | 
| 26 | 
            +
              [ "--name",    "-n",              GetoptLong::NO_ARGUMENT ],
         | 
| 27 | 
            +
              [ "--debug",   "-d",              GetoptLong::NO_ARGUMENT ]
         | 
| 28 | 
            +
            )
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            opts.each do |opt, arg|
         | 
| 31 | 
            +
              case opt
         | 
| 32 | 
            +
                when "--help" then
         | 
| 33 | 
            +
                  puts HELP
         | 
| 34 | 
            +
                  exit 0
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                when "--name" then
         | 
| 37 | 
            +
                  opt_name = true
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                when "--debug" then
         | 
| 40 | 
            +
                  opt_debug = true
         | 
| 41 | 
            +
              end
         | 
| 42 | 
            +
            end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            if ARGV.length < 1
         | 
| 45 | 
            +
              puts "no vcard files specified, try -h!"
         | 
| 46 | 
            +
              exit 1
         | 
| 47 | 
            +
            end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            ARGV.each do |file|
         | 
| 50 | 
            +
             | 
| 51 | 
            +
              cards = Vpim::Vcard.decode(open(file))
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              cards.each do |card|
         | 
| 54 | 
            +
                card.each do |field|
         | 
| 55 | 
            +
                  puts "..#{field.name.capitalize}=#{field.value.inspect}"
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  if field.group
         | 
| 58 | 
            +
                    puts " group=#{field.group}"
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  field.each_param do |param, values|
         | 
| 62 | 
            +
                    puts " #{param}=[#{values.join(", ")}]"
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                if opt_name
         | 
| 67 | 
            +
                  begin
         | 
| 68 | 
            +
                  puts "#name=#{card.name.formatted}"
         | 
| 69 | 
            +
                  rescue
         | 
| 70 | 
            +
                    puts "! failed to decode name!"
         | 
| 71 | 
            +
                  end
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
             | 
| 75 | 
            +
                if opt_debug
         | 
| 76 | 
            +
                  card.groups.sort.each do |group|
         | 
| 77 | 
            +
                    card.enum_by_group(group).each do |field|
         | 
| 78 | 
            +
                      puts "#{group} -> #{field.inspect}"
         | 
| 79 | 
            +
                    end
         | 
| 80 | 
            +
                  end
         | 
| 81 | 
            +
                end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                puts ""
         | 
| 84 | 
            +
              end
         | 
| 85 | 
            +
            end
         | 
| 86 | 
            +
             | 
| @@ -0,0 +1,61 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            $-w = true
         | 
| 4 | 
            +
            $:.unshift File.dirname($0) + '/../lib'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            require 'pp'
         | 
| 7 | 
            +
            require 'getoptlong'
         | 
| 8 | 
            +
            require 'vpim/vcard'
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            HELP =<<EOF
         | 
| 11 | 
            +
            Usage: #{$0} <vcard>...
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            Options
         | 
| 14 | 
            +
              -h,--help      Print this helpful message.
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            Examples:
         | 
| 17 | 
            +
            EOF
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            opt_name  = nil
         | 
| 20 | 
            +
            opt_debug = nil
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            opts = GetoptLong.new(
         | 
| 23 | 
            +
              [ "--help",    "-h",              GetoptLong::NO_ARGUMENT ],
         | 
| 24 | 
            +
              [ "--name",    "-n",              GetoptLong::NO_ARGUMENT ],
         | 
| 25 | 
            +
              [ "--debug",   "-d",              GetoptLong::NO_ARGUMENT ]
         | 
| 26 | 
            +
            )
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            opts.each do |opt, arg|
         | 
| 29 | 
            +
              case opt
         | 
| 30 | 
            +
                when "--help" then
         | 
| 31 | 
            +
                  puts HELP
         | 
| 32 | 
            +
                  exit 0
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                when "--name" then
         | 
| 35 | 
            +
                  opt_name = true
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                when "--debug" then
         | 
| 38 | 
            +
                  opt_debug = true
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
            end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
            if ARGV.length < 1
         | 
| 43 | 
            +
              puts "no vcard files specified, try -h!"
         | 
| 44 | 
            +
              exit 1
         | 
| 45 | 
            +
            end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
            ARGV.each do |file|
         | 
| 48 | 
            +
             | 
| 49 | 
            +
              cards = Vpim::Vcard.decode(open(file))
         | 
| 50 | 
            +
             | 
| 51 | 
            +
              cards.each do |card|
         | 
| 52 | 
            +
                card.lines.each_with_index do |line, i|
         | 
| 53 | 
            +
                  print line.name
         | 
| 54 | 
            +
                  if line.group.length > 0
         | 
| 55 | 
            +
                    print " (", line.group, ")"
         | 
| 56 | 
            +
                  end
         | 
| 57 | 
            +
                  print ": ", line.value.inspect, "\n"
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
              end
         | 
| 60 | 
            +
            end
         | 
| 61 | 
            +
             | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'vpim/vcard'
         | 
| 4 | 
            +
            require 'vpim/icalendar'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            $in  = ARGV.first ? File.open(ARGV.shift) : $stdin
         | 
| 7 | 
            +
            $out = ARGV.first ? File.open(ARGV.shift, 'w') : $stdout
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            cal = Vpim::Icalendar.create
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            Vpim::Vcard.decode($in).each do |card|
         | 
| 12 | 
            +
              if card.birthday
         | 
| 13 | 
            +
                cal.push Vpim::Icalendar::Vevent.create_yearly(
         | 
| 14 | 
            +
                  card.birthday,
         | 
| 15 | 
            +
                  "Birthday for #{card['fn'].strip}"
         | 
| 16 | 
            +
                  )
         | 
| 17 | 
            +
                $stderr.puts "#{card['fn']} -> bday #{cal.events.last.dtstart}"
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            puts cal.encode
         | 
| 22 | 
            +
             | 
| @@ -0,0 +1,121 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
            #
         | 
| 3 | 
            +
            # For a query command, mutt expects output of the form:
         | 
| 4 | 
            +
            #
         | 
| 5 | 
            +
            # informational line
         | 
| 6 | 
            +
            # <email>TAB<name>[TAB<other info>]
         | 
| 7 | 
            +
            # ...
         | 
| 8 | 
            +
            #
         | 
| 9 | 
            +
            # For an alias command, mutt expects output of the form:
         | 
| 10 | 
            +
            # alias NICKNAME EMAIL
         | 
| 11 | 
            +
            #
         | 
| 12 | 
            +
            # NICKNAME shouldn't have spaces, and EMAIL can be either "user@example.com",
         | 
| 13 | 
            +
            # "<user@example.com>", or "User <user@example.com>".
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            $-w = true
         | 
| 16 | 
            +
            $:.unshift File.dirname($0) + '/../lib'
         | 
| 17 | 
            +
             | 
| 18 | 
            +
             | 
| 19 | 
            +
            require 'getoptlong'
         | 
| 20 | 
            +
            require 'vpim/vcard'
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            HELP =<<EOF
         | 
| 23 | 
            +
            Usage: vcf-to-mutt.rb [--aliases] [query]
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            Queries a vCard file and prints the results in Mutt's query result format, or
         | 
| 26 | 
            +
            as a Mutt alias file. No query matches all vCards.
         | 
| 27 | 
            +
              
         | 
| 28 | 
            +
            The query is matched against all fields, so you can use 'climbers' to match all
         | 
| 29 | 
            +
            vCards that has that string in the Notes field if you want to email all the
         | 
| 30 | 
            +
            rock climbers you know. Or you can query all vCards with addresses in a
         | 
| 31 | 
            +
            particular city, you get the idea.
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            Options
         | 
| 34 | 
            +
              -h,--help      Print this helpful message.
         | 
| 35 | 
            +
              -a,--aliases   Output an alias file, otherwise output a query response.
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            Examples:
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            Put in your muttrc file (either ~/.muttrc or ~/.mutt/muttrc) a line such as:
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            set query_command = "vcf-to-mutt.rb '%s' < ~/mycards.vcf"
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            Bugs:
         | 
| 44 | 
            +
             | 
| 45 | 
            +
             The aliases output file bases the alias name on the nickname, or the full
         | 
| 46 | 
            +
            name, but either way, they aren't guaranteed to be unique if you have more than
         | 
| 47 | 
            +
            email address in a vCard, or more than one vCard for the same nickname or full
         | 
| 48 | 
            +
            name.
         | 
| 49 | 
            +
            EOF
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            opt_query = ''
         | 
| 52 | 
            +
            opt_aliases = false
         | 
| 53 | 
            +
             | 
| 54 | 
            +
            opts = GetoptLong.new(
         | 
| 55 | 
            +
              [ "--help",    "-h",              GetoptLong::NO_ARGUMENT ],
         | 
| 56 | 
            +
              [ "--aliases", "-a",              GetoptLong::NO_ARGUMENT ]
         | 
| 57 | 
            +
            )
         | 
| 58 | 
            +
             | 
| 59 | 
            +
            opts.each do |opt, arg|
         | 
| 60 | 
            +
              case opt
         | 
| 61 | 
            +
                when "--help" then
         | 
| 62 | 
            +
                  puts HELP
         | 
| 63 | 
            +
                  exit 0
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                when "--aliases" then
         | 
| 66 | 
            +
                  opt_aliases = true
         | 
| 67 | 
            +
              end
         | 
| 68 | 
            +
            end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
            opt_query = ARGV.first
         | 
| 71 | 
            +
             | 
| 72 | 
            +
            module Mutt
         | 
| 73 | 
            +
              def Mutt.vcard_query(cards, query)
         | 
| 74 | 
            +
                query = query.downcase if query
         | 
| 75 | 
            +
                cards.find_all do |card|
         | 
| 76 | 
            +
                  card.detect do |f|
         | 
| 77 | 
            +
                    !query || f.value.downcase.include?(query)
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
              end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
              def Mutt.query_print(cards, caption)
         | 
| 83 | 
            +
                puts caption
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                cards.each do
         | 
| 86 | 
            +
                  |vcard|
         | 
| 87 | 
            +
                  # find the email addresses
         | 
| 88 | 
            +
                  vcard.enum_by_name("email").each do |f|
         | 
| 89 | 
            +
                    nn = vcard.nickname
         | 
| 90 | 
            +
                    nn = nn ? "\t#{nn}" : ""
         | 
| 91 | 
            +
                    puts "#{f.value}\t#{vcard['fn']}#{nn}"
         | 
| 92 | 
            +
                  end
         | 
| 93 | 
            +
                end
         | 
| 94 | 
            +
              end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
              def Mutt.alias_print(cards)
         | 
| 97 | 
            +
                cards.each do
         | 
| 98 | 
            +
                  |vcard|
         | 
| 99 | 
            +
                  # find the email addresses
         | 
| 100 | 
            +
                  vcard.enum_by_name("email").each do |f|
         | 
| 101 | 
            +
                    em = f.value
         | 
| 102 | 
            +
                    fn = vcard['fn']
         | 
| 103 | 
            +
                    nn = vcard.nickname || fn.gsub(/\s+/,'')
         | 
| 104 | 
            +
                    puts "alias #{nn} #{fn} <#{em}>"
         | 
| 105 | 
            +
                  end
         | 
| 106 | 
            +
                end
         | 
| 107 | 
            +
              end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
            end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
            cards = Vpim::Vcard.decode($stdin)
         | 
| 112 | 
            +
             | 
| 113 | 
            +
            matches = Mutt::vcard_query(cards, opt_query)
         | 
| 114 | 
            +
             | 
| 115 | 
            +
            if opt_aliases
         | 
| 116 | 
            +
              Mutt::alias_print(matches)
         | 
| 117 | 
            +
            else
         | 
| 118 | 
            +
              qstr = opt_query == '' ? '<all records>' : opt_query;
         | 
| 119 | 
            +
              Mutt::query_print(matches, "Query #{qstr} against #{cards.size} vCards:")
         | 
| 120 | 
            +
            end
         | 
| 121 | 
            +
             |