Эх сурвалжийг харах

initial draft for mailto handling

cyberta 4 жил өмнө
parent
commit
ac545c4517

+ 1 - 1
DcCore/DcCore/DC/Wrapper.swift

@@ -150,7 +150,7 @@ public class DcContext {
         return ids
     }
 
-    public func createContact(name: String, email: String) -> Int {
+    public func createContact(name: String?, email: String) -> Int {
         return Int(dc_create_contact(contextPointer, name, email))
     }
 

+ 15 - 7
deltachat-ios/AppDelegate.swift

@@ -130,13 +130,21 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         //    NotificationCenter.default.post(name: NSNotification.Name("oauthLoginApproved"), object: nil, userInfo: ["token": token])
         // }
 
-        // Hack to format url properly
-        let urlString = url.absoluteString
-                       .replacingOccurrences(of: "openpgp4fpr", with: "OPENPGP4FPR", options: .literal, range: nil)
-                       .replacingOccurrences(of: "%23", with: "#", options: .literal, range: nil)
-
-        self.appCoordinator.handleQRCode(urlString)
-        return true
+        switch url.scheme?.lowercased() {
+        case "openpgp4fpr":
+            // Hack to format url properly
+            let urlString = url.absoluteString
+                           .replacingOccurrences(of: "openpgp4fpr", with: "OPENPGP4FPR", options: .literal, range: nil)
+                           .replacingOccurrences(of: "%23", with: "#", options: .literal, range: nil)
+
+            self.appCoordinator.handleQRCode(urlString)
+            return true
+        case "mailto":
+            self.appCoordinator.handleMailtoURL(url)
+            return true
+        default:
+            return false
+        }
     }
 
 

+ 1 - 1
deltachat-ios/Controller/ChatListController.swift

@@ -467,7 +467,7 @@ class ChatListController: UITableViewController {
     }
 
     // MARK: - coordinator
-    private func showNewChatController() {
+    func showNewChatController() {
         let newChatVC = NewChatViewController(dcContext: dcContext)
         navigationController?.pushViewController(newChatVC, animated: true)
     }

+ 30 - 0
deltachat-ios/Controller/NewChatViewController.swift

@@ -89,6 +89,12 @@ class NewChatViewController: UITableViewController {
         tableView.register(ActionCell.self, forCellReuseIdentifier: "actionCell")
         tableView.register(ContactCell.self, forCellReuseIdentifier: "contactCell")
         tableView.sectionHeaderHeight = UITableView.automaticDimension
+
+        if RelayHelper.sharedInstance.isMailtoHandling() {
+            if let mailtoAddress = RelayHelper.sharedInstance.mailtoAddress {
+                askToChatWith(address: mailtoAddress)
+            }
+        }
     }
 
     override func viewWillAppear(_ animated: Bool) {
@@ -98,6 +104,7 @@ class NewChatViewController: UITableViewController {
 
     // MARK: - actions
     @objc func cancelButtonPressed() {
+
         dismiss(animated: true, completion: nil)
     }
 
@@ -383,6 +390,29 @@ extension NewChatViewController {
         present(alert, animated: true, completion: nil)
     }
 
+    private func askToChatWith(address: String) {
+        var contactId = dcContext.lookupContactIdByAddress(address)
+        if contactId != 0 && dcContext.getChatIdByContactId(contactId: contactId) != 0 {
+            self.showNewChat(contactId: contactId)
+        } else {
+            let alert = UIAlertController(title: String.localizedStringWithFormat(String.localized("ask_start_chat_with"), address),
+                                          message: nil,
+                                          preferredStyle: .safeActionSheet)
+            alert.addAction(UIAlertAction(title: String.localized("start_chat"), style: .default, handler: { [weak self] _ in
+                guard let self = self else { return }
+                self.dismiss(animated: true, completion: nil)
+                if contactId == 0 {
+                    contactId = self.dcContext.createContact(name: nil, email: address)
+                }
+                self.showNewChat(contactId: contactId)
+            }))
+            alert.addAction(UIAlertAction(title: String.localized("cancel"), style: .cancel, handler: { _ in
+                self.reactivateSearchBarIfNeeded()
+            }))
+            present(alert, animated: true, completion: nil)
+        }
+    }
+
     private func askToChatWith(contactId: Int) {
         if dcContext.getChatIdByContactId(contactId: contactId) != 0 {
             self.dismiss(animated: true, completion: nil)

+ 14 - 0
deltachat-ios/Coordinator/AppCoordinator.swift

@@ -97,6 +97,20 @@ class AppCoordinator {
         }
     }
 
+    func handleMailtoURL(_ url: URL) {
+        if RelayHelper.sharedInstance.parseMailtoUrl(url) {
+            showTab(index: chatsTab)
+            if let rootController = self.tabBarController.selectedViewController as? UINavigationController {
+                rootController.popToRootViewController(animated: false)
+                if let controller = rootController.viewControllers.first as? ChatListController {
+                    controller.showNewChatController()
+                }
+            }
+        } else {
+            logger.warning("Could not parse mailto: URL")
+        }
+    }
+    
     func handleQRCode(_ code: String) {
         showTab(index: qrTab)
         if let navController = self.tabBarController.selectedViewController as? UINavigationController,

+ 56 - 0
deltachat-ios/Helper/RelayHelper.swift

@@ -6,6 +6,9 @@ class RelayHelper {
     private static var dcContext: DcContext?
     var messageIds: [Int]?
 
+    var mailtoDraft: String = ""
+    var mailtoAddress: String?
+
     private init() {
         guard RelayHelper.dcContext != nil else {
             fatalError("Error - you must call RelayHelper.setup() before accessing RelayHelper.shared")
@@ -39,4 +42,57 @@ class RelayHelper {
     func cancel() {
         messageIds = nil
     }
+
+    func isMailtoHandling() -> Bool {
+        return !mailtoDraft.isEmpty || mailtoAddress != nil
+    }
+
+    func finishMailto() {
+        mailtoDraft = ""
+        mailtoAddress = nil
+    }
+
+
+    func splitString(_ value: String) -> [String] {
+        return value.split(separator: ",").map(String.init)
+    }
+
+    /**
+            returns true if parsing was successful
+     */
+    func parseMailtoUrl(_ url: URL) -> Bool {
+        if Utils.isEmail(url: url),
+           let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false),
+           !urlComponents.path.isEmpty {
+            var subject: String = ""
+            var body: String = ""
+            let queryItems = urlComponents.queryItems ?? []
+            for queryItem in queryItems {
+                guard let value = queryItem.value else {
+                    continue
+                }
+                switch queryItem.name {
+                case "body":
+                    body = value
+                case "subject":
+                    subject = value
+                default:
+                    break
+                }
+            }
+
+            if !subject.isEmpty {
+                mailtoDraft = subject
+                if !body.isEmpty {
+                    mailtoDraft += "\n\n \(body)"
+                }
+            } else if (!body.isEmpty) {
+                mailtoDraft = body
+            }
+
+            mailtoAddress = splitString(urlComponents.path)[0] // we currently only allow 1 receipient
+            return true
+        }
+        return false
+    }
 }