cfd27b0b1495a300bdff4584adce7a8da8475250
[platform/core/pim/contacts-service.git] / native / ctsvc_utils.c
1 /*
2  * Contacts Service
3  *
4  * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
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
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  *
18  */
19 #include <ctype.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <errno.h>
23 #include <dirent.h>
24 #include <sys/stat.h>
25 #include <sys/vfs.h>
26 #include <image_util.h>
27 #include <vconf.h>
28 #include <vconf-keys.h>
29 #include <unicode/ulocdata.h>
30 #include <unicode/uset.h>
31 #include <unicode/ustring.h>
32 #include <libexif/exif-data.h>
33
34 #include "contacts.h"
35 #include "ctsvc_internal.h"
36 #include "ctsvc_utils.h"
37 #include "ctsvc_mutex.h"
38 #include "ctsvc_sqlite.h"
39 #include "ctsvc_schema.h"
40 #include "ctsvc_notification.h"
41 #include "ctsvc_struct.h"
42 #include "ctsvc_normalize.h"
43 #include "ctsvc_localize.h"
44 #include "ctsvc_localize_utils.h"
45 #include "ctsvc_setting.h"
46 #include "ctsvc_notify.h"
47
48 #ifdef _CONTACTS_IPC_SERVER
49 #include "ctsvc_server_change_subject.h"
50 #endif
51
52 static __thread int transaction_count = 0;
53 static __thread int transaction_ver = 0;
54 static __thread bool version_up = false;
55
56 #define CTS_SECURITY_IMAGE_PERMISSION 0440
57 #define CTS_IMAGE_ENCODE_QUALITY        50
58
59 #define CTS_COMMIT_TRY_MAX 500000 // For 3second
60
61 int ctsvc_begin_trans(void)
62 {
63         int ret = -1, progress;
64
65 #ifndef _CONTACTS_IPC_SERVER
66         ctsvc_mutex_lock(CTS_MUTEX_TRANSACTION);
67 #endif
68         if (transaction_count <= 0) {
69                 ret = ctsvc_query_exec("BEGIN IMMEDIATE TRANSACTION");
70                 progress = 100000;
71                 while (CONTACTS_ERROR_DB == ret && progress < CTS_COMMIT_TRY_MAX) {
72                         usleep(progress);
73                         ret = ctsvc_query_exec("BEGIN IMMEDIATE TRANSACTION");
74                         progress *= 2;
75                 }
76                 if(CONTACTS_ERROR_NONE != ret) {
77                         CTS_ERR("ctsvc_query_exec() Failed(%d)", ret);
78 #ifndef _CONTACTS_IPC_SERVER
79                         ctsvc_mutex_unlock(CTS_MUTEX_TRANSACTION);
80 #endif
81                         return ret;
82                 }
83
84                 transaction_count = 0;
85
86                 const char *query = "SELECT ver FROM "CTS_TABLE_VERSION;
87                 ret = ctsvc_query_get_first_int_result(query, &transaction_ver);
88                 version_up = false;
89         }
90         transaction_count++;
91         INFO("transaction_count : %d.", transaction_count);
92 #ifndef _CONTACTS_IPC_SERVER
93         ctsvc_mutex_unlock(CTS_MUTEX_TRANSACTION);
94 #endif
95         return CONTACTS_ERROR_NONE;
96 }
97
98 int ctsvc_end_trans(bool is_success)
99 {
100         int ret = -1, progress;
101         char query[CTS_SQL_MIN_LEN] = {0};
102
103 #ifndef _CONTACTS_IPC_SERVER
104         ctsvc_mutex_lock(CTS_MUTEX_TRANSACTION);
105 #endif
106
107         transaction_count--;
108         INFO("%s, transaction_count : %d", is_success?"True": "False",  transaction_count);
109
110         if (0 != transaction_count) {
111                 CTS_DBG("contact transaction_count : %d.", transaction_count);
112 #ifndef _CONTACTS_IPC_SERVER
113                 ctsvc_mutex_unlock(CTS_MUTEX_TRANSACTION);
114 #endif
115                 return CONTACTS_ERROR_NONE;
116         }
117
118         if (false == is_success) {
119                 ctsvc_nofitication_cancel();
120 #ifdef _CONTACTS_IPC_SERVER
121                 ctsvc_change_subject_clear_changed_info();
122 #endif
123                 ret = ctsvc_query_exec("ROLLBACK TRANSACTION");
124
125 #ifndef _CONTACTS_IPC_SERVER
126                 ctsvc_mutex_unlock(CTS_MUTEX_TRANSACTION);
127 #endif
128                 return CONTACTS_ERROR_NONE;
129         }
130
131         if (version_up) {
132                 transaction_ver++;
133                 snprintf(query, sizeof(query), "UPDATE %s SET ver = %d",
134                                 CTS_TABLE_VERSION, transaction_ver);
135                 ret = ctsvc_query_exec(query);
136                 WARN_IF(CONTACTS_ERROR_NONE != ret, "ctsvc_query_exec(version up) Failed(%d)", ret);
137         }
138
139         INFO("start commit");
140         progress = 100000;
141         ret = ctsvc_query_exec("COMMIT TRANSACTION");
142         while (CONTACTS_ERROR_DB == ret && progress<CTS_COMMIT_TRY_MAX) {
143                 usleep(progress);
144                 ret = ctsvc_query_exec("COMMIT TRANSACTION");
145                 progress *= 2;
146         }
147         INFO("%s", (CONTACTS_ERROR_NONE == ret)?"commit": "rollback");
148
149         if (CONTACTS_ERROR_NONE != ret) {
150                 int tmp_ret;
151                 CTS_ERR("ctsvc_query_exec() Failed(%d)", ret);
152                 ctsvc_nofitication_cancel();
153 #ifdef _CONTACTS_IPC_SERVER
154                 ctsvc_change_subject_clear_changed_info();
155 #endif
156                 tmp_ret = ctsvc_query_exec("ROLLBACK TRANSACTION");
157                 WARN_IF(CONTACTS_ERROR_NONE != tmp_ret, "ctsvc_query_exec(ROLLBACK) Failed(%d)", tmp_ret);
158 #ifndef _CONTACTS_IPC_SERVER
159                 ctsvc_mutex_unlock(CTS_MUTEX_TRANSACTION);
160 #endif
161                 return ret;
162         }
163
164         ctsvc_notification_send();
165 #ifdef _CONTACTS_IPC_SERVER
166         ctsvc_change_subject_publish_changed_info();
167 #endif
168
169 #ifndef _CONTACTS_IPC_SERVER
170         ctsvc_mutex_unlock(CTS_MUTEX_TRANSACTION);
171 #endif
172
173         CTS_DBG("Transaction shut down! : (%d)\n", transaction_ver);
174
175         return CONTACTS_ERROR_NONE;
176 }
177
178 const char* ctsvc_get_display_column(void)
179 {
180         contacts_name_display_order_e order;
181
182         contacts_setting_get_name_display_order(&order);
183         if (CONTACTS_NAME_DISPLAY_ORDER_FIRSTLAST == order)
184                 return "display_name";
185         else
186                 return "reverse_display_name";
187 }
188
189 const char* ctsvc_get_sort_name_column(void)
190 {
191         contacts_name_sorting_order_e order;
192
193         contacts_setting_get_name_sorting_order(&order);
194         if (CONTACTS_NAME_SORTING_ORDER_FIRSTLAST == order)
195                 return "sort_name, display_name_language";
196         else
197                 return "reverse_sort_name, reverse_display_name_language";
198 }
199
200 const char* ctsvc_get_sort_column(void)
201 {
202         contacts_name_sorting_order_e order;
203
204         contacts_setting_get_name_sorting_order(&order);
205         if (CONTACTS_NAME_SORTING_ORDER_FIRSTLAST == order)
206                 return "display_name_language, sortkey";
207         else
208                 return "reverse_display_name_language, reverse_sortkey";
209 }
210
211 void ctsvc_utils_make_image_file_name(int parent_id, int id, char *src_img, char *dest, int dest_size)
212 {
213         char *ext;
214         char *temp;
215         char *lower_ext;
216
217         ext = strrchr(src_img, '.');
218         if (NULL == ext || strchr(ext, '/'))
219                 ext = "";
220
221         lower_ext = strdup(ext);
222         temp = lower_ext;
223         while (*temp) {
224                 *temp = tolower(*temp);
225                 temp++;
226         }
227
228         if (parent_id > 0)
229                 snprintf(dest, dest_size, "%d_%d%s", parent_id, id, lower_ext);
230         else
231                 snprintf(dest, dest_size, "%d%s", id, ext);
232         free(lower_ext);
233 }
234
235 static inline bool ctsvc_check_available_image_space(void){
236         int ret;
237         struct statfs buf;
238         long long size;
239         ret = statfs(CTSVC_NOTI_IMG_REPERTORY, &buf);
240
241         RETVM_IF(ret!=0, false, "statfs Failed(%d)", ret);
242
243         size = (long long)buf.f_bavail * (buf.f_bsize);
244
245         if (size > 1024*1024) // if available space to copy a image is larger than 1M
246                 return true;
247         return false;
248 }
249
250 static image_util_rotation_e __ctsvc_get_rotation_info(const char *path)
251 {
252         ExifData *ed = NULL;
253         ExifEntry *entry;
254         image_util_rotation_e rotation = IMAGE_UTIL_ROTATION_NONE;
255         int orientation = 0;
256
257         ed = exif_data_new_from_file(path);
258         if (ed == NULL) {
259                 CTS_ERR("exif_data_new_from_file : ExifData is NULL");
260                 return IMAGE_UTIL_ROTATION_NONE;
261         }
262
263         entry = exif_data_get_entry(ed, EXIF_TAG_ORIENTATION);
264         if (entry) {
265                 ExifByteOrder mByteOrder = exif_data_get_byte_order(ed);
266                 orientation = (int)exif_get_short(entry->data, mByteOrder);
267                 if (orientation < 0 || orientation > 8)
268                         orientation = 0;
269         }
270
271         if (ed)
272                 exif_data_unref(ed);
273
274         switch(orientation) {
275         case 1: // Top-left
276                 rotation = IMAGE_UTIL_ROTATION_NONE;
277                 break;
278         case 2: // Top-right
279                 rotation = IMAGE_UTIL_ROTATION_FLIP_HORZ;
280                 break;
281         case 3: // Bottom-right
282                 rotation = IMAGE_UTIL_ROTATION_180;
283                 break;
284         case 4: // Bottom-left
285                 rotation = IMAGE_UTIL_ROTATION_FLIP_VERT;
286                 break;
287         case 6:         // Right-top
288                 rotation = IMAGE_UTIL_ROTATION_90;
289                 break;
290         case 8: // Left-bottom
291                 rotation = IMAGE_UTIL_ROTATION_270;
292                 break;
293         case 5: // Left-top
294         case 7: // Right-bottom
295         case 0:
296         default:
297                 break;
298         };
299
300         return rotation;
301 }
302
303 static int image_size = 480;
304
305 typedef struct {
306         const char *src;
307         const char *dest;
308         int ret;
309 }image_info;
310
311 static bool __ctsvc_image_util_supported_jpeg_colorspace_cb(image_util_colorspace_e colorspace, void *user_data)
312 {
313         image_info *info = (image_info*)user_data;
314         image_util_error_e ret;
315         int width = 0, height = 0;
316         unsigned int size_decode = 0;
317         int resized_width, resized_height;
318         unsigned char * img_target = 0;
319         unsigned char * img_source = 0;
320         int dest_fd;
321         image_util_rotation_e rotation;
322
323         // temporary code
324         if (colorspace == IMAGE_UTIL_COLORSPACE_YV12 || colorspace == IMAGE_UTIL_COLORSPACE_I420) {
325                 info->ret = CONTACTS_ERROR_SYSTEM;
326                 return true;
327         }
328
329         rotation = __ctsvc_get_rotation_info(info->src);
330
331         // load jpeg sample file
332         CTS_DBG("colorspace %d src : %s, dest : %s", colorspace, info->src, info->dest);
333         ret = image_util_decode_jpeg( info->src, colorspace, &img_source, &width, &height, &size_decode );
334         if (ret!=IMAGE_UTIL_ERROR_NONE) {
335                 info->ret = CONTACTS_ERROR_SYSTEM;
336                 return true;
337         }
338
339 #if 0
340         if (0>image_size) {
341                 int w,h;
342                 ecore_x_window_size_get(
343                                 ecore_x_window_root_get(ecore_x_window_focus_get())
344                                 , &w, &h);
345
346                 if (w>h)
347                         image_size = h;
348                 else
349                         image_size = w;
350
351         }
352 #endif
353
354         if (width > image_size || height > image_size) {
355                 // image resize
356                 if (image_size<=0 || width <=0 || height <= 0) {
357                         free(img_source);
358                         CTS_ERR("image size error(%d)", image_size);
359                         info->ret = CONTACTS_ERROR_SYSTEM;
360                         return false;
361                 }
362
363                 if (width>height) {
364                         resized_width = image_size;
365                         resized_height = height*image_size/width;
366                 }
367                 else {
368                         resized_height = image_size;
369                         resized_width = width*image_size/height;
370                 }
371
372                 if (resized_height%8)
373                         resized_height += 8 - (resized_height%8);
374                 if (resized_width%8)
375                         resized_width += 8 - (resized_width%8);
376
377                 CTS_DBG("size(%d, %d) -> resize(%d,%d)", width, height, resized_width, resized_height);
378
379                 image_util_calculate_buffer_size(resized_width, resized_height, colorspace , &size_decode);
380
381                 img_target = malloc( size_decode );
382
383                 // do resize
384                 ret = image_util_resize( img_target, &resized_width, &resized_height,
385                                 img_source, width, height, colorspace );
386                 if (ret!=IMAGE_UTIL_ERROR_NONE) {
387                         CTS_ERR("image_util_resize failed(%d)", ret);
388                         free( img_target );
389                         free( img_source );
390                         info->ret = CONTACTS_ERROR_SYSTEM;
391                         return false;
392                 }
393                 free( img_source );
394         }
395         else {
396                 resized_width = width;
397                 resized_height = height;
398                 img_target = img_source;
399         }
400
401         // image rotation
402         if (IMAGE_UTIL_ROTATION_NONE != rotation) {
403                 int rotated_width, rotated_height;
404                 unsigned char *img_rotate = 0;
405                 img_rotate = malloc( size_decode );
406                 ret= image_util_rotate(img_rotate, &rotated_width, &rotated_height,
407                                         rotation, img_target, resized_width, resized_height, colorspace);
408                 free(img_target);
409                 if (IMAGE_UTIL_ERROR_NONE != ret) {
410                         CTS_ERR("image_util_rotate failed(%d)", ret);
411                         info->ret = CONTACTS_ERROR_SYSTEM;
412                         free(img_rotate);
413                         return false;
414                 }
415                 resized_width = rotated_width;
416                 resized_height = rotated_height;
417                 img_target = img_rotate;
418         }
419
420         // image encode
421         ret = image_util_encode_jpeg(img_target, resized_width, resized_height, colorspace, CTS_IMAGE_ENCODE_QUALITY, info->dest );
422         free( img_target );
423         if(ret != IMAGE_UTIL_ERROR_NONE) {
424                 CTS_ERR("image_util_encode_jpeg failed(%d)", ret);
425                 info->ret = CONTACTS_ERROR_SYSTEM;
426                 return false;
427         }
428
429         dest_fd = open(info->dest, O_RDONLY);
430         if (dest_fd < 0) {
431                 CTS_ERR("System : Open Failed(%d)", errno);
432                 info->ret = CONTACTS_ERROR_SYSTEM;
433                 return false;
434         }
435
436         ret = fchown(dest_fd, getuid(), CTS_SECURITY_FILE_GROUP);
437         if (0 != ret) {
438                 CTS_ERR("fchown Failed(%d)", errno);
439                 info->ret = CONTACTS_ERROR_SYSTEM;
440                 close(dest_fd);
441                 return false;
442         }
443
444         ret = fchmod(dest_fd, CTS_SECURITY_IMAGE_PERMISSION);
445         if (0 != ret) {
446                 CTS_ERR("fchmod Failed(%d)", errno);
447                 info->ret = CONTACTS_ERROR_SYSTEM;
448                 close(dest_fd);
449                 return false;
450         }
451         close(dest_fd);
452
453         info->ret = CONTACTS_ERROR_NONE;
454         return false;
455 }
456
457 static int __ctsvc_resize_and_copy_image(const char *src, const char *dest)
458 {
459         int ret;
460         image_info info = {.src = src, .dest = dest, ret = CONTACTS_ERROR_SYSTEM};
461
462         ret = image_util_foreach_supported_jpeg_colorspace(__ctsvc_image_util_supported_jpeg_colorspace_cb, &info);
463
464         if (ret != IMAGE_UTIL_ERROR_NONE)
465                 return CONTACTS_ERROR_SYSTEM;
466
467         return info.ret;
468 }
469
470 #define CTSVC_COPY_SIZE_MAX 4096
471 int ctsvc_utils_copy_image(const char *dir, const char *src, const char *file)
472 {
473         int ret;
474         int size;
475         int src_fd, dest_fd;
476         char buf[CTSVC_COPY_SIZE_MAX] = {0};
477
478         if (NULL == file || *file == '\0')
479                 return CONTACTS_ERROR_INVALID_PARAMETER;
480
481         char dest[strlen(dir) + strlen(file) + 2];
482         snprintf(dest, sizeof(dest), "%s/%s", dir, file);
483
484         if (!ctsvc_check_available_image_space())
485                 return CONTACTS_ERROR_FILE_NO_SPACE;
486
487         ret = __ctsvc_resize_and_copy_image(src, dest);
488         if (CONTACTS_ERROR_NONE == ret) {
489                 return ret;
490         }
491         else
492                 CTS_ERR("__ctsvc_resize_and_copy_image Failed(%d)", ret);
493
494         src_fd = open(src, O_RDONLY);
495         RETVM_IF(src_fd < 0, CONTACTS_ERROR_SYSTEM, "System : Open(src:%s) Failed(%d)", src, errno);
496         dest_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, 0660);
497         if (dest_fd < 0) {
498                 CTS_ERR("Open Failed(%d)", errno);
499                 close(src_fd);
500                 return CONTACTS_ERROR_SYSTEM;
501         }
502
503         while ((size = read(src_fd, buf, CTSVC_COPY_SIZE_MAX)) > 0) {
504                 ret = write(dest_fd, buf, size);
505                 if (ret <= 0) {
506                         if (EINTR == errno)
507                                 continue;
508                         else {
509                                 CTS_ERR("write() Failed(%d)", errno);
510                                 if (ENOSPC == errno)
511                                         ret = CONTACTS_ERROR_FILE_NO_SPACE;     // No space
512                                 else
513                                         ret = CONTACTS_ERROR_SYSTEM;                    // IO error
514                                 close(src_fd);
515                                 close(dest_fd);
516                                 unlink(dest);
517                                 return ret;
518                         }
519                 }
520         }
521
522         ret = fchown(dest_fd, getuid(), CTS_SECURITY_FILE_GROUP);
523         if (0 != ret) {
524                 CTS_ERR("fchown() Failed(%d)", ret);
525         }
526         ret = fchmod(dest_fd, CTS_SECURITY_IMAGE_PERMISSION);
527         if (0 != ret) {
528                 CTS_ERR("fchmod() Failed(%d)", ret);
529         }
530         close(src_fd);
531         close(dest_fd);
532
533         return CONTACTS_ERROR_NONE;
534 }
535
536 int ctsvc_get_next_ver(void)
537 {
538         const char *query;
539         int version;
540         int ret;
541
542         if (0 < transaction_count) {
543                 version_up = true;
544                 return transaction_ver + 1;
545         }
546
547         query = "SELECT ver FROM "CTS_TABLE_VERSION;
548         ret = ctsvc_query_get_first_int_result(query, &version);
549
550         // In this case, contacts-service already works abnormally.
551         if (CONTACTS_ERROR_NONE != ret)
552                 CTS_ERR("ctsvc_query_get_first_int_result : get version error(%d)", ret);
553
554         return (1 + version);
555 }
556
557 int ctsvc_get_current_version( int* out_current_version ){
558         if (transaction_count <= 0) {
559                 int ret;
560                 int version = 0;
561                 const char *query = "SELECT ver FROM "CTS_TABLE_VERSION;
562                 ret = ctsvc_query_get_first_int_result(query, &version);
563                 RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "ctsvc_query_get_first_int_result() Failed(%d)", ret);
564                 *out_current_version = version;
565         }
566         else
567                 *out_current_version = transaction_ver;
568         return CONTACTS_ERROR_NONE;
569 }
570
571 int ctsvc_get_transaction_ver(void)
572 {
573         return transaction_ver;
574 }
575
576 int SAFE_SNPRINTF(char **buf, int *buf_size, int len, const char *src)
577 {
578         int remain;
579         int temp_len;
580
581         if (len < 0)
582                 return -1;
583
584         remain = *buf_size - len;
585         if (remain > strlen(src) + 1) {
586                 temp_len = snprintf((*buf)+len, remain, "%s", src);
587                 return temp_len;
588         }
589         else {
590                 char *temp;
591                 while(1) {
592                         temp = realloc(*buf, *buf_size*2);
593                         if (NULL == temp)
594                                 return -1;
595                         *buf = temp;
596                         *buf_size = *buf_size * 2;
597                         remain = *buf_size - len;
598                         if (remain > strlen(src) + 1)
599                                 break;
600                 }
601                 temp_len = snprintf((*buf)+len, remain, "%s", src);
602                 return temp_len;
603         }
604 }
605