4 * Copyright (c) 2010 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
26 #include <image_util.h>
27 #include <unicode/ulocdata.h>
28 #include <unicode/uset.h>
29 #include <unicode/ustring.h>
30 #include <libexif/exif-data.h>
33 #include "ctsvc_internal.h"
34 #include "ctsvc_db_utils.h"
35 #include "ctsvc_mutex.h"
36 #include "ctsvc_db_sqlite.h"
37 #include "ctsvc_db_schema.h"
38 #include "ctsvc_notification.h"
39 #include "ctsvc_struct.h"
40 #include "ctsvc_normalize.h"
41 #include "ctsvc_localize.h"
42 #include "ctsvc_localize_utils.h"
43 #include "ctsvc_server_setting.h"
44 #include "ctsvc_notify.h"
45 #include "ctsvc_image_util.h"
47 #ifdef _CONTACTS_IPC_SERVER
48 #include "ctsvc_server_change_subject.h"
51 static __thread int transaction_count = 0;
52 static __thread int transaction_ver = 0;
53 static __thread bool version_up = false;
55 #define CTS_SECURITY_IMAGE_PERMISSION 0440
56 #define CTS_COMMIT_TRY_MAX 500000 /* For 3second */
58 int ctsvc_begin_trans(void)
60 int ret = -1, progress;
62 if (transaction_count <= 0) {
63 ret = ctsvc_query_exec("BEGIN IMMEDIATE TRANSACTION");
65 while (CONTACTS_ERROR_DB == ret && progress < CTS_COMMIT_TRY_MAX) {
67 ret = ctsvc_query_exec("BEGIN IMMEDIATE TRANSACTION");
70 if (CONTACTS_ERROR_NONE != ret) {
72 ERR("ctsvc_query_exec() Fail(%d)", ret);
77 transaction_count = 0;
79 const char *query = "SELECT ver FROM "CTS_TABLE_VERSION;
80 ret = ctsvc_query_get_first_int_result(query, &transaction_ver);
84 INFO("transaction_count : %d.", transaction_count);
85 return CONTACTS_ERROR_NONE;
88 int ctsvc_end_trans(bool is_success)
90 int ret = -1, progress;
91 char query[CTS_SQL_MIN_LEN] = {0};
94 INFO("%s, transaction_count : %d", is_success ? "True" : "False", transaction_count);
96 if (0 != transaction_count) {
97 DBG("contact transaction_count : %d.", transaction_count);
98 return CONTACTS_ERROR_NONE;
101 if (false == is_success) {
102 ctsvc_nofitication_cancel();
103 ctsvc_change_subject_clear_changed_info();
104 ret = ctsvc_query_exec("ROLLBACK TRANSACTION");
106 return CONTACTS_ERROR_NONE;
111 snprintf(query, sizeof(query), "UPDATE %s SET ver = %d",
112 CTS_TABLE_VERSION, transaction_ver);
113 ret = ctsvc_query_exec(query);
114 if (CONTACTS_ERROR_NONE != ret)
115 /* LCOV_EXCL_START */
116 ERR("ctsvc_query_exec(version up) Fail(%d)", ret);
120 INFO("start commit");
122 ret = ctsvc_query_exec("COMMIT TRANSACTION");
123 while (CONTACTS_ERROR_DB == ret && progress < CTS_COMMIT_TRY_MAX) {
125 ret = ctsvc_query_exec("COMMIT TRANSACTION");
128 INFO("%s", (CONTACTS_ERROR_NONE == ret) ? "commit" : "rollback");
130 if (CONTACTS_ERROR_NONE != ret) {
131 /* LCOV_EXCL_START */
133 ERR("ctsvc_query_exec() Fail(%d)", ret);
134 ctsvc_nofitication_cancel();
135 ctsvc_change_subject_clear_changed_info();
137 tmp_ret = ctsvc_query_exec("ROLLBACK TRANSACTION");
138 if (CONTACTS_ERROR_NONE != tmp_ret)
139 ERR("ctsvc_query_exec(ROLLBACK) Fail(%d)", tmp_ret);
145 ctsvc_notification_send();
146 ctsvc_change_subject_publish_changed_info();
148 DBG("Transaction shut down! : (%d)\n", transaction_ver);
150 return CONTACTS_ERROR_NONE;
153 const char* ctsvc_get_display_column(void)
155 contacts_name_display_order_e order;
157 ctsvc_setting_get_name_display_order(&order);
158 if (CONTACTS_NAME_DISPLAY_ORDER_FIRSTLAST == order)
159 return "display_name";
161 return "reverse_display_name";
164 const char* ctsvc_get_sort_name_column(void)
166 contacts_name_sorting_order_e order;
168 ctsvc_setting_get_name_sorting_order(&order);
169 if (CONTACTS_NAME_SORTING_ORDER_FIRSTLAST == order)
170 return "sort_name, display_name_language";
172 return "reverse_sort_name, reverse_display_name_language";
175 const char* ctsvc_get_sort_column(void)
177 contacts_name_sorting_order_e order;
179 ctsvc_setting_get_name_sorting_order(&order);
180 if (CONTACTS_NAME_SORTING_ORDER_FIRSTLAST == order)
181 return "display_name_language, sortkey";
183 return "reverse_display_name_language, reverse_sortkey";
186 void ctsvc_utils_make_image_file_name(int parent_id, int id, char *src_img, char *dest,
193 ext = strrchr(src_img, '.');
194 if (NULL == ext || strchr(ext, '/'))
197 lower_ext = strdup(ext);
198 if (NULL == lower_ext) {
199 /* LCOV_EXCL_START */
200 ERR("strdup() Fail");
206 *temp = tolower(*temp);
211 snprintf(dest, dest_size, "%d_%d%s", parent_id, id, lower_ext);
213 snprintf(dest, dest_size, "%d%s", id, ext);
217 static inline bool _ctsvc_check_available_image_space(int need_size)
223 ret = statfs(CTSVC_IMG_REPERTORY, &buf);
224 RETVM_IF(ret != 0, false, "statfs() Fail(%d)", ret);
226 size = (long long)buf.f_bavail * (buf.f_bsize);
228 if (need_size < size) /* if available space to copy a image is larger than need_size */
233 static image_util_rotation_e _ctsvc_image_get_rotation_info(const char *path)
237 image_util_rotation_e rotation = IMAGE_UTIL_ROTATION_NONE;
240 ed = exif_data_new_from_file(path);
242 /* LCOV_EXCL_START */
243 ERR("exif_data_new_from_file() Fail");
244 return IMAGE_UTIL_ROTATION_NONE;
248 entry = exif_data_get_entry(ed, EXIF_TAG_ORIENTATION);
250 ExifByteOrder mByteOrder = exif_data_get_byte_order(ed);
251 orientation = (int)exif_get_short(entry->data, mByteOrder);
252 if (orientation < 0 || 8 < orientation)
259 switch (orientation) {
260 case 1: /* Top-left */
261 rotation = IMAGE_UTIL_ROTATION_NONE;
263 case 2: /* Top-right */
264 rotation = IMAGE_UTIL_ROTATION_FLIP_HORZ;
266 case 3: /* Bottom-right */
267 rotation = IMAGE_UTIL_ROTATION_180;
269 case 4: /* Bottom-left */
270 rotation = IMAGE_UTIL_ROTATION_FLIP_VERT;
272 case 6: /* Right-top */
273 rotation = IMAGE_UTIL_ROTATION_90;
275 case 8: /* Left-bottom */
276 rotation = IMAGE_UTIL_ROTATION_270;
278 case 5: /* Left-top */
279 case 7: /* Right-bottom */
296 static bool _ctsvc_image_util_supported_jpeg_colorspace_cb(
297 image_util_colorspace_e colorspace, void *user_data)
305 void *buffer_temp = NULL;
307 image_util_rotation_e rotation;
308 image_info *info = user_data;
310 ret = ctsvc_image_util_get_mimetype(colorspace, &mimetype);
311 if (CONTACTS_ERROR_NONE != ret) {
312 info->ret = CONTACTS_ERROR_SYSTEM;
316 ret = image_util_decode_jpeg(info->src, colorspace, (unsigned char **)&buffer,
317 &width, &height, (unsigned int *)&size);
318 if (IMAGE_UTIL_ERROR_NONE != ret) {
319 info->ret = CONTACTS_ERROR_SYSTEM;
323 rotation = _ctsvc_image_get_rotation_info(info->src);
324 if (IMAGE_UTIL_ROTATION_NONE != rotation) { /* need rotate */
326 media_packet_h packet;
328 fmt = ctsvc_image_util_create_media_format(mimetype, width, height);
330 /* LCOV_EXCL_START */
331 ERR("ctsvc_image_util_create_media_format() Fail");
332 info->ret = CONTACTS_ERROR_SYSTEM;
338 packet = ctsvc_image_util_create_media_packet(fmt, buffer, (unsigned int)size);
341 if (NULL == packet) {
342 /* LCOV_EXCL_START */
343 ERR("ctsvc_image_util_create_media_packet() Fail");
344 media_format_unref(fmt);
345 info->ret = CONTACTS_ERROR_SYSTEM;
350 ret = ctsvc_image_util_rotate(packet, rotation, &buffer_temp, &size);
352 media_packet_destroy(packet);
353 media_format_unref(fmt);
355 if (CONTACTS_ERROR_NONE != ret) {
356 /* LCOV_EXCL_START */
357 info->ret = CONTACTS_ERROR_SYSTEM;
362 if (rotation == IMAGE_UTIL_ROTATION_90 || rotation == IMAGE_UTIL_ROTATION_270) {
367 buffer = buffer_temp;
370 if (info->max_size < width || info->max_size < height) { /* need resize */
374 media_packet_h packet;
377 if (width > height) {
378 resized_width = info->max_size;
379 resized_height = height * info->max_size / width;
381 resized_height = info->max_size;
382 resized_width = width * info->max_size / height;
385 if (resized_height % 8)
386 resized_height += (8 - (resized_height % 8));
388 if (resized_width % 8)
389 resized_width += (8 - (resized_width % 8));
391 fmt = ctsvc_image_util_create_media_format(mimetype, width, height);
393 /* LCOV_EXCL_START */
394 ERR("ctsvc_image_util_create_media_format() Fail");
395 info->ret = CONTACTS_ERROR_SYSTEM;
401 packet = ctsvc_image_util_create_media_packet(fmt, buffer, (unsigned int)size);
404 if (NULL == packet) {
405 /* LCOV_EXCL_START */
406 ERR("ctsvc_image_util_create_media_packet() Fail");
407 media_format_unref(fmt);
408 info->ret = CONTACTS_ERROR_SYSTEM;
413 ret = ctsvc_image_util_resize(packet, resized_width, resized_height, &buffer_temp,
416 media_packet_destroy(packet);
417 media_format_unref(fmt);
419 if (CONTACTS_ERROR_NONE != ret) {
423 buffer = buffer_temp;
425 width = resized_width;
426 height = resized_height;
429 ret = image_util_encode_jpeg(buffer, width, height, colorspace,
430 CTSVC_IMAGE_ENCODE_QUALITY, info->dest);
432 if (IMAGE_UTIL_ERROR_NONE != ret) {
433 /* LCOV_EXCL_START */
434 ERR("image_util_encode_jpeg Fail(%d)", ret);
435 info->ret = CONTACTS_ERROR_SYSTEM;
440 dest_fd = open(info->dest, O_RDONLY);
442 /* LCOV_EXCL_START */
443 ERR("System : Open Fail(%d)", errno);
444 info->ret = CONTACTS_ERROR_SYSTEM;
449 ret = fchmod(dest_fd, CTS_SECURITY_IMAGE_PERMISSION);
451 /* LCOV_EXCL_START */
452 ERR("fchmod Fail(%d)", errno);
453 info->ret = CONTACTS_ERROR_SYSTEM;
460 info->ret = CONTACTS_ERROR_NONE;
464 static int _ctsvc_image_encode(const char *src, const char *dest, int max_size)
467 image_info info = {src, dest, max_size, CONTACTS_ERROR_SYSTEM};
469 ret = image_util_foreach_supported_jpeg_colorspace(
470 _ctsvc_image_util_supported_jpeg_colorspace_cb, &info);
472 if (IMAGE_UTIL_ERROR_NONE != ret)
473 return CONTACTS_ERROR_SYSTEM;
478 #define CTSVC_COPY_SIZE_MAX 4096
479 int ctsvc_utils_copy_image(const char *dir, const char *src, const char *file)
484 char buf[CTSVC_COPY_SIZE_MAX] = {0};
486 if (NULL == file || *file == '\0')
487 return CONTACTS_ERROR_INVALID_PARAMETER;
489 char dest[strlen(dir) + strlen(file) + 2];
490 snprintf(dest, sizeof(dest), "%s/%s", dir, file);
492 if (false == _ctsvc_check_available_image_space(1204 * 1204)) /*need larger than 1M*/
493 return CONTACTS_ERROR_FILE_NO_SPACE;
495 ret = _ctsvc_image_encode(src, dest, CTSVC_IMAGE_MAX_SIZE);
496 if (CONTACTS_ERROR_NONE == ret)
499 /* LCOV_EXCL_START */
500 ERR("_ctsvc_image_encode Fail(%d)", ret);
503 src_fd = open(src, O_RDONLY);
505 /* LCOV_EXCL_START */
506 ERR("System : Open(%s) Fail(%d)", src, errno);
507 return CONTACTS_ERROR_SYSTEM;
511 dest_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, 0660);
513 /* LCOV_EXCL_START */
514 ERR("Open Fail(%d)", errno);
516 return CONTACTS_ERROR_SYSTEM;
520 while (0 < (size = read(src_fd, buf, CTSVC_COPY_SIZE_MAX))) {
521 ret = write(dest_fd, buf, size);
523 if (EINTR == errno) {
526 /* LCOV_EXCL_START */
527 ERR("write() Fail(%d)", errno);
529 ret = CONTACTS_ERROR_FILE_NO_SPACE; /* No space */
531 ret = CONTACTS_ERROR_SYSTEM; /* IO error */
541 ret = fchmod(dest_fd, CTS_SECURITY_IMAGE_PERMISSION);
543 /* LCOV_EXCL_START */
544 ERR("fchmod() Fail(%d)", ret);
550 return CONTACTS_ERROR_NONE;
553 char* ctsvc_utils_get_thumbnail_path(const char *image_path)
557 char *thumbnail_path = NULL;
560 RETV_IF(NULL == image_path, NULL);
561 RETV_IF(NULL != strstr(image_path, CTSVC_IMAGE_THUMBNAIL_SUFFIX), NULL);
563 full_len = strlen(image_path) + strlen(CTSVC_IMAGE_THUMBNAIL_SUFFIX) + 1;
564 thumbnail_path = calloc(1, full_len);
565 if (NULL == thumbnail_path) {
566 /* LCOV_EXCL_START */
567 ERR("calloc() Fail");
572 ext = strrchr(image_path, '.');
574 name_len = ext -image_path;
575 strncpy(thumbnail_path, image_path, name_len);
576 snprintf(thumbnail_path+name_len, full_len-name_len, "%s%s", CTSVC_IMAGE_THUMBNAIL_SUFFIX, ext);
578 snprintf(thumbnail_path, full_len, "%s%s", image_path, CTSVC_IMAGE_THUMBNAIL_SUFFIX);
581 return thumbnail_path;
584 char* ctsvc_utils_get_image_path(const char *thumbnail_path)
588 char *image_path = NULL;
591 RETV_IF(NULL == thumbnail_path, NULL);
592 RETV_IF(NULL == strstr(thumbnail_path, CTSVC_IMAGE_THUMBNAIL_SUFFIX), NULL);
594 full_len = strlen(thumbnail_path) - strlen(CTSVC_IMAGE_THUMBNAIL_SUFFIX) + 1;
595 image_path = calloc(1, full_len);
596 if (NULL == image_path) {
597 /* LCOV_EXCL_START */
598 ERR("calloc() Fail");
603 ext = strrchr(thumbnail_path, '.');
605 name_len = ext -thumbnail_path - strlen(CTSVC_IMAGE_THUMBNAIL_SUFFIX);
606 strncpy(image_path, thumbnail_path, name_len);
607 snprintf(image_path + name_len, full_len -name_len, "%s", ext);
609 name_len = strlen(thumbnail_path) - strlen(CTSVC_IMAGE_THUMBNAIL_SUFFIX);
610 strncpy(image_path, thumbnail_path, name_len);
615 char* ctsvc_utils_make_thumbnail(const char *image_path)
618 char src[CTSVC_IMG_FULL_PATH_SIZE_MAX] = {0};
619 char dest[CTSVC_IMG_FULL_PATH_SIZE_MAX] = {0};
620 char *thumbnail_path = NULL;
622 RETV_IF(NULL == image_path, NULL);
623 RETV_IF(NULL != strstr(image_path, CTSVC_IMAGE_THUMBNAIL_SUFFIX), NULL);
625 if (false == _ctsvc_check_available_image_space(
626 CTSVC_IMAGE_THUMBNAIL_SIZE * CTSVC_IMAGE_THUMBNAIL_SIZE)) {
627 /* LCOV_EXCL_START */
628 ERR("No space to make thumbnail");
633 thumbnail_path = ctsvc_utils_get_thumbnail_path(image_path);
634 if (NULL == thumbnail_path) {
635 /* LCOV_EXCL_START */
636 ERR("ctsvc_image_util_get_thumbnail_path() Fail");
641 snprintf(src, sizeof(src), "%s/%s", CTSVC_CONTACT_IMG_FULL_LOCATION, image_path);
642 snprintf(dest, sizeof(dest), "%s/%s", CTSVC_CONTACT_IMG_FULL_LOCATION, thumbnail_path);
644 if (0 == access(dest, F_OK)) {
645 DBG("already exist");
646 return thumbnail_path;
649 ret = _ctsvc_image_encode(src, dest, CTSVC_IMAGE_THUMBNAIL_SIZE);
650 if (CONTACTS_ERROR_NONE != ret) {
651 /* LCOV_EXCL_START */
652 ERR("_ctsvc_image_encode() Fail(%d)", ret);
653 free(thumbnail_path);
658 return strdup(thumbnail_path);
661 int ctsvc_get_next_ver(void)
667 if (0 < transaction_count) {
669 return transaction_ver + 1;
672 query = "SELECT ver FROM "CTS_TABLE_VERSION;
673 ret = ctsvc_query_get_first_int_result(query, &version);
675 /* In this case, contacts-service already works abnormally. */
676 if (CONTACTS_ERROR_NONE != ret)
677 /* LCOV_EXCL_START */
678 ERR("ctsvc_query_get_first_int_result : get version error(%d)", ret);
681 return (1 + version);
684 int ctsvc_get_current_version(int *out_current_version)
686 if (transaction_count <= 0) {
689 const char *query = "SELECT ver FROM "CTS_TABLE_VERSION;
691 ret = ctsvc_query_get_first_int_result(query, &version);
692 if (CONTACTS_ERROR_NONE != ret) {
693 /* LCOV_EXCL_START */
694 ERR("ctsvc_query_get_first_int_result() Fail(%d)", ret);
699 *out_current_version = version;
701 *out_current_version = transaction_ver;
703 return CONTACTS_ERROR_NONE;
706 int ctsvc_get_transaction_ver(void)
708 return transaction_ver;
711 int SAFE_SNPRINTF(char **buf, int *buf_size, int len, const char *src)
719 remain = *buf_size - len;
720 if (strlen(src) + 1 < remain) {
721 temp_len = snprintf((*buf)+len, remain, "%s", src);
726 temp = realloc(*buf, *buf_size*2);
730 *buf_size = *buf_size * 2;
731 remain = *buf_size - len;
732 if (strlen(src) + 1 < remain)
735 temp_len = snprintf((*buf)+len, remain, "%s", src);