2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * @file scheme_action_map.cpp
18 * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
22 #include "scheme_action_map.h"
24 #include <dpl/log/log.h>
25 #include <dpl/event/controller.h>
26 #include <application_launcher.h>
30 #include <curl/curl.h>
31 #include "scheme_action_map_data.h"
33 namespace ViewModule {
36 * Lazy construction pattern.
37 * TODO Make it more general. Use variadic template/tuples/lambdas or sth. Move
40 template <typename T, typename Arg1>
44 explicit Lazy(const Arg1& arg1) :
46 m_object(new std::unique_ptr<T>())
48 Lazy(const Lazy<T, Arg1>& other) :
50 m_object(other.m_object)
57 const T& operator*() const
61 const T* operator->() const
70 Lazy<T, Arg1>& operator=(const Lazy<T, Arg1>& other)
72 m_arg1 = other.m_arg1;
73 m_object = other.m_object;
81 (*m_object).reset(new T(m_arg1));
87 // single unique_ptr shared among many Lazy copies
88 mutable std::shared_ptr<std::unique_ptr<T> > m_object;
92 * Struct defining conversion of scheme for given appsvc key for example:
93 * sms:5551212?body=expected%20text => APPSVC_DATA_TEXT + expected%20text
95 struct AppSvcConversion {
96 AppSvcConversion(char const * const keyValue,
97 const std::string& regexStr) :
100 char const * const key;
101 Lazy<pcrecpp::RE, std::string> regex;
105 * Struct defining an appsvc operation and a list of scheme conversions used to
106 * fill in additional appsvc data.
108 struct ServiceOperation {
109 const char* operation;
112 std::list<AppSvcConversion> conversions;
115 typedef std::map<Scheme::Type, ServiceOperation> ServiceOperationMap;
117 // Regular expressions used to extract appsvc data from scheme
118 // TODO what about multiple recipients?
119 char const * const REGEX_BODY = ".*[?&]body=([^&]+).*";
120 char const * const REGEX_SMS = "sms:([^&]+).*";
121 char const * const REGEX_SMSTO = "smsto:([^&]+).*";
122 char const * const REGEX_MMSTO = "mmsto:([^&]+).*";
123 char const * const REGEX_MAILTO = "mailto:([^&]+).*";
124 char const * const REGEX_TO = ".*[?&]to=([^&]+).*";
125 char const * const REGEX_CC = ".*[?&]cc=([^&]+).*";
126 char const * const REGEX_BCC = ".*[?&]bcc=([^&]+).*";
127 char const * const REGEX_SUBJECT = ".*[?&]subject=([^&]+).*";
128 char const * const REGEX_DATA_CONTEXT = ".*;phone-context=([^:]+).*";
130 ServiceOperationMap initializeAppSvcOperations()
132 ServiceOperationMap ret;
134 // FILE, HTTP & HTTPS
135 ServiceOperation viewOp;
136 viewOp.operation = SERVICE_OPERATION_VIEW;
137 viewOp.fakeUri = NULL;
139 // no additional data
140 ret.insert(std::make_pair(Scheme::FILE, viewOp));
141 ret.insert(std::make_pair(Scheme::HTTP, viewOp));
142 ret.insert(std::make_pair(Scheme::HTTPS, viewOp));
145 ServiceOperation smsOp;
146 smsOp.operation = SERVICE_OPERATION_COMPOSE;
147 smsOp.fakeUri = NULL;
149 smsOp.conversions.push_back(AppSvcConversion(SERVICE_DATA_TO, REGEX_SMS));
150 smsOp.conversions.push_back(AppSvcConversion(SERVICE_DATA_TEXT, REGEX_BODY));
151 ret.insert(std::make_pair(Scheme::SMS, smsOp));
154 ServiceOperation smstoOp;
155 smstoOp.operation = SERVICE_OPERATION_COMPOSE;
156 smstoOp.fakeUri = "sms";
157 smstoOp.mime = "*/*";
158 smstoOp.conversions.push_back(AppSvcConversion(SERVICE_DATA_TO, REGEX_SMSTO));
159 smstoOp.conversions.push_back(AppSvcConversion(SERVICE_DATA_TEXT, REGEX_BODY));
160 ret.insert(std::make_pair(Scheme::SMSTO, smstoOp));
164 ServiceOperation sendOp;
165 sendOp.operation = SERVICE_OPERATION_COMPOSE;
166 sendOp.fakeUri = NULL;
168 sendOp.conversions.push_back(AppSvcConversion(SERVICE_DATA_TO, REGEX_MMSTO));
169 sendOp.conversions.push_back(AppSvcConversion(SERVICE_DATA_TO, REGEX_MAILTO));
170 sendOp.conversions.push_back(AppSvcConversion(SERVICE_DATA_CC, REGEX_CC));
171 sendOp.conversions.push_back(
172 AppSvcConversion(SERVICE_DATA_BCC, REGEX_BCC));
173 sendOp.conversions.push_back(
174 AppSvcConversion(SERVICE_DATA_SUBJECT, REGEX_SUBJECT));
175 sendOp.conversions.push_back(
176 AppSvcConversion(SERVICE_DATA_TEXT, REGEX_BODY));
177 ret.insert(std::make_pair(Scheme::MAILTO, sendOp));
179 ret.insert(std::make_pair(Scheme::MMSTO, sendOp));
181 // TODO what about DATA?
184 ServiceOperation telOp;
185 telOp.operation = SERVICE_OPERATION_CALL;
186 telOp.fakeUri = NULL;
188 ret.insert(std::make_pair(Scheme::TEL, telOp));
193 ServiceOperationMap g_serviceOperationMap = initializeAppSvcOperations();
195 void handleTizenServiceScheme(const char* uri)
197 // <a href="tizen-service:AppID=com.samsung.myfile; key=key1, value=value1; end">Tizen Service</a>
198 std::string parameter = std::string(uri);
200 size_t start, end = 0;
202 if (parameter.find("AppID=") != std::string::npos) {
203 start = parameter.find("AppID=") + strlen("AppID=");
204 end = parameter.find(";", start);
205 appId = parameter.substr(start, end-start);
207 LogError("parameter doesn't contain appID");
211 service_h handle = NULL;
212 if (service_create(&handle) != SERVICE_ERROR_NONE) {
213 LogError("Fail to create service handle");
217 if (service_set_app_id(handle, appId.c_str()) < 0) {
218 LogError("Fail to service_set_app_id");
219 service_destroy(handle);
223 const char* KEY_KEY = "key=";
224 const char* KEY_VALUE = "value=";
226 char* buf = strdup(parameter.c_str());
227 const char* ptr = strtok(buf,";");
228 while (ptr != NULL) {
229 std::string string = ptr;
230 ptr = strtok (NULL, ";");
232 size_t devide = string.find(',');
233 if (devide == std::string::npos) {
236 size_t keyPos = string.find(KEY_KEY);
237 if (keyPos == std::string::npos) {
240 size_t valuePos = string.find(KEY_VALUE);
241 if (valuePos == std::string::npos) {
246 string.substr(keyPos + std::string(KEY_KEY).size(),
247 devide - (keyPos + std::string(KEY_KEY).size()));
249 string.substr(valuePos + std::string(KEY_VALUE).size());
251 if (service_add_extra_data(handle, key.c_str(), value.c_str())) {
252 LogError("service_add_extra_data is failed.");
253 service_destroy(handle);
260 CONTROLLER_POST_EVENT(
262 ApplicationLauncherEvents::LaunchApplicationByAppService(
268 void handleUnknownScheme(const char* scheme, const char* uri)
270 LogError("Invalid scheme: " << scheme);
271 // case of unknown scheme, send to app-control
272 // This is temporary soultion. "invalid" scheme should be handled by
275 if (!strcmp(scheme, "tizen-service")) {
276 handleTizenServiceScheme(uri);
280 service_h serviceHandle = NULL;
281 if (SERVICE_ERROR_NONE != service_create(&serviceHandle)) {
282 service_set_operation(serviceHandle, SERVICE_OPERATION_VIEW);
283 service_set_uri(serviceHandle, uri);
284 CONTROLLER_POST_EVENT(
286 ApplicationLauncherEvents::LaunchApplicationByAppService(
297 namespace SchemeActionMap {
298 bool HandleUri(const char* uri, NavigationContext context)
301 LogError("wrong arguments passed");
304 LogDebug("Uri being checked: " << uri);
306 const char *end = strstr(uri, ":");
308 LogError("Lack of scheme - ignoring");
311 std::string name(uri, end);
313 LogDebug("Scheme: " << name);
315 Scheme::Type type = scheme.GetType();
316 if (type < Scheme::FILE || type >= Scheme::COUNT) {
317 LogError("Invalid scheme: " << name);
318 handleUnknownScheme(name.c_str(), uri);
322 LogDebug("Scheme type: " << type);
323 LogDebug("Navigation context: " << context);
325 UriAction action = g_tizenActionMap[type][context];
327 LogDebug("Uri action: " << action);
329 // execute action if necessary
331 case URI_ACTION_APPSVC:
333 // find AppSvcOperation for given scheme type
334 auto it = g_serviceOperationMap.find(type);
335 if (it == g_serviceOperationMap.end()) {
336 LogError("No entry for scheme: " << name);
340 // prepare appsvc bundle
341 service_h serviceHandle = NULL;
342 service_create(&serviceHandle);
343 LogDebug("appsvc operation " << it->second.operation);
344 service_set_operation(serviceHandle, it->second.operation);
345 if (it->second.fakeUri) {
346 size_t size = strlen(it->second.fakeUri) + strlen(uri) + 1;
347 char *newUri = new char[size];
348 strcpy(newUri, it->second.fakeUri);
349 const char* uriArgs = strstr(uri, ":");
350 strcpy(newUri + strlen(it->second.fakeUri), uriArgs);
351 service_set_uri(serviceHandle, newUri);
355 service_set_uri(serviceHandle, uri);
357 if (it->second.mime) {
358 service_set_mime(serviceHandle, it->second.mime);
361 // this is safe as there are no other threads
362 CURL* curl = curl_easy_init();
365 char* unescaped = curl_easy_unescape(curl, uri, 0, &outLength);
366 std::string uUri(unescaped, outLength);
367 curl_free(unescaped);
368 curl_easy_cleanup(curl);
369 LogDebug("unescaped " << uUri);
371 // setup additional appsvc data
372 FOREACH(cit, it->second.conversions) {
373 LogDebug("extracting data for key " << cit->key);
376 pcrecpp::StringPiece input(uUri);
378 // convert scheme text to appsvc format
379 while (cit->regex->Consume(&input, &match)) {
380 LogDebug("Adding apssvc data: " << cit->key << " " << match);
381 service_add_extra_data(serviceHandle, cit->key, match.c_str());
385 // TODO do we need a callback?
386 CONTROLLER_POST_EVENT(
388 ApplicationLauncherEvents::LaunchApplicationByAppService(
395 case URI_ACTION_VIDEO:
396 CONTROLLER_POST_EVENT(
398 ApplicationLauncherEvents::LaunchApplicationByPkgname(
399 ApplicationLauncherPkgname::PKG_NAME_VIDEO_PLAYER,
407 return (action == URI_ACTION_WRT);
409 } // namespace SchemeActionMap
410 } /* namespace ViewModule */