vCard: use utf16 encoding

Use utf16 encoding when parsing data to CNContact to avoid
CNContactVCardSerialization errors. For sharing  vCard with
other contacts we still use utf8.

Change-Id: I3a7a9b7b9a40a3c17d067115c5e7897899ae0a69
diff --git a/Ring/Ring/Account/VCardUtils.swift b/Ring/Ring/Account/VCardUtils.swift
index 7165b44..1043d20 100644
--- a/Ring/Ring/Account/VCardUtils.swift
+++ b/Ring/Ring/Account/VCardUtils.swift
@@ -105,8 +105,8 @@
     class func sendVCard(card: CNContact, callID: String, accountID: String, sender: CallsService) {
         do {
             let vCard = card
-            let vCardData = try CNContactVCardSerialization.dataWithImageAndUUID(from: vCard, andImageCompression: 40000)
-            guard var vCardString = String(data: vCardData, encoding: String.Encoding.utf8) else {
+            guard let vCardData = try CNContactVCardSerialization.dataWithImageAndUUID(from: vCard, andImageCompression: 40000, encoding: .utf8),
+                var vCardString = String(data: vCardData, encoding: String.Encoding.utf8) else {
                 return
             }
             var vcardLength = vCardString.count
diff --git a/Ring/Ring/Database/DBManager.swift b/Ring/Ring/Database/DBManager.swift
index 2e1598d..39049b9 100644
--- a/Ring/Ring/Database/DBManager.swift
+++ b/Ring/Ring/Database/DBManager.swift
@@ -764,7 +764,7 @@
                                            options: NSData.Base64DecodingOptions.ignoreUnknownCharacters) as Data?
         }
         let data = try CNContactVCardSerialization.dataWithImageAndUUID(from: contactCard, andImageCompression: 40000)
-        try data.write(to: url)
+        try data?.write(to: url)
     }
 
     private func getConversationsFor(contactUri: String,
diff --git a/Ring/Ring/Extensions/CNContactVCardSerialization+Helpers.swift b/Ring/Ring/Extensions/CNContactVCardSerialization+Helpers.swift
index 8e52580..6a4e3b5 100644
--- a/Ring/Ring/Extensions/CNContactVCardSerialization+Helpers.swift
+++ b/Ring/Ring/Extensions/CNContactVCardSerialization+Helpers.swift
@@ -36,7 +36,7 @@
 
 extension CNContactVCardSerialization {
 
-    class func dataWithImageAndUUID(from contact: CNContact, andImageCompression compressedSize: Int?) throws -> Data {
+    class func dataWithImageAndUUID(from contact: CNContact, andImageCompression compressedSize: Int?, encoding: String.Encoding = .utf16) throws -> Data? {
 
         // recreate vCard string
         let beginString = VCardFields.begin.rawValue + "\n"
@@ -51,7 +51,7 @@
 
         // if contact have an image add it to vCard data
         guard var image = contact.imageData  else {
-            return vCardString.data(using: .utf8)!
+            return vCardString.data(using: encoding)
         }
 
         var photofieldName = VCardFields.photoPNG
@@ -63,17 +63,15 @@
                 .convert(toSize: CGSize(width: 200.0, height: 200.0), scale: 1)
         }
 
-        if let scaledImage = scaledImage {
-            if scaledImage.pngData() != nil {
-                image = scaledImage.pngData()!
-            }
+        if let scaledImage = scaledImage, let data = scaledImage.pngData() {
+            image = data
         }
 
         if let compressionSize = compressedSize {
             // compress image before sending vCard
             guard let compressedImage = UIImage(data: image)?
                 .convertToData(ofMaxSize: compressionSize) else {
-                    return vCardString.data(using: .utf8)!
+                    return vCardString.data(using: encoding)
             }
 
             image = compressedImage
@@ -84,7 +82,7 @@
         let vcardImageString = photofieldName.rawValue + base64Image + "\n"
         vCardString = vCardString.replacingOccurrences(of: VCardFields.end.rawValue, with: (vcardImageString + VCardFields.end.rawValue))
 
-        return vCardString.data(using: .utf8)!
+        return vCardString.data(using: encoding)
     }
 
     class func parseToVCard(data: Data) -> CNContact? {
@@ -92,13 +90,18 @@
         do {
             try ObjCHandler.try {
                 guard let vCards = try? CNContactVCardSerialization.contacts(with: data),
-                    let vCard = vCards.first,
-                    let returnData = String(data: data, encoding: .utf8) else { return }
+                    let vCard = vCards.first else { return }
+                var stringData = String(data: data, encoding: .utf16)
+                if stringData == nil {
+                    stringData = String(data: data, encoding: .utf8)
+                }
+                guard let returnData = stringData else { return }
                 let contentArr = returnData.components(separatedBy: "\n")
-                guard let nameRow = contentArr.filter({ String($0.prefix(3)) == VCardFields.fullName.rawValue }).first else { return }
                 let vcard = CNMutableContact()
-                let name = String(nameRow.suffix(nameRow.count - 3))
-                vcard.familyName = name
+                if let nameRow = contentArr.filter({ String($0.prefix(3)) == VCardFields.fullName.rawValue }).first {
+                    let name = String(nameRow.suffix(nameRow.count - 3))
+                    vcard.familyName = name
+                }
                 vcard.phoneNumbers = vCard.phoneNumbers
                 vcard.imageData = vCard.imageData
                 contact = vcard
diff --git a/Ring/Ring/Services/ContactsService.swift b/Ring/Ring/Services/ContactsService.swift
index 4f99317..d874d01 100644
--- a/Ring/Ring/Services/ContactsService.swift
+++ b/Ring/Ring/Services/ContactsService.swift
@@ -213,7 +213,7 @@
                         cardChanged = true
                     }
                     if cardChanged {
-                        payload = try CNContactVCardSerialization.dataWithImageAndUUID(from: vCard, andImageCompression: 40000)
+                        payload = try CNContactVCardSerialization.dataWithImageAndUUID(from: vCard, andImageCompression: 40000, encoding: .utf8)
                     }
                 }
                 self.contactsAdapter.sendTrustRequest(toContact: ringId, payload: payload, withAccountId: account.id)
diff --git a/Ring/Ring/Services/ProfilesService.swift b/Ring/Ring/Services/ProfilesService.swift
index d2ca9f4..220e7bf 100644
--- a/Ring/Ring/Services/ProfilesService.swift
+++ b/Ring/Ring/Services/ProfilesService.swift
@@ -155,6 +155,11 @@
             }
         }
 
+        if let datautf8 = String(data: vCardData, encoding: .utf8),
+            let dataUtf16 = datautf8.data(using: String.Encoding.utf16) {
+            vCardData = dataUtf16
+        }
+
         //Create the vCard, save and db and emit a new event
         if let vCard = CNContactVCardSerialization.parseToVCard(data: vCardData) {
             let name = VCardUtils.getName(from: vCard)