Set mime type for bundle in case of mmsto, sms
[platform/framework/web/wrt.git] / src / view / common / scheme_action_map.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @file       scheme_action_map.cpp
18  * @author     Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
19  * @version    1.0
20  */
21
22 #include "scheme_action_map.h"
23 #include <scheme.h>
24 #include <dpl/log/log.h>
25 #include <dpl/event/controller.h>
26 #include <application_launcher.h>
27 #include <appsvc.h>
28 #include <pcrecpp.h>
29 #include <memory>
30 #include <curl/curl.h>
31 #include "scheme_action_map_data.h"
32
33 namespace ViewModule {
34
35 namespace {
36
37 /*
38  * Lazy construction pattern.
39  * TODO Make it more general. Use variadic template/tuples/lambdas or sth. Move
40  * to DPL.
41  */
42 template <typename T, typename Arg1>
43 class Lazy
44 {
45 public:
46     explicit Lazy(const Arg1& arg1) :
47         m_arg1(arg1),
48         m_object(new std::unique_ptr<T>())
49     {
50     }
51     Lazy(const Lazy<T, Arg1>& other) :
52         m_arg1(other.m_arg1),
53         m_object(other.m_object)
54     {
55     }
56
57     T& operator*()  { return GetObject(); }
58     const T& operator*() const { return GetObject(); }
59     const T* operator->() const  { return &GetObject(); }
60     T* operator->() { return &GetObject(); }
61
62     Lazy<T, Arg1>& operator=(const Lazy<T, Arg1>& other)
63     {
64         m_arg1 = other.m_arg1;
65         m_object = other.m_object;
66         return *this;
67     }
68 private:
69     T& GetObject() const
70     {
71         if (!(*m_object)) {
72             (*m_object).reset(new T(m_arg1));
73         }
74         return **m_object;
75     }
76
77     Arg1 m_arg1;
78     // single unique_ptr shared among many Lazy copies
79     mutable std::shared_ptr<std::unique_ptr<T> > m_object;
80 };
81
82 /*
83  * Struct defining conversion of scheme for given appsvc key for example:
84  * sms:5551212?body=expected%20text => APPSVC_DATA_TEXT + expected%20text
85  */
86 struct AppSvcConversion {
87     AppSvcConversion(char const * const keyValue, const std::string& regexStr):
88         key(keyValue),
89         regex(regexStr) {
90     }
91     char const * const key;
92     Lazy<pcrecpp::RE,std::string> regex;
93 };
94
95 /*
96  * Struct defining an appsvc operation and a list of scheme conversions used to
97  * fill in additional appsvc data.
98  */
99 struct AppSvcOperation {
100     const char* operation;
101     bool needUri;
102     std::list<AppSvcConversion> conversions;
103 };
104
105 typedef std::map<Scheme::Type, AppSvcOperation> AppSvcOperationMap;
106
107 // Regular expressions used to extract appsvc data from scheme
108 // TODO what about multiple recipients?
109 char const * const REGEX_BODY =         ".*[?&]body=([^&]+).*";
110 char const * const REGEX_SMS =           "sms:([^&]+).*";
111 char const * const REGEX_MMSTO =        "mmsto:([^&]+).*";
112 char const * const REGEX_MAILTO =       "mailto:([^&]+).*";
113 char const * const REGEX_TO =           ".*[?&]to=([^&]+).*";
114 char const * const REGEX_CC =           ".*[?&]cc=([^&]+).*";
115 char const * const REGEX_BCC =          ".*[?&]bcc=([^&]+).*";
116 char const * const REGEX_SUBJECT =      ".*[?&]subject=([^&]+).*";
117 char const * const REGEX_DATA_CONTEXT = ".*;phone-context=([^:]+).*";
118
119 AppSvcOperationMap initializeAppSvcOperations()
120 {
121     AppSvcOperationMap ret;
122
123     // FILE, HTTP & HTTPS
124     AppSvcOperation viewOp;
125     viewOp.operation = APPSVC_OPERATION_VIEW;
126     viewOp.needUri = true;
127     // no additional data
128     ret.insert(std::make_pair(Scheme::FILE, viewOp));
129     ret.insert(std::make_pair(Scheme::HTTP, viewOp));
130     ret.insert(std::make_pair(Scheme::HTTPS, viewOp));
131
132     // SMS
133     AppSvcOperation smsOp;
134     smsOp.operation = APPSVC_OPERATION_SEND_TEXT;
135     smsOp.needUri = false;
136     smsOp.conversions.push_back(AppSvcConversion(APPSVC_DATA_TO, REGEX_SMS));
137     smsOp.conversions.push_back(AppSvcConversion(APPSVC_DATA_TEXT, REGEX_BODY));
138     ret.insert(std::make_pair(Scheme::SMS, smsOp));
139
140     // MMSTO & MAILTO
141     AppSvcOperation sendOp;
142     sendOp.operation = APPSVC_OPERATION_SEND;
143     sendOp.needUri = false;
144     sendOp.conversions.push_back(AppSvcConversion(APPSVC_DATA_TO, REGEX_MMSTO));
145     sendOp.conversions.push_back(AppSvcConversion(APPSVC_DATA_TO, REGEX_MAILTO));
146     sendOp.conversions.push_back(AppSvcConversion(APPSVC_DATA_CC, REGEX_CC));
147     sendOp.conversions.push_back(
148             AppSvcConversion(APPSVC_DATA_BCC, REGEX_BCC));
149     sendOp.conversions.push_back(
150             AppSvcConversion(APPSVC_DATA_SUBJECT, REGEX_SUBJECT));
151     sendOp.conversions.push_back(
152             AppSvcConversion(APPSVC_DATA_TEXT, REGEX_BODY));
153     ret.insert(std::make_pair(Scheme::MMSTO, sendOp));
154     ret.insert(std::make_pair(Scheme::MAILTO, sendOp));
155
156     // TODO what about DATA?
157
158     // TEL
159     AppSvcOperation telOp;
160     telOp.operation = APPSVC_OPERATION_CALL;
161     telOp.needUri = false;
162     //telOp.conversions.push_back(
163     //      AppSvcConversion(APPSVC_DATA_CONTEXT, REGEX_DATA_CONTEXT)); //TODO
164     ret.insert(std::make_pair(Scheme::TEL, telOp));
165
166     return ret;
167 }
168
169 AppSvcOperationMap g_appSvcOperationMap = initializeAppSvcOperations();
170
171 } // namespace
172
173
174 namespace SchemeActionMap {
175
176 bool HandleUri(const char* uri,
177                NavigationContext context,
178                WrtDB::AppType appType)
179 {
180     if (!uri) {
181         LogError("wrong arguments passed");
182         return false;
183     }
184     LogDebug("Uri being checked: " << uri);
185
186     const char *end = strstr(uri, ":");
187     if (!end) {
188         LogError("Lack of scheme - ignoring");
189         return false;
190     }
191     std::string name(uri, end);
192     Scheme scheme(name);
193     LogDebug("Scheme: " << name);
194
195     Scheme::Type type = scheme.GetType();
196     if (type < Scheme::FILE || type >= Scheme::COUNT) {
197         LogError("Invalid scheme: " << name);
198         return false;
199     }
200
201     LogDebug("Scheme type: " << type);
202     LogDebug("Navigation context: " << context);
203     LogDebug("Application type: " << appType);
204
205     UriAction action;
206     switch (appType) {
207     case WrtDB::APP_TYPE_WAC20:
208         action = g_wacActionMap[type][context];
209         break;
210     case WrtDB::APP_TYPE_TIZENWEBAPP:
211         action = g_tizenActionMap[type][context];
212         break;
213     default:
214         LogError("Unsupported application type: " << type);
215         return false;
216     }
217
218     LogDebug("Uri action: " << action);
219
220     // execute action if necessary
221     switch (action) {
222     case URI_ACTION_APPSVC:
223     {
224         // find AppSvcOperation for given scheme type
225         auto it = g_appSvcOperationMap.find(type);
226         if (it == g_appSvcOperationMap.end()) {
227             LogError("No entry for scheme: " << name);
228             return false;
229         }
230
231         // prepare appsvc bundle
232         bundle* bundleData = bundle_create();
233         LogDebug("appsvc operation " << it->second.operation);
234         appsvc_set_operation(bundleData, it->second.operation);
235         if (it->second.needUri) {
236             appsvc_set_uri(bundleData, uri);
237         }
238
239         // this is safe as there are no other threads
240         CURL* curl = curl_easy_init();
241         // unescape the url
242         int outLength = 0;
243         char* unescaped = curl_easy_unescape(curl, uri, 0, &outLength);
244         std::string uUri(unescaped, outLength);
245         curl_free(unescaped);
246         curl_easy_cleanup(curl);
247         LogDebug("unescaped " << uUri);
248
249         // setup additional appsvc data
250         FOREACH(cit, it->second.conversions) {
251             LogDebug("extracting data for key " << cit->key);
252
253             std::string match;
254             pcrecpp::StringPiece input(uUri);
255
256             // convert scheme text to appsvc format
257             while (cit->regex->Consume(&input, &match)) {
258                 LogInfo("Adding apssvc data: " << cit->key << " " << match);
259                 appsvc_add_data(bundleData, cit->key, match.c_str());
260             }
261         }
262
263         // TODO do we need a callback?
264         CONTROLLER_POST_EVENT(
265                 ApplicationLauncher,
266                 ApplicationLauncherEvents::LaunchApplicationByAppService(
267                         bundleData,
268                         NULL,
269                         NULL));
270         break;
271     }
272
273     case URI_ACTION_VIDEO:
274         CONTROLLER_POST_EVENT(
275                 ApplicationLauncher,
276                 ApplicationLauncherEvents::LaunchApplicationByPkgname(
277                         ApplicationLauncherPkgname::PKG_NAME_VIDEO_PLAYER,
278                         name,
279                         uri,
280                         "null"));
281         break;
282     default:
283         break;
284     }
285     return (action == URI_ACTION_WRT);
286 }
287
288 } // namespace SchemeActionMap
289
290 } /* namespace ViewModule */