From ca61358d5c3f2d8ece12b21cf3c4e5730b958654 Mon Sep 17 00:00:00 2001 From: Jason Hinkle Date: Thu, 23 Jun 2011 18:00:15 -0500 Subject: [PATCH] Fixed parsing errors with older outlook vcard format 2.2 Fix bug with parsing address with no street number Added parsing support for IM Added parsing support for displayAsCompany Adding parsing support for preferred phone/email/IM --- src/com/adobe/fileformats/vcard/Address.as | 4 +- src/com/adobe/fileformats/vcard/Email.as | 1 + src/com/adobe/fileformats/vcard/IM.as | 40 +++++ src/com/adobe/fileformats/vcard/Phone.as | 1 + src/com/adobe/fileformats/vcard/VCard.as | 3 + .../adobe/fileformats/vcard/VCardParser.as | 146 +++++++++++++++--- 6 files changed, 170 insertions(+), 25 deletions(-) create mode 100644 src/com/adobe/fileformats/vcard/IM.as diff --git a/src/com/adobe/fileformats/vcard/Address.as b/src/com/adobe/fileformats/vcard/Address.as index a368ffb..29d7b0c 100644 --- a/src/com/adobe/fileformats/vcard/Address.as +++ b/src/com/adobe/fileformats/vcard/Address.as @@ -35,13 +35,15 @@ package com.adobe.fileformats.vcard { public var type:String; public var street:String; + public var street2:String; public var city:String; public var state:String; public var postalCode:String; + public var country:String; public function toString():String { - return (street + " " + city + ", " + state + " " + postalCode); + return (street + " " + city + ", " + state + " " + postalCode+ " " + country); } } } \ No newline at end of file diff --git a/src/com/adobe/fileformats/vcard/Email.as b/src/com/adobe/fileformats/vcard/Email.as index 071c39e..1492e7e 100644 --- a/src/com/adobe/fileformats/vcard/Email.as +++ b/src/com/adobe/fileformats/vcard/Email.as @@ -33,6 +33,7 @@ package com.adobe.fileformats.vcard { public class Email { + public var isPreferred:Boolean; public var type:String; public var address:String; } diff --git a/src/com/adobe/fileformats/vcard/IM.as b/src/com/adobe/fileformats/vcard/IM.as new file mode 100644 index 0000000..09ea467 --- /dev/null +++ b/src/com/adobe/fileformats/vcard/IM.as @@ -0,0 +1,40 @@ +/* +Copyright (c) 2008, Adobe Systems Incorporated +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +* Neither the name of Adobe Systems Incorporated nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +package com.adobe.fileformats.vcard +{ + public class IM + { + public var isPreferred:Boolean; + public var type:String; + public var address:String; + } +} \ No newline at end of file diff --git a/src/com/adobe/fileformats/vcard/Phone.as b/src/com/adobe/fileformats/vcard/Phone.as index 27f98e4..6a3bfba 100644 --- a/src/com/adobe/fileformats/vcard/Phone.as +++ b/src/com/adobe/fileformats/vcard/Phone.as @@ -33,6 +33,7 @@ package com.adobe.fileformats.vcard { public class Phone { + public var isPreferred:Boolean; public var type:String; public var number:String; } diff --git a/src/com/adobe/fileformats/vcard/VCard.as b/src/com/adobe/fileformats/vcard/VCard.as index d6bc283..cff594b 100644 --- a/src/com/adobe/fileformats/vcard/VCard.as +++ b/src/com/adobe/fileformats/vcard/VCard.as @@ -41,7 +41,9 @@ package com.adobe.fileformats.vcard public var image:ByteArray; public var phones:Array; public var emails:Array; + public var ims:Array; public var addresses:Array; + public var isCompany:Boolean; public function VCard() { @@ -49,6 +51,7 @@ package com.adobe.fileformats.vcard phones = new Array(); emails = new Array(); addresses = new Array(); + ims = new Array(); } } } \ No newline at end of file diff --git a/src/com/adobe/fileformats/vcard/VCardParser.as b/src/com/adobe/fileformats/vcard/VCardParser.as index 45c954a..a4ed296 100644 --- a/src/com/adobe/fileformats/vcard/VCardParser.as +++ b/src/com/adobe/fileformats/vcard/VCardParser.as @@ -44,13 +44,19 @@ package com.adobe.fileformats.vcard var type:String; var typeTmp:String; var line:String; + var numEmails:int; for (var i:uint = 0; i < lines.length; ++i) { line = lines[i]; + + line = line.replace(/type=/ig,"TYPE="); + + if (line == "BEGIN:VCARD") { vcard = new VCard(); + numEmails = 0; } else if (line == "END:VCARD") { @@ -76,6 +82,38 @@ package com.adobe.fileformats.vcard var title:String = line.substring(6, line.length); vcard.title = title; } + else if(line.search(/^X-AIM/i) != -1) + { + var im:IM = new IM(); + + var imTokens:Array =line.split(/;/); + + for each (var imToken:String in imTokens) + { + if (imToken.indexOf(":") > -1) + { + var imParts:Array = imToken.split(/:/); + im.address = imParts[imParts.length-1] as String; + } + + if (imToken.indexOf("TYPE=") > -1) + { + var tParts:Array = imToken.split(/:/); + var t:String = (tParts[0] as String).replace("TYPE=",""); + if (t == "pref") + { + im.isPreferred = true; + } + else + { + im.type = t; + } + } + } + + vcard.ims.push(im); + + } else if (line.search(/^FN:/i) != -1) { var fullName:String = line.substring(3, line.length); @@ -88,31 +126,45 @@ package com.adobe.fileformats.vcard var phone:Phone = new Phone(); var number:String; var phoneTokens:Array = line.split(";"); - for each (var phoneToken:String in phoneTokens) + + if (line.indexOf("TYPE=") == -1) + { + // there is no type specified so this is an older format, likely outlook + var phoneParts:Array = (phoneTokens[phoneTokens.length-1] as String).split(/:/,2); + number = phoneParts[phoneParts.length-1]; + type = phoneTokens.length > 1 ? phoneTokens[1] : 'UNKNOWN'; + + if (line.indexOf("FAX") > -1) type += ' FAX'; + } + else { - if (phoneToken.search(/^TYPE=/i) != -1) + for each (var phoneToken:String in phoneTokens) { - if (phoneToken.indexOf(":") != -1) - { - typeTmp = phoneToken.substring(5, phoneToken.indexOf(":")); - number = phoneToken.substring(phoneToken.indexOf(":")+1, phoneToken.length); - } - else - { - typeTmp = phoneToken.substring(5, phoneToken.length); - } - - typeTmp = typeTmp.toLocaleLowerCase(); - - if (typeTmp == "pref") - { - continue; - } - if (type.length != 0) + if (phoneToken.search(/^TYPE=/i) != -1) { - type += (" "); + if (phoneToken.indexOf(":") != -1) + { + typeTmp = phoneToken.substring(5, phoneToken.indexOf(":")); + number = phoneToken.substring(phoneToken.indexOf(":")+1, phoneToken.length); + } + else + { + typeTmp = phoneToken.substring(5, phoneToken.length); + } + + typeTmp = typeTmp.toLocaleLowerCase(); + + if (typeTmp == "pref") + { + phone.isPreferred = true; + continue; + } + if (type.length != 0) + { + type += (" "); + } + type += typeTmp; } - type += typeTmp; } } if (type.length > 0 && number != null) @@ -145,7 +197,13 @@ package com.adobe.fileformats.vcard typeTmp = typeTmp.toLocaleLowerCase(); - if (typeTmp == "pref" || typeTmp == "internet") + if (typeTmp == "pref") + { + email.isPreferred = true; + continue; + } + + if (typeTmp == "internet") { continue; } @@ -155,6 +213,14 @@ package com.adobe.fileformats.vcard } type += typeTmp; } + else if (type.length == 0 && emailToken.indexOf("@") != -1) + { + // this is probably an outlook style email which isn't caught by above logic + var emailParts:Array = emailToken.split(":"); + emailAddress = emailParts[emailParts.length-1]; + numEmails++; + type="EMAIL " + numEmails; // todo: type is unknown for this email + } } if (type.length > 0 && emailAddress != null) { @@ -167,9 +233,18 @@ package com.adobe.fileformats.vcard { var addressTokens:Array = line.split(";"); var address:Address = new Address(); + var delimIndex:int = 0; + var streetLines:Array; + for (var j:uint = 0; j < addressTokens.length; ++j) { var addressToken:String = addressTokens[j]; + + if (addressToken.substr(addressToken.length-1,1) == ":") + { + delimIndex = j; + } + if (addressToken.search(/^home:+$/i) != -1) // For Outlook, which uses non-standard vCards. { address.type = "home"; @@ -178,6 +253,7 @@ package com.adobe.fileformats.vcard { address.type = "work"; } + if (addressToken.search(/^type=/i) != -1) // The "type" parameter is the standard way (which Address Book uses) { // First, remove the optional ":" character. @@ -209,12 +285,26 @@ package com.adobe.fileformats.vcard } address.type = addressType; } - else if (addressToken.search(/^\d/) != -1 && address.street == null) + else if (addressToken.search(/^\d/) != -1 && address.street == null) // FAULTY LOGIC - STREET NAME DOES NOT REQUIRE NUMBERS + { + streetLines = addressToken.split(/\\n/, 2); + address.street = streetLines[0]; + address.street2 = streetLines.length > 1 ? (streetLines[1] as String).replace(/\\n/," ") : ''; + address.city = addressTokens[j+1]; + address.state = addressTokens[j+2]; + address.postalCode = addressTokens[j+3]; + address.country = addressTokens.length > j+4 ? addressTokens[j+4] : ''; + } + else if (delimIndex > 0 && j == (delimIndex + 2) && address.street == null) { - address.street = addressToken.replace(/\\n/, ""); + // TODO HACK this means that the faulty logic above didn't catch the address, not sure how compatible this is...? + streetLines = addressToken.split(/\\n/, 2); + address.street = streetLines[0]; + address.street2 = streetLines.length > 1 ? (streetLines[1] as String).replace(/\\n/," ") : ''; address.city = addressTokens[j+1]; address.state = addressTokens[j+2]; address.postalCode = addressTokens[j+3]; + address.country = addressTokens.length > j+4 ? addressTokens[j+4] : ''; } } if (address.type != null && address.street != null) @@ -239,6 +329,14 @@ package com.adobe.fileformats.vcard } } } + else if (line == 'X-ABShowAs:COMPANY') + { + vcard.isCompany = true; + } + else + { + trace('UNKNOWN LINE'); + } } return vcards; }