Refactor DBManager
[platform/core/appfw/watchface-complication.git] / watchface-complication / db-manager.cc
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
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 <dlog.h>
18 #include <unistd.h>
19 #include <sqlite3.h>
20 #include <tzplatform_config.h>
21 #include <pkgmgr-info.h>
22 #include <pkgmgr_installer_info.h>
23 #include <vconf.h>
24
25 #include "watchface-complication/include/watchface-complication-internal.h"
26 #include "watchface-complication/db-manager.h"
27 #include "watchface-common/watchface-util.h"
28
29 #ifdef LOG_TAG
30 #undef LOG_TAG
31 #endif
32
33 #define LOG_TAG "WATCHFACE_COMPLICATION"
34
35 #define DEFAULT_LOCALE "No Locale"
36 #define ROOT_USER 0
37
38 using namespace tizen_base;
39
40 namespace {
41 class DBHelper {
42  public:
43   using Cursor = std::unique_ptr<sqlite3_stmt, decltype(sqlite3_finalize)*>;
44   DBHelper()
45       : db_(nullptr, sqlite3_close_v2), stmt_(nullptr, sqlite3_finalize) {}
46
47   bool Open() {
48     const char* path = GetParserDataPath();
49     if (path == nullptr)
50       return false;
51
52     sqlite3* db = nullptr;
53     int ret = sqlite3_open_v2(path, &db, SQLITE_OPEN_READONLY, nullptr);
54     if (ret != SQLITE_OK) {
55       LOGE("open db(%s) error: %d", path, ret);
56       return false;
57     }
58
59     db_.reset(db);
60
61     return true;
62   }
63
64   void Close() {
65     db_.reset();
66   }
67
68   bool Prepare(const std::string& query) {
69     sqlite3_stmt* stmt = nullptr;
70     if (sqlite3_prepare_v2(db_.get(), query.c_str(), query.size(), &stmt,
71         nullptr) != SQLITE_OK) {
72       LOGE("prepare error: %s", sqlite3_errmsg(db_.get()));
73       return false;
74     }
75
76     stmt_.reset(stmt);
77
78     return true;
79   }
80
81   const Cursor& GetCursor() const {
82     return stmt_;
83   }
84
85   int Step() const {
86     return sqlite3_step(stmt_.get());
87   }
88
89   bool Bind(int pos, std::string text) {
90     int ret = sqlite3_bind_text(stmt_.get(), pos, text.c_str(),
91       -1, SQLITE_TRANSIENT);
92     if (ret != SQLITE_OK) {
93       LOGE("bind error: %s", sqlite3_errmsg(db_.get()));
94       return false;
95     }
96
97     return true;
98   }
99
100   bool Bind(int pos, int val) {
101     if (sqlite3_bind_int(stmt_.get(), pos, val) != SQLITE_OK) {
102       LOGE("bind error: %s", sqlite3_errmsg(db_.get()));
103       return false;
104     }
105
106     return true;
107   }
108
109   const char* GetText(int pos) const {
110     return reinterpret_cast<const char*>(sqlite3_column_text(stmt_.get(), pos));
111   }
112
113   int GetInt(int pos) const {
114     return sqlite3_column_int(stmt_.get(), pos);
115   }
116
117  private:
118   const char* GetParserDataPath() const {
119     uid_t target_uid;
120     const char* path;
121     bool is_global;
122
123     pkgmgr_installer_info_get_target_uid(&target_uid);
124
125     if (target_uid == ROOT_USER
126       || target_uid == tzplatform_getuid(TZ_SYS_GLOBALAPP_USER))
127       is_global = true;
128     else
129       is_global = false;
130
131     if (!is_global)
132         tzplatform_set_user(target_uid);
133
134     path = tzplatform_mkpath(is_global ? TZ_SYS_DB : TZ_USER_DB,
135         ".complication_provider.db");
136     tzplatform_reset_user();
137
138     return path;
139   }
140
141  private:
142   std::unique_ptr<sqlite3, decltype(sqlite3_close_v2)*> db_;
143   Cursor stmt_;
144 };
145 }  // namespace
146
147 namespace watchface_complication {
148
149 DBManager::DBManager() = default;
150 DBManager::~DBManager() = default;
151
152 std::unique_ptr<Bundle> DBManager::GetDefaultData(const char* provider_id,
153                                                   int support_type) {
154   static const char query[] =
155     "SELECT trusted, appid, default_data FROM complication_provider "
156     "WHERE provider_id=? AND support_type=?";
157
158   ::DBHelper db;
159
160   if (!db.Open())
161     return nullptr;
162
163   if (!db.Prepare(query))
164     return nullptr;
165
166   if (!db.Bind(1, provider_id))
167     return nullptr;
168
169   if (!db.Bind(2, support_type))
170     return nullptr;
171
172   if (db.Step() != SQLITE_ROW)
173     return nullptr;
174
175   int trusted = db.GetInt(0);
176   const char* app_id = db.GetText(1);
177   if (app_id == nullptr) {
178     LOGE("app_id is nullptr");
179     return nullptr;
180   }
181
182   std::string provider_app_id = app_id;
183   if (trusted && util::CheckCertificate(provider_app_id) == false)
184     return nullptr;
185
186   const char* raw_data = db.GetText(2);
187   if (raw_data == nullptr) {
188     LOGE("raw_data is nullptr");
189     return nullptr;
190   }
191
192   std::unique_ptr<Bundle> default_data;
193   try {
194     default_data = std::unique_ptr<Bundle>(new Bundle(std::string(raw_data)));
195   } catch (const std::exception& e) {
196     LOGE("Exception occurred : %s", e.what());
197     return nullptr;
198   }
199
200   util::ConvertPathToAppPath(provider_app_id.c_str(),
201       default_data.get()->GetHandle());
202
203   return default_data;
204 }
205
206 int DBManager::GetProviderPeriod(std::string& provider_id, int* period) {
207   static const char query[] =
208     "SELECT period FROM complication_provider WHERE provider_id=?";
209
210   ::DBHelper db;
211
212   if (!db.Open())
213     return WATCHFACE_COMPLICATION_ERROR_DB;
214
215   if (!db.Prepare(query))
216     return WATCHFACE_COMPLICATION_ERROR_DB;
217
218   if (!db.Bind(1, provider_id))
219     return WATCHFACE_COMPLICATION_ERROR_DB;
220
221   /* complication_provider table's default value of period is -1.
222   *  So, if nothing specified in period, it will return -1
223   */
224   if (db.Step() == SQLITE_ROW)
225     *period = db.GetInt(0);
226
227   return WATCHFACE_COMPLICATION_ERROR_NONE;
228 }
229
230 bool DBManager::IsProviderExist(std::string& provider_id, int support_type) {
231   static const char query[] =
232     "SELECT trusted, appid FROM complication_provider "
233     "WHERE provider_id=? AND support_type=?";
234   ::DBHelper db;
235
236   if (!db.Open())
237     return false;;
238
239   if (!db.Prepare(query))
240     return false;
241
242   if (!db.Bind(1, provider_id))
243     return false;
244
245   if (!db.Bind(2, support_type))
246     return false;
247
248   bool is_exist = false;
249   if (db.Step() == SQLITE_ROW) {
250     int trusted;
251
252     trusted = db.GetInt(0);
253     const char* app_id = db.GetText(1);
254     if (app_id == nullptr) {
255       LOGE("app_id is nullptr");
256       return false;
257     }
258     std::string provider_app_id = app_id;
259     if (trusted && util::CheckCertificate(provider_app_id) == false)
260       is_exist = false;
261     else
262       is_exist = true;
263   }
264
265   return is_exist;
266 }
267
268 std::string DBManager::GetProviderAppId(const char* provider_id) {
269   static const char query[] =
270     "SELECT trusted, appid FROM complication_provider WHERE provider_id=?";
271   ::DBHelper db;
272
273   if (!db.Open())
274     return std::string();
275
276   if (!db.Prepare(query))
277     return std::string();
278
279   if (!db.Bind(1, provider_id))
280     return std::string();
281
282   if (db.Step() != SQLITE_ROW)
283     return std::string();
284
285   int trusted = db.GetInt(0);
286   const char* app_id = db.GetText(1);
287
288   if (app_id == nullptr) {
289     LOGE("app_id is nullptr");
290     return std::string();
291   }
292
293   std::string provider_app_id = app_id;
294   if (trusted && util::CheckCertificate(provider_app_id) == false)
295     return std::string();
296
297   return provider_app_id;
298 }
299
300 std::list<std::unique_ptr<DBManager::ProviderInfo>>
301 DBManager::GetProviderListWithTypes(int supported_types) {
302   static const char query[] =
303     "SELECT trusted, appid, provider_id, support_type FROM complication_provider "
304     "WHERE (support_type & ?) > 0";
305   ::DBHelper db;
306
307   if (!db.Open())
308     return {};
309
310   if (!db.Prepare(query))
311     return {};
312
313   if (!db.Bind(1, supported_types))
314     return {};
315
316   std::list<std::unique_ptr<DBManager::ProviderInfo>> provider_list;
317   while (db.Step() == SQLITE_ROW) {
318     int trusted = db.GetInt(0);
319     const char* app_id = db.GetText(1);
320     if (app_id == nullptr) {
321       LOGE("app_id is nullptr");
322       continue;
323     }
324
325     if (trusted && util::CheckCertificate(std::string(app_id)) == false)
326       continue;
327
328     const char* provider_id = db.GetText(2);
329     if (provider_id == nullptr) {
330       LOGE("prodiver_id is nullptr");
331       continue;
332     }
333     int type = db.GetInt(3);
334     provider_list.emplace_back(
335         std::unique_ptr<ProviderInfo>(new ProviderInfo(provider_id, type)));
336   }
337
338   return std::move(provider_list);
339 }
340
341 std::list<std::string> DBManager::GetProviderListWithAppId(
342     const char* provider_app_id) {
343   static const char query[] =
344     "SELECT DISTINCT provider_id FROM complication_provider WHERE appid=?";
345   ::DBHelper db;
346
347   if (!db.Open())
348     return {};
349
350   if (!db.Prepare(query))
351     return {};
352
353   if (!db.Bind(1, std::string(provider_app_id)))
354     return {};
355
356   std::list<std::string> provider_list;
357   while (db.Step() == SQLITE_ROW) {
358     const char* provider = db.GetText(0);
359     if (provider == nullptr) {
360       LOGW("provider is nullptr");
361       continue;
362     }
363     provider_list.push_back(std::string(provider));
364   }
365
366   return provider_list;
367 }
368
369 int DBManager::GetSupportTypes(std::string& provider_id, int* types) {
370   static const char query[] =
371       "SELECT trusted, appid, SUM(support_type) FROM complication_provider "
372       "WHERE provider_id = ?";
373   ::DBHelper db;
374
375   if (!db.Open())
376     return WATCHFACE_COMPLICATION_ERROR_DB;
377
378   if (!db.Prepare(query))
379     return WATCHFACE_COMPLICATION_ERROR_DB;
380
381   if (!db.Bind(1, provider_id))
382     return WATCHFACE_COMPLICATION_ERROR_DB;
383
384   int supported_types = 0;
385   if (db.Step() == SQLITE_ROW) {
386     int trusted = db.GetInt(0);
387     const char* app_id = db.GetText(1);
388     if (app_id == nullptr) {
389       LOGE("app_id is nullptr");
390       return WATCHFACE_COMPLICATION_ERROR_DB;
391     }
392     std::string provider_app_id = app_id;
393     if (trusted && util::CheckCertificate(provider_app_id) == false)
394       supported_types = 0;
395     else
396       supported_types = db.GetInt(2);
397   }
398
399   *types = supported_types;
400
401   return WATCHFACE_COMPLICATION_ERROR_NONE;
402 }
403
404 std::list<std::string> DBManager::GetRequiredPrivilegeList(
405     std::string& provider_id) {
406   static const char query[] =
407     "SELECT DISTINCT privilege FROM provider_privilege WHERE provider_id=?";
408   ::DBHelper db;
409
410   if (!db.Open())
411     return {};
412
413   if (!db.Prepare(query))
414     return {};
415
416   if (!db.Bind(1, provider_id))
417     return {};
418
419   std::list<std::string> privlege_list;
420   while (db.Step() == SQLITE_ROW) {
421     const char* privilege = db.GetText(0);
422     if (privilege == nullptr) {
423       LOGW("privilege is nullptr");
424       continue;
425     }
426     privlege_list.push_back(std::string(privilege));
427   }
428
429   return privlege_list;
430 }
431
432 /*
433 Return WATCHFACE_COMPLICATION_EVENT_NONE if there is no required events.
434 Return bigger than 1 value if there is at least one required event.
435 Return -1 if error occurs.
436 */
437 int DBManager::GetRequiredSupportEvents(
438     std::string& provider_id) {
439   int support_events = WATCHFACE_COMPLICATION_EVENT_NONE;
440   static const char query[] =
441     "SELECT support_events FROM provider_support_events WHERE provider_id=?";
442   ::DBHelper db;
443
444   if (!db.Open())
445     return -1;
446
447   if (!db.Prepare(query))
448     return -1;
449
450   if (!db.Bind(1, provider_id))
451     return -1;
452
453   if (db.Step() == SQLITE_ROW)
454     support_events = db.GetInt(0);
455
456   return support_events;
457 }
458
459 char* DBManager::GetSystemLocale() {
460   char* lang;
461   char* locale;
462   char* ptr;
463   char* tmp;
464
465   lang = vconf_get_str(VCONFKEY_LANGSET);
466   if (lang == nullptr) {
467     locale = strdup(DEFAULT_LOCALE);
468     if (locale == nullptr) {
469       LOGE("out of memory");
470       return nullptr;
471     }
472     return locale;
473   }
474
475   tmp = strtok_r(lang, ".", &ptr);
476   if (tmp == nullptr) {
477     LOGE("failed to get language");
478     free(lang);
479     return nullptr;
480   }
481
482   locale = strdup(tmp);
483   if (locale == nullptr) {
484     LOGE("out of memory");
485     free(lang);
486     return nullptr;
487   }
488
489   for (int i = 0; i < static_cast<int>(strlen(locale)); i++) {
490     if (locale[i] == '_')
491       locale[i] = '-';
492
493     if (isupper(locale[i]))
494       locale[i] = tolower(locale[i]);
495   }
496
497   free(lang);
498
499   return locale;
500 }
501
502 std::string DBManager::GetLabel(const char* provider_id) {
503   static const char query[] =
504     "SELECT provider_label FROM provider_localized_info "
505     "WHERE provider_id=? AND locale=?";
506   ::DBHelper db;
507
508   if (!db.Open())
509     return std::string();
510
511   if (!db.Prepare(query))
512     return std::string();
513
514   char* locale = GetSystemLocale();
515   if (locale == nullptr)
516     return std::string();
517
518   std::unique_ptr<char, decltype(std::free)*> locale_ptr(locale, std::free);
519
520   if (!db.Bind(1, provider_id))
521     return std::string();
522
523   if (!db.Bind(2, locale_ptr.get()))
524     return std::string();
525
526   std::string label;
527   if (db.Step() == SQLITE_ROW) {
528     const char* lb = db.GetText(0);
529     if (lb == nullptr) {
530       LOGW("lb is nullptr");
531     } else {
532       label = lb;
533     }
534   }
535
536   if (label.empty()) {
537     sqlite3_reset(db.GetCursor().get());
538     sqlite3_clear_bindings(db.GetCursor().get());
539
540     db.Bind(1, provider_id);
541     db.Bind(2, DEFAULT_LOCALE);
542
543     if (db.Step() == SQLITE_ROW) {
544       const char* lb = db.GetText(0);
545       if (lb == nullptr) {
546         LOGW("lb is nullptr");
547       } else {
548         label = lb;
549       }
550     }
551   }
552
553   return label;
554 }
555
556 std::string DBManager::GetSetupAppId(const char* provider_id) {
557   static const char query[] =
558     "SELECT DISTINCT setup_appid FROM provider_setup_appid WHERE provider_id=?";
559   ::DBHelper db;
560
561   if (!db.Open())
562     return std::string();
563
564   if (!db.Prepare(query))
565     return std::string();
566
567   if (!db.Bind(1, provider_id))
568     return std::string();
569
570   std::string setup_appid;
571   if (db.Step() == SQLITE_ROW) {
572     const char* appid = db.GetText(0);
573     if (appid == nullptr) {
574       LOGE("appid is nullptr");
575       return std::string();
576     }
577     setup_appid = appid;
578   }
579
580   return setup_appid;
581 }
582
583 int DBManager::GetTrustedInfo(std::string& provider_id, bool* trusted) {
584   static const char query[] =
585       "SELECT trusted FROM complication_provider WHERE provider_id = ?";
586   ::DBHelper db;
587
588   if (!db.Open())
589     return WATCHFACE_COMPLICATION_ERROR_DB;
590
591   if (!db.Prepare(query))
592     return WATCHFACE_COMPLICATION_ERROR_DB;
593
594   if (!db.Bind(1, provider_id))
595     return WATCHFACE_COMPLICATION_ERROR_DB;
596
597   if (db.Step() != SQLITE_ROW)
598     return WATCHFACE_COMPLICATION_ERROR_INVALID_PARAMETER;
599
600   int trusted_info = db.GetInt(0);
601   if (trusted_info == 0)
602     *trusted = false;
603   else if (trusted_info == 1)
604     *trusted = true;
605   else
606     return WATCHFACE_COMPLICATION_ERROR_DB;
607
608   return WATCHFACE_COMPLICATION_ERROR_NONE;
609 }
610
611 }  // namespace watchface_complication