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