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) {
71 ERR("ctsvc_query_exec() Fail(%d)", ret);
75 transaction_count = 0;
77 const char *query = "SELECT ver FROM "CTS_TABLE_VERSION;
78 ret = ctsvc_query_get_first_int_result(query, &transaction_ver);
82 INFO("transaction_count : %d.", transaction_count);
83 return CONTACTS_ERROR_NONE;
86 int ctsvc_end_trans(bool is_success)
88 int ret = -1, progress;
89 char query[CTS_SQL_MIN_LEN] = {0};
92 INFO("%s, transaction_count : %d", is_success ? "True" : "False", transaction_count);
94 if (0 != transaction_count) {
95 DBG("contact transaction_count : %d.", transaction_count);
96 return CONTACTS_ERROR_NONE;
99 if (false == is_success) {
100 ctsvc_nofitication_cancel();
101 ctsvc_change_subject_clear_changed_info();
102 ret = ctsvc_query_exec("ROLLBACK TRANSACTION");
104 return CONTACTS_ERROR_NONE;
109 snprintf(query, sizeof(query), "UPDATE %s SET ver = %d",
110 CTS_TABLE_VERSION, transaction_ver);
111 ret = ctsvc_query_exec(query);
112 if (CONTACTS_ERROR_NONE != ret)
113 ERR("ctsvc_query_exec(version up) Fail(%d)", ret);
116 INFO("start commit");
118 ret = ctsvc_query_exec("COMMIT TRANSACTION");
119 while (CONTACTS_ERROR_DB == ret && progress < CTS_COMMIT_TRY_MAX) {
121 ret = ctsvc_query_exec("COMMIT TRANSACTION");
124 INFO("%s", (CONTACTS_ERROR_NONE == ret) ? "commit" : "rollback");
126 if (CONTACTS_ERROR_NONE != ret) {
128 ERR("ctsvc_query_exec() Fail(%d)", ret);
129 ctsvc_nofitication_cancel();
130 ctsvc_change_subject_clear_changed_info();
132 tmp_ret = ctsvc_query_exec("ROLLBACK TRANSACTION");
133 if (CONTACTS_ERROR_NONE != tmp_ret)
134 ERR("ctsvc_query_exec(ROLLBACK) Fail(%d)", tmp_ret);
139 ctsvc_notification_send();
140 ctsvc_change_subject_publish_changed_info();
142 DBG("Transaction shut down! : (%d)\n", transaction_ver);
144 return CONTACTS_ERROR_NONE;
147 const char* ctsvc_get_display_column(void)
149 contacts_name_display_order_e order;
151 ctsvc_setting_get_name_display_order(&order);
152 if (CONTACTS_NAME_DISPLAY_ORDER_FIRSTLAST == order)
153 return "display_name";
155 return "reverse_display_name";
158 const char* ctsvc_get_sort_name_column(void)
160 contacts_name_sorting_order_e order;
162 ctsvc_setting_get_name_sorting_order(&order);
163 if (CONTACTS_NAME_SORTING_ORDER_FIRSTLAST == order)
164 return "sort_name, display_name_language";
166 return "reverse_sort_name, reverse_display_name_language";
169 const char* ctsvc_get_sort_column(void)
171 contacts_name_sorting_order_e order;
173 ctsvc_setting_get_name_sorting_order(&order);
174 if (CONTACTS_NAME_SORTING_ORDER_FIRSTLAST == order)
175 return "display_name_language, sortkey";
177 return "reverse_display_name_language, reverse_sortkey";
180 void ctsvc_utils_make_image_file_name(int parent_id, int id, char *src_img, char *dest,
187 ext = strrchr(src_img, '.');
188 if (NULL == ext || strchr(ext, '/'))
191 lower_ext = strdup(ext);
192 if (NULL == lower_ext) {
193 ERR("strdup() Fail");
198 *temp = tolower(*temp);
203 snprintf(dest, dest_size, "%d_%d%s", parent_id, id, lower_ext);
205 snprintf(dest, dest_size, "%d%s", id, ext);
209 static inline bool _ctsvc_check_available_image_space(int need_size)
215 ret = statfs(CTSVC_NOTI_IMG_REPERTORY, &buf);
216 RETVM_IF(ret != 0, false, "statfs() Fail(%d)", ret);
218 size = (long long)buf.f_bavail * (buf.f_bsize);
220 if (need_size < size) /* if available space to copy a image is larger than need_size */
225 static image_util_rotation_e _ctsvc_image_get_rotation_info(const char *path)
229 image_util_rotation_e rotation = IMAGE_UTIL_ROTATION_NONE;
232 ed = exif_data_new_from_file(path);
234 ERR("exif_data_new_from_file() Fail");
235 return IMAGE_UTIL_ROTATION_NONE;
238 entry = exif_data_get_entry(ed, EXIF_TAG_ORIENTATION);
240 ExifByteOrder mByteOrder = exif_data_get_byte_order(ed);
241 orientation = (int)exif_get_short(entry->data, mByteOrder);
242 if (orientation < 0 || 8 < orientation)
249 switch (orientation) {
250 case 1: /* Top-left */
251 rotation = IMAGE_UTIL_ROTATION_NONE;
253 case 2: /* Top-right */
254 rotation = IMAGE_UTIL_ROTATION_FLIP_HORZ;
256 case 3: /* Bottom-right */
257 rotation = IMAGE_UTIL_ROTATION_180;
259 case 4: /* Bottom-left */
260 rotation = IMAGE_UTIL_ROTATION_FLIP_VERT;
262 case 6: /* Right-top */
263 rotation = IMAGE_UTIL_ROTATION_90;
265 case 8: /* Left-bottom */
266 rotation = IMAGE_UTIL_ROTATION_270;
268 case 5: /* Left-top */
269 case 7: /* Right-bottom */
286 static bool _ctsvc_image_util_supported_jpeg_colorspace_cb(
287 image_util_colorspace_e colorspace, void *user_data)
295 void *buffer_temp = NULL;
297 image_util_rotation_e rotation;
298 image_info *info = user_data;
300 ret = ctsvc_image_util_get_mimetype(colorspace, &mimetype);
301 if (CONTACTS_ERROR_NONE != ret) {
302 info->ret = CONTACTS_ERROR_SYSTEM;
306 ret = image_util_decode_jpeg(info->src, colorspace, (unsigned char **)&buffer,
307 &width, &height, (unsigned int *)&size);
308 if (IMAGE_UTIL_ERROR_NONE != ret) {
309 info->ret = CONTACTS_ERROR_SYSTEM;
313 rotation = _ctsvc_image_get_rotation_info(info->src);
314 if (IMAGE_UTIL_ROTATION_NONE != rotation) { /* need rotate */
316 media_packet_h packet;
318 fmt = ctsvc_image_util_create_media_format(mimetype, width, height);
320 ERR("ctsvc_image_util_create_media_format() Fail");
321 info->ret = CONTACTS_ERROR_SYSTEM;
326 packet = ctsvc_image_util_create_media_packet(fmt, buffer, (unsigned int)size);
327 if (NULL == packet) {
328 ERR("ctsvc_image_util_create_media_packet() Fail");
329 media_format_unref(fmt);
330 info->ret = CONTACTS_ERROR_SYSTEM;
335 ret = ctsvc_image_util_rotate(packet, rotation, &buffer_temp, &size);
337 media_packet_destroy(packet);
338 media_format_unref(fmt);
340 if (CONTACTS_ERROR_NONE != ret) {
342 info->ret = CONTACTS_ERROR_SYSTEM;
346 if (rotation == IMAGE_UTIL_ROTATION_90 || rotation == IMAGE_UTIL_ROTATION_270) {
352 buffer = buffer_temp;
355 if (info->max_size < width || info->max_size < height) { /* need resize */
359 media_packet_h packet;
362 if (width > height) {
363 resized_width = info->max_size;
364 resized_height = height * info->max_size / width;
366 resized_height = info->max_size;
367 resized_width = width * info->max_size / height;
370 if (resized_height % 8)
371 resized_height += (8 - (resized_height % 8));
373 if (resized_width % 8)
374 resized_width += (8 - (resized_width % 8));
376 fmt = ctsvc_image_util_create_media_format(mimetype, width, height);
378 ERR("ctsvc_image_util_create_media_format() Fail");
379 info->ret = CONTACTS_ERROR_SYSTEM;
384 packet = ctsvc_image_util_create_media_packet(fmt, buffer, (unsigned int)size);
385 if (NULL == packet) {
386 ERR("ctsvc_image_util_create_media_packet() Fail");
387 media_format_unref(fmt);
388 info->ret = CONTACTS_ERROR_SYSTEM;
393 ret = ctsvc_image_util_resize(packet, resized_width, resized_height, &buffer_temp,
396 media_packet_destroy(packet);
397 media_format_unref(fmt);
399 if (CONTACTS_ERROR_NONE != ret) {
405 buffer = buffer_temp;
407 width = resized_width;
408 height = resized_height;
411 ret = image_util_encode_jpeg(buffer, width, height, colorspace,
412 CTSVC_IMAGE_ENCODE_QUALITY, info->dest);
414 if (IMAGE_UTIL_ERROR_NONE != ret) {
415 ERR("image_util_encode_jpeg Fail(%d)", ret);
416 info->ret = CONTACTS_ERROR_SYSTEM;
420 dest_fd = open(info->dest, O_RDONLY);
422 ERR("System : Open Fail(%d)", errno);
423 info->ret = CONTACTS_ERROR_SYSTEM;
427 ret = fchmod(dest_fd, CTS_SECURITY_IMAGE_PERMISSION);
429 ERR("fchmod Fail(%d)", errno);
430 info->ret = CONTACTS_ERROR_SYSTEM;
436 info->ret = CONTACTS_ERROR_NONE;
440 static int _ctsvc_image_encode(const char *src, const char *dest, int max_size)
443 image_info info = {src, dest, max_size, CONTACTS_ERROR_SYSTEM};
445 ret = image_util_foreach_supported_jpeg_colorspace(
446 _ctsvc_image_util_supported_jpeg_colorspace_cb, &info);
448 if (IMAGE_UTIL_ERROR_NONE != ret)
449 return CONTACTS_ERROR_SYSTEM;
454 #define CTSVC_COPY_SIZE_MAX 4096
455 int ctsvc_utils_copy_image(const char *dir, const char *src, const char *file)
460 char buf[CTSVC_COPY_SIZE_MAX] = {0};
462 if (NULL == file || *file == '\0')
463 return CONTACTS_ERROR_INVALID_PARAMETER;
465 char dest[strlen(dir) + strlen(file) + 2];
466 snprintf(dest, sizeof(dest), "%s/%s", dir, file);
468 if (false == _ctsvc_check_available_image_space(1204 * 1204)) /*need larger than 1M*/
469 return CONTACTS_ERROR_FILE_NO_SPACE;
471 ret = _ctsvc_image_encode(src, dest, CTSVC_IMAGE_MAX_SIZE);
472 if (CONTACTS_ERROR_NONE == ret)
475 ERR("_ctsvc_image_encode Fail(%d)", ret);
477 src_fd = open(src, O_RDONLY);
479 ERR("System : Open(%s) Fail(%d)", src, errno);
480 return CONTACTS_ERROR_SYSTEM;
483 dest_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, 0660);
485 ERR("Open Fail(%d)", errno);
487 return CONTACTS_ERROR_SYSTEM;
490 while (0 < (size = read(src_fd, buf, CTSVC_COPY_SIZE_MAX))) {
491 ret = write(dest_fd, buf, size);
493 if (EINTR == errno) {
496 ERR("write() Fail(%d)", errno);
498 ret = CONTACTS_ERROR_FILE_NO_SPACE; /* No space */
500 ret = CONTACTS_ERROR_SYSTEM; /* IO error */
509 ret = fchmod(dest_fd, CTS_SECURITY_IMAGE_PERMISSION);
511 ERR("fchmod() Fail(%d)", ret);
516 return CONTACTS_ERROR_NONE;
519 char* ctsvc_utils_get_thumbnail_path(const char *image_path)
523 char *thumbnail_path = NULL;
526 RETV_IF(NULL == image_path, NULL);
527 RETV_IF(NULL != strstr(image_path, CTSVC_IMAGE_THUMBNAIL_SUFFIX), NULL);
529 full_len = strlen(image_path) + strlen(CTSVC_IMAGE_THUMBNAIL_SUFFIX) + 1;
530 thumbnail_path = calloc(1, full_len);
531 if (NULL == thumbnail_path) {
532 ERR("calloc() Fail");
536 ext = strrchr(image_path, '.');
538 name_len = ext -image_path;
539 strncpy(thumbnail_path, image_path, name_len);
540 snprintf(thumbnail_path+name_len, full_len-name_len, "%s%s", CTSVC_IMAGE_THUMBNAIL_SUFFIX, ext);
542 snprintf(thumbnail_path, full_len, "%s%s", image_path, CTSVC_IMAGE_THUMBNAIL_SUFFIX);
545 return thumbnail_path;
548 char* ctsvc_utils_get_image_path(const char *thumbnail_path)
552 char *image_path = NULL;
555 RETV_IF(NULL == thumbnail_path, NULL);
556 RETV_IF(NULL == strstr(thumbnail_path, CTSVC_IMAGE_THUMBNAIL_SUFFIX), NULL);
558 full_len = strlen(thumbnail_path) - strlen(CTSVC_IMAGE_THUMBNAIL_SUFFIX) + 1;
559 image_path = calloc(1, full_len);
560 if (NULL == image_path) {
561 ERR("calloc() Fail");
565 ext = strrchr(thumbnail_path, '.');
567 name_len = ext -thumbnail_path - strlen(CTSVC_IMAGE_THUMBNAIL_SUFFIX);
568 strncpy(image_path, thumbnail_path, name_len);
569 snprintf(image_path + name_len, full_len -name_len, "%s", ext);
571 name_len = strlen(thumbnail_path) - strlen(CTSVC_IMAGE_THUMBNAIL_SUFFIX);
572 strncpy(image_path, thumbnail_path, name_len);
577 char* ctsvc_utils_make_thumbnail(const char *image_path)
580 char src[CTSVC_IMG_FULL_PATH_SIZE_MAX] = {0};
581 char dest[CTSVC_IMG_FULL_PATH_SIZE_MAX] = {0};
582 char *thumbnail_path = NULL;
584 RETV_IF(NULL == image_path, NULL);
585 RETV_IF(NULL != strstr(image_path, CTSVC_IMAGE_THUMBNAIL_SUFFIX), NULL);
587 if (false == _ctsvc_check_available_image_space(
588 CTSVC_IMAGE_THUMBNAIL_SIZE * CTSVC_IMAGE_THUMBNAIL_SIZE)) {
589 ERR("No space to make thumbnail");
593 thumbnail_path = ctsvc_utils_get_thumbnail_path(image_path);
594 if (NULL == thumbnail_path) {
595 ERR("ctsvc_image_util_get_thumbnail_path() Fail");
599 if (0 == access(dest, F_OK)) {
600 DBG("already exist");
601 return thumbnail_path;
604 snprintf(src, sizeof(src), "%s/%s", CTSVC_CONTACT_IMG_FULL_LOCATION, image_path);
605 snprintf(dest, sizeof(dest), "%s/%s", CTSVC_CONTACT_IMG_FULL_LOCATION, thumbnail_path);
607 ret = _ctsvc_image_encode(src, dest, CTSVC_IMAGE_THUMBNAIL_SIZE);
608 if (CONTACTS_ERROR_NONE != ret) {
609 ERR("_ctsvc_image_encode() Fail(%d)", ret);
610 free(thumbnail_path);
614 return strdup(thumbnail_path);
617 int ctsvc_get_next_ver(void)
623 if (0 < transaction_count) {
625 return transaction_ver + 1;
628 query = "SELECT ver FROM "CTS_TABLE_VERSION;
629 ret = ctsvc_query_get_first_int_result(query, &version);
631 /* In this case, contacts-service already works abnormally. */
632 if (CONTACTS_ERROR_NONE != ret)
633 ERR("ctsvc_query_get_first_int_result : get version error(%d)", ret);
635 return (1 + version);
638 int ctsvc_get_current_version(int *out_current_version)
640 if (transaction_count <= 0) {
643 const char *query = "SELECT ver FROM "CTS_TABLE_VERSION;
645 ret = ctsvc_query_get_first_int_result(query, &version);
646 if (CONTACTS_ERROR_NONE != ret) {
647 ERR("ctsvc_query_get_first_int_result() Fail(%d)", ret);
651 *out_current_version = version;
653 *out_current_version = transaction_ver;
655 return CONTACTS_ERROR_NONE;
658 int ctsvc_get_transaction_ver(void)
660 return transaction_ver;
663 int SAFE_SNPRINTF(char **buf, int *buf_size, int len, const char *src)
671 remain = *buf_size - len;
672 if (strlen(src) + 1 < remain) {
673 temp_len = snprintf((*buf)+len, remain, "%s", src);
678 temp = realloc(*buf, *buf_size*2);
682 *buf_size = *buf_size * 2;
683 remain = *buf_size - len;
684 if (strlen(src) + 1 < remain)
687 temp_len = snprintf((*buf)+len, remain, "%s", src);