Tizen C++ Coding Rules
[platform/core/location/maps-plugin-here.git] / src / here_manager.cpp
1 /*
2  * Copyright (c) 2014 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 #include <unistd.h>
18 #include <libxml/xpath.h>
19
20 #include "here_manager.h"
21 #include "here_base.h"
22 #include "here_geocode.h"
23 #include "here_revgeocode.h"
24 #include "here_multirevgeocode.h"
25 #include "here_place.h"
26 #include "here_route.h"
27 #include "here_utils.h"
28 #include "here_view.h"
29 #include "heremaps-uc-dbus.h"
30
31 #include <common/HereConfig.h>
32 #include <app.h>
33 #include <iostream>
34 #include <fstream>
35 #include <string>
36 #include <vconf.h>
37 #include <vconf-internal-location-keys.h>
38
39 using namespace HERE_PLUGIN_NAMESPACE_PREFIX;
40 using namespace TIZEN_MAPS_NAMESPACE_PREFIX;
41
42 HERE_PLUGIN_BEGIN_NAMESPACE
43
44 HereManager *HereManager::m_pHereManager = NULL;
45 int HereManager::m_nRefCnt = 0;
46 pthread_mutex_t g_mtxRef;
47
48 HereManager::HereManager()
49 : m_nNextReqId(1),
50   m_hPref(NULL)
51 {
52         xmlInitParser();
53         m_hConnection = NULL;
54         pthread_mutex_init(&m_mtxHereList, NULL);
55         pthread_mutex_init(&g_mtxRef, NULL);
56 }
57
58 HereManager::~HereManager()
59 {
60         if (m_hConnection)
61         {
62                 connection_unset_type_changed_cb(m_hConnection);
63                 connection_destroy(m_hConnection);
64                 m_hConnection = NULL;
65         }
66
67         pthread_mutex_destroy(&m_mtxHereList);
68         pthread_mutex_destroy(&g_mtxRef);
69         xmlCleanupParser();
70 }
71
72 bool HereManager::Create()
73 {
74         bool result = false;
75
76         if (!m_pHereManager)
77                 m_pHereManager = new (std::nothrow) HereManager();
78
79         pthread_mutex_lock(&g_mtxRef);
80         if (m_pHereManager) {
81                 m_nRefCnt++;
82                 result = true;
83                 MAPS_LOGD("Created a HereManager instance (%d).", m_nRefCnt);
84         }
85         pthread_mutex_unlock(&g_mtxRef);
86
87         if (m_pHereManager)
88                 m_pHereManager->SetCredentials();
89         return result;
90 }
91
92 void HereManager::Close()
93 {
94         pthread_mutex_lock(&g_mtxRef);
95         bool terminate = (--m_nRefCnt == 0 && m_pHereManager);
96         pthread_mutex_unlock(&g_mtxRef);
97
98         if (terminate) {
99                 m_pHereManager->TerminateAllServices();
100                 HereConfig::Shutdown();
101
102                 delete m_pHereManager;
103                 m_pHereManager = NULL;
104         }
105         MAPS_LOGD("Closed a HereManager instance (%d).", m_nRefCnt);
106 }
107
108 HereManager* HereManager::GetHandler()
109 {
110         return m_pHereManager;
111 }
112
113 void* HereManager::CreateInstance(HereSvcType nHereSvc, void* pCbFunc,
114         void* pUserData, int *nReqId)
115 {
116         HereBase *pHere = NULL;
117
118         int reqId = m_nNextReqId++;
119         if (nReqId) *nReqId = reqId;
120
121         switch(nHereSvc)
122         {
123         case HERE_SVC_GEOCODE:
124                 pHere = (HereBase*)new (std::nothrow) HereGeocode(pCbFunc, pUserData, reqId);
125                 break;
126
127         case HERE_SVC_REV_GEOCODE:
128                 pHere = (HereBase*)new (std::nothrow) HereRevGeocode(pCbFunc, pUserData, reqId);
129                 break;
130
131         case HERE_SVC_PLACE:
132                 pHere = (HereBase*)new (std::nothrow) HerePlace(pCbFunc, pUserData, reqId);
133                 break;
134
135         case HERE_SVC_ROUTE:
136                 pHere = (HereBase*)new (std::nothrow) HereRoute(pCbFunc, pUserData, reqId);
137                 break;
138
139         case HERE_SVC_MULTI_REV_GEOCODE:
140                 pHere = (HereBase*)new (std::nothrow) HereMultiRevGeocode(pCbFunc, pUserData, reqId);
141                 break;
142
143         case HERE_SVC_VIEW:
144                 pHere = (HereBase*)new (std::nothrow) HereView();
145                 break;
146
147         default:
148                 return NULL;
149         }
150
151         pthread_mutex_lock(&m_mtxHereList);
152         if (pHere)
153                 m_HereList.push_back(pHere);
154         pthread_mutex_unlock(&m_mtxHereList);
155
156         return pHere;
157 }
158
159 here_error_e HereManager::CloseInstance(int nReqId)
160 {
161         HereSvcList::iterator it;
162
163         pthread_mutex_lock(&m_mtxHereList);
164         for (it = m_HereList.begin(); it != m_HereList.end(); it++) {
165                 if ((*it)->GetReqId() == nReqId) {
166                         m_HereList.erase(it);
167                         break;
168                 }
169         }
170         pthread_mutex_unlock(&m_mtxHereList);
171
172         return HERE_ERROR_NONE;
173 }
174
175 here_error_e HereManager::CancelInstance(int nReqId)
176 {
177         HereSvcList::iterator it;
178
179         pthread_mutex_lock(&m_mtxHereList);
180         for (it = m_HereList.begin(); it != m_HereList.end(); it++) {
181                 if ((*it)->GetReqId() == nReqId) {
182                         m_HereList.erase(it);
183                         RestItemHandle::Cancel((*it)->GetRestReqId());
184                         (*it)->TerminateService();
185                         pthread_mutex_unlock(&m_mtxHereList);
186                         return HERE_ERROR_NONE;
187                 }
188         }
189         pthread_mutex_unlock(&m_mtxHereList);
190
191         return HERE_ERROR_NOT_FOUND;
192 }
193
194 bool HereManager::AppInfoMetadataCb(const char *metadata_key, const char *metadata_value, void *user_data)
195 {
196         if (!metadata_key || !metadata_value)
197                 return false;
198
199         if (!strncmp(metadata_key, "http://tizen.org/metadata/here_key", 35) && strlen(metadata_value) > 0) {
200                 if (m_pHereManager->SetCredentials(metadata_value) == HERE_ERROR_NONE)
201                         MAPS_LOGD("Succeeded getting credential from metadata");
202
203                 return false;
204         }
205
206         return true;
207 }
208
209 here_error_e HereManager::SetCredentials(void)
210 {
211         int nRet = 0;
212         app_info_h hAppInfo;
213         pid_t nProcessId = -1;
214         char *strAppId = NULL;
215
216         nProcessId = getpid();
217         nRet = app_manager_get_app_id(nProcessId, &strAppId);
218         if (nRet != APP_MANAGER_ERROR_NONE) {
219                 MAPS_LOGI("Get app_id [%ld]. nRet[%d]", nProcessId, nRet);
220                 return HERE_ERROR_NONE;
221         }
222
223         nRet = app_info_create(strAppId, &hAppInfo);
224         if (nRet != APP_MANAGER_ERROR_NONE) {
225                 MAPS_LOGI("Get appinfo of [%s]. nRet[%d]", strAppId, nRet);
226                 if (strAppId) free(strAppId);
227                 return HERE_ERROR_NONE;
228         }
229
230         if (strAppId) free(strAppId);
231
232         nRet = app_info_foreach_metadata(hAppInfo, AppInfoMetadataCb, NULL);
233         if (nRet != APP_MANAGER_ERROR_NONE)
234                 MAPS_LOGI("Get metadata. nRet[%d]", nRet);
235
236         nRet = app_info_destroy(hAppInfo);
237         if (nRet != APP_MANAGER_ERROR_NONE)
238                 MAPS_LOGI("Destroy app_info. nRet[%d]", nRet);
239
240         return HERE_ERROR_NONE;
241 }
242
243 here_error_e HereManager::SetCredentials(const char *szKey)
244 {
245         if (!szKey)
246                 return HERE_ERROR_INVALID_PARAMETER;
247
248         String strKey(szKey);
249         String strAppId, strAppCode, strRequestAppId = "";
250         size_t nCodeStart;
251
252         nCodeStart = strKey.find("/");
253
254         if(nCodeStart == 0 || nCodeStart >= (strKey.length()-1)) {
255                 MAPS_LOGE("[error] Key type fault : Key type should be as like XXXXX/YYYYY");
256                 return HERE_ERROR_INVALID_PARAMETER;
257         }
258
259         strAppId = strKey.substr(0, nCodeStart);
260         strAppCode = strKey.substr(nCodeStart+1, std::string::npos);
261
262         if (ApplicationContext::GetInstance().GetRequestAppId().length() < 1) {
263                 char *strAppId = NULL;
264                 pid_t nProcessId = getpid();
265
266                 app_manager_get_app_id(nProcessId, &strAppId);
267                 if (strAppId != NULL) {
268                         MAPS_LOGE("RequestAppId is %s", strAppId);
269                         strRequestAppId.append(strAppId);
270                         g_free(strAppId);
271                 }
272         } else {
273                 strRequestAppId = ApplicationContext::GetInstance().GetRequestAppId();
274         }
275
276         if(!ApplicationContext::GetInstance().Initialize(strAppCode, strAppId, strRequestAppId))
277                 return HERE_ERROR_INVALID_OPERATION;
278
279         //MAPS_LOGD("[success] credential setted to 'XXXXX/XXXXX'");
280
281         return HERE_ERROR_NONE;
282 }
283
284 here_error_e HereManager::GetCredentials(char **szKey)
285 {
286         if (!szKey)
287                 return HERE_ERROR_INVALID_PARAMETER;
288
289         if (!ApplicationContext::GetInstance().IsInitialized())
290                 return HERE_ERROR_NOT_FOUND;
291
292         String strCredentials = ApplicationContext::GetInstance().GetAppId() + "/" +
293                                 ApplicationContext::GetInstance().GetAppCode();
294
295         *szKey = g_strndup(strCredentials.c_str(), strCredentials.length());
296
297         if (*szKey == NULL)
298                 return HERE_ERROR_INVALID_OPERATION;
299
300         //MAPS_LOGD("current credential : %s", *szKey);
301
302         return HERE_ERROR_NONE;
303 }
304
305 here_error_e HereManager::SetPreference(maps_preference_h hPref)
306 {
307         int error = HERE_ERROR_NONE;
308
309         if (!hPref)
310                 return HERE_ERROR_INVALID_PARAMETER;
311
312         if (m_hPref) {
313                 if (maps_preference_destroy(m_hPref) != MAPS_ERROR_NONE)
314                         return HERE_ERROR_INVALID_OPERATION;
315         }
316
317         do {
318                 error = maps_preference_clone(hPref, &m_hPref);
319                 if (error != MAPS_ERROR_NONE) break;
320
321                 char *szLanguage = NULL;
322                 error = maps_preference_get_language(hPref, &szLanguage);
323                 if (error == MAPS_ERROR_NONE && szLanguage && strlen(szLanguage) > 0)
324                         ApplicationContext::GetInstance().SetPreferredLanguage(String(szLanguage));
325         } while (0);
326
327         return (here_error_e)ConvertToHereError(error);
328 }
329
330 here_error_e HereManager::GetPreference(maps_preference_h *hPref)
331 {
332         int ret = HERE_ERROR_NONE;
333
334         if (!hPref)
335                 return HERE_ERROR_INVALID_PARAMETER;
336
337         if (!m_hPref)
338                 return HERE_ERROR_NOT_FOUND;
339
340         ret = maps_preference_clone(m_hPref, hPref);
341
342         return (here_error_e)ConvertToHereError(ret);
343 }
344
345 maps_preference_h HereManager::GetPreference()
346 {
347         return m_hPref;
348 }
349
350 void HereManager::TerminateAllServices(void)
351 {
352         HereSvcList::iterator it;
353
354         while (1) {
355                 pthread_mutex_lock(&m_mtxHereList);
356                 if (m_HereList.empty()) {
357                         pthread_mutex_unlock(&m_mtxHereList);
358                         break;
359                 }
360                 it = m_HereList.begin();
361                 pthread_mutex_unlock(&m_mtxHereList);
362
363                 try {
364                         if (*it) (*it)->TerminateService();
365                         m_HereList.erase(it);
366                 } catch (std::exception &e) {
367                         MAPS_LOGD("Exception caught: %s", e.what());
368                 }
369         };
370
371         if (m_hPref) {
372                 maps_preference_destroy(m_hPref);
373                 m_hPref = NULL;
374         }
375 }
376
377 here_error_e HereManager::ConvertNetworkErrorCode(const int nErrorCode)
378 {
379         here_error_e err = HERE_ERROR_NONE;
380
381         switch (nErrorCode) {
382         case CONNECTION_ERROR_NONE:
383                 //MAPS_LOGD("No error");
384                 err = HERE_ERROR_NONE;
385                 break;
386         case CONNECTION_ERROR_INVALID_PARAMETER:
387                 MAPS_LOGD("Invalid parameter");
388                 err = HERE_ERROR_INVALID_PARAMETER;
389                 break;
390         case CONNECTION_ERROR_OUT_OF_MEMORY:
391                 MAPS_LOGD("Out of memory error");
392                 err = HERE_ERROR_OUT_OF_MEMORY;
393                 break;
394         case CONNECTION_ERROR_INVALID_OPERATION:
395                 MAPS_LOGD("Invalid Operation");
396                 err = HERE_ERROR_INVALID_OPERATION;
397                 break;
398         case CONNECTION_ERROR_ADDRESS_FAMILY_NOT_SUPPORTED:
399                 MAPS_LOGD("Address family not supported");
400                 err = HERE_ERROR_NOT_SUPPORTED;
401                 break;
402         case CONNECTION_ERROR_PERMISSION_DENIED:
403                 MAPS_LOGD("Permission denied");
404                 err = HERE_ERROR_PERMISSION_DENIED;
405                 break;
406         case CONNECTION_ERROR_OPERATION_FAILED:
407                 MAPS_LOGD("Operation failed");
408                 err = HERE_ERROR_INVALID_OPERATION;
409                 break;
410         case CONNECTION_ERROR_ITERATOR_END:
411                 MAPS_LOGD("End of iteration");
412                 break;
413         case CONNECTION_ERROR_NO_CONNECTION:
414                 MAPS_LOGD("There is no connection");
415                 err = HERE_ERROR_NETWORK_UNREACHABLE;
416                 break;
417         case CONNECTION_ERROR_NOW_IN_PROGRESS:
418                 MAPS_LOGD("Now in progress");
419                 err = HERE_ERROR_RESOURCE_BUSY;
420                 break;
421         case CONNECTION_ERROR_ALREADY_EXISTS:
422                 MAPS_LOGD("Already exists");
423                 break;
424         case CONNECTION_ERROR_OPERATION_ABORTED:
425                 MAPS_LOGD("Operation is aborted");
426                 err = HERE_ERROR_CANCELED;
427                 break;
428         case CONNECTION_ERROR_DHCP_FAILED:
429                 MAPS_LOGD("DHCP failed");
430                 break;
431         case CONNECTION_ERROR_INVALID_KEY:
432                 MAPS_LOGD("Invalid key");
433                 err = HERE_ERROR_KEY_NOT_AVAILABLE;
434                 break;
435         case CONNECTION_ERROR_NO_REPLY:
436                 MAPS_LOGD("No Reply");
437                 err = HERE_ERROR_RESOURCE_BUSY;
438                 break;
439         case CONNECTION_ERROR_NOT_SUPPORTED:
440                 MAPS_LOGD("Not Supported");
441                 err = HERE_ERROR_NOT_SUPPORTED;
442                 break;
443         default:
444                 MAPS_LOGD("Unknown");
445                 break;
446         }
447         //MAPS_LOGD("nErrorCode = 0x%08X", nErrorCode);
448
449         return err;
450 }
451
452 here_error_e HereManager::SetProxyAddress()
453 {
454         int errorCode = CONNECTION_ERROR_NONE;
455
456         char *proxy_address = NULL;
457
458         if (!m_hConnection) {
459                 errorCode = connection_create(&m_hConnection);
460                 if (errorCode == CONNECTION_ERROR_NONE)
461                         errorCode = connection_set_type_changed_cb(m_hConnection, NetworkStateChangedIndCb, this);
462         }
463         if (errorCode != CONNECTION_ERROR_NONE)
464                 return ConvertNetworkErrorCode(errorCode);
465
466         errorCode = connection_get_proxy(m_hConnection, CONNECTION_ADDRESS_FAMILY_IPV4, &proxy_address);
467         if (errorCode == CONNECTION_ERROR_NONE) {
468                 MAPS_LOGD("Proxy = %s", (proxy_address ? proxy_address : "(null)"));
469                 Tizen::Maps::HereConfig::SetProxyAddress(proxy_address);
470         }
471         g_free(proxy_address);
472
473         return ConvertNetworkErrorCode(errorCode);
474 }
475
476 void HereManager::NetworkStateChangedIndCb(connection_type_e type, void *user_data)
477 {
478         MAPS_LOGD("Network state is changed. type=%d", type);
479
480         if (!user_data) return;
481
482         HereManager *pManager = (HereManager*)user_data;
483
484         if ((type != CONNECTION_TYPE_DISCONNECTED) && (type != CONNECTION_TYPE_BT))
485                 pManager->SetProxyAddress();
486 }
487
488 here_error_e HereManager::CheckAgreement()
489 {
490         const char UTC_TPK_APP[] = "org.tizen.capi-maps-service-native-utc";
491         const char ITC_TPK_APP[] = "org.tizen.capi-maps-service-native-itc";
492         const char UTC_APP[] = "core.capi-maps-service-tests";
493         const char ITC_APP[] = "native.capi-maps-service-itc";
494
495         int enabled = 0;
496         int ret = 0;
497         char *strAppId = NULL;
498         here_error_e error = HERE_ERROR_NONE;
499
500         ret = vconf_get_bool(VCONFKEY_LOCATION_HEREMAPS_CONSENT, &enabled);
501         MAPS_LOGD("VCONFKEY_LOCATION_HEREMAPS_CONSENT is %d", enabled);
502         if (ret != 0 || enabled == 0) {
503                 error = HERE_ERROR_SERVICE_NOT_AVAILABLE;
504                 if (ret != 0)
505                         MAPS_LOGD("Fail to get vconf value");
506
507                 pid_t nProcessId = getpid();
508                 ret = app_manager_get_app_id(nProcessId, &strAppId);
509                 if (ret != APP_MANAGER_ERROR_NONE)
510                         MAPS_LOGI("Get app_id [%ld]. nRet[%d]", nProcessId, ret);
511                 else if (!strncmp(strAppId, UTC_APP, strlen(UTC_APP)) ||
512                                 !strncmp(strAppId, ITC_APP, strlen(ITC_APP)) ||
513                                 !strncmp(strAppId, UTC_TPK_APP, strlen(UTC_TPK_APP)) ||
514                                 !strncmp(strAppId, ITC_TPK_APP, strlen(ITC_TPK_APP))) { 
515                         MAPS_LOGD("Requested by tct");
516                         error = HERE_ERROR_NONE;
517                 }
518         }
519
520         if (error != HERE_ERROR_NONE) {
521                 MAPS_LOGD("heremaps_uc_dbus_launch_receiver is called");
522                 ret = heremaps_uc_dbus_launch_receiver();
523                 if (ret != HEREMAPS_UC_DBUS_ERROR_NONE)
524                         MAPS_LOGD("heremaps_uc_dbus_launch_receiver fail");
525         } else
526                 MAPS_LOGD("Vconf value of HereMaps is true");
527
528         if (strAppId != NULL)
529                 g_free(strAppId);
530         return error;
531 }
532
533 HERE_PLUGIN_END_NAMESPACE
534