Use the same type to compare values
[platform/framework/web/download-provider.git] / provider / download-provider-plugin-download-agent.c
1 /*
2  * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
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 <stdio.h>
18 #include <stdlib.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
22 #include <time.h>
23 #include <sys/time.h>
24 #include <string.h>
25 #include <dlfcn.h> // dlopen
26 #include <fcntl.h>
27
28 #include <download-provider.h>
29 #include <download-provider-log.h>
30 #include <download-provider-pthread.h>
31 #include <download-provider-ipc.h>
32 #include <download-provider-db-defs.h>
33 #include <download-provider-db.h>
34 #include <download-provider-utils.h>
35 #include <download-provider-notify.h>
36 #include <download-provider-security.h>
37 #include <download-provider-client.h>
38 #include <download-provider-client-manager.h>
39 #include <download-provider-plugin-download-agent.h>
40 #include <download-provider-notification-manager.h>
41 #include <download-provider-queue-manager.h>
42
43 #include <download-agent-defs.h>
44 #include <download-agent-interface.h>
45 #include <tzplatform_config.h>
46
47 #include "xdgmime.h"
48 #include "content/mime_type.h"
49
50 #define DP_SDCARD_MNT_POINT tzplatform_mkpath(TZ_SYS_STORAGE, "sdcard")
51 #define DP_EXTERNAL_STORAGE "/opt/media/"
52 #define DP_MAX_FILE_PATH_LEN 256
53 #define DP_MAX_MIME_TABLE_NUM 15
54
55 typedef struct {
56         const char *mime;
57         int content_type;
58 } mime_table_type;
59
60 static const char *ambiguous_mime_type_list[] = {
61         "text/plain",
62         "application/octet-stream"
63 };
64
65 static mime_table_type mime_table[] = {
66         // PDF
67         {"application/pdf", DP_CONTENT_PDF},
68         // word
69         {"application/msword", DP_CONTENT_WORD},
70         {"application/vnd.openxmlformats-officedocument.wordprocessingml.document", DP_CONTENT_WORD},
71         // ppt
72         {"application/vnd.ms-powerpoint", DP_CONTENT_PPT},
73         {"application/vnd.openxmlformats-officedocument.presentationml.presentation", DP_CONTENT_PPT},
74         // excel
75         {"application/vnd.ms-excel", DP_CONTENT_EXCEL},
76         {"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", DP_CONTENT_EXCEL},
77         // html
78         {"text/html", DP_CONTENT_HTML},
79         // txt
80         {"text/txt", DP_CONTENT_TEXT},
81         {"text/plain", DP_CONTENT_TEXT},
82         // DRM
83         {"application/vnd.oma.drm.content", DP_CONTENT_SD_DRM},
84         {"application/vnd.oma.drm.message", DP_CONTENT_DRM},
85         {"application/x-shockwave-flash", DP_CONTENT_FLASH},
86         {"application/vnd.tizen.package", DP_CONTENT_TPK},
87         {"text/calendar", DP_CONTENT_VCAL},
88 };
89
90 static void *g_da_handle = NULL;
91 static int (*download_agent_init)(void) = NULL; // int da_init(da_client_cb_t *da_client_callback);
92 static int (*download_agent_deinit)(void) = NULL; //  int da_deinit();
93 static int (*download_agent_is_alive)(int) = NULL;  // int da_is_valid_download_id(int download_id);
94 static int (*download_agent_suspend)(int) = NULL; // int da_suspend_download(int download_id);
95 static int (*download_agent_resume)(int) = NULL; // int da_resume_download(int download_id);
96 static int (*download_agent_cancel)(int) = NULL; // int da_cancel_download(int download_id);
97 static int (*download_agent_suspend_without_update)(int) = NULL; // int da_suspend_download_without_update(int download_id);
98 static int (*download_agent_cancel_without_update)(int) = NULL; // int da_cancel_download_without_update(int download_id);
99 static int (*download_agent_start)(const char *url, req_data_t *ext_data, da_cb_t *da_cb_data, int *download_id) = NULL; // int da_start_download_with_extension(const char *url, extension_data_t *ext_data, int *download_id);
100 static dp_content_type __dp_get_content_type(const char *mime, const char *file_path);
101
102 static int __change_error(int err)
103 {
104         int ret = DP_ERROR_NONE;
105         switch (err) {
106         case DA_RESULT_OK:
107                 ret = DP_ERROR_NONE;
108                 break;
109         case DA_ERR_INVALID_ARGUMENT:
110                 ret = DP_ERROR_INVALID_PARAMETER;
111                 break;
112         case DA_ERR_FAIL_TO_MEMALLOC:
113                 ret = DP_ERROR_OUT_OF_MEMORY;
114                 break;
115         case DA_ERR_UNREACHABLE_SERVER:
116                 ret = DP_ERROR_NETWORK_UNREACHABLE;
117                 break;
118         case DA_ERR_HTTP_TIMEOUT:
119                 ret = DP_ERROR_CONNECTION_TIMED_OUT;
120                 break;
121         case DA_ERR_DISK_FULL:
122                 ret = DP_ERROR_NO_SPACE;
123                 break;
124         case DA_ERR_INVALID_STATE:
125                 ret = DP_ERROR_INVALID_STATE;
126                 break;
127         case DA_ERR_NETWORK_FAIL:
128                 ret = DP_ERROR_NETWORK_ERROR;
129                 break;
130         case DA_ERR_CONNECTION_FAIL:
131         case DA_ERR_NETWORK_UNAUTHORIZED:
132                 ret = DP_ERROR_CONNECTION_FAILED;
133                 break;
134         case DA_ERR_INVALID_URL:
135                 ret = DP_ERROR_INVALID_URL;
136                 break;
137         case DA_ERR_INVALID_INSTALL_PATH:
138                 ret = DP_ERROR_INVALID_DESTINATION;
139                 break;
140         case DA_ERR_ALREADY_MAX_DOWNLOAD:
141                 ret = DP_ERROR_TOO_MANY_DOWNLOADS;
142                 break;
143         case DA_ERR_FAIL_TO_CREATE_THREAD:
144         case DA_ERR_FAIL_TO_ACCESS_FILE:
145         default:
146                 ret = DP_ERROR_IO_ERROR;
147                 break;
148         }
149         return ret;
150 }
151
152 static int __dp_da_state_feedback(dp_client_slots_fmt *slot, dp_request_fmt *request)
153 {
154         if (slot == NULL || request == NULL) {
155                 TRACE_ERROR("check address");
156                 return -1; // try cancel
157         }
158
159         TRACE_INFO("[INFO][%d] state:%s error:%s", request->id,
160                         dp_print_state(request->state), dp_print_errorcode(request->error));
161
162         int errorcode = DP_ERROR_NONE;
163         if (dp_db_update_logging(slot->client.dbhandle, request->id,
164                                 request->state, request->error, &errorcode) < 0) {
165                 TRACE_ERROR("logging failure id:%d error:%d", request->id, errorcode);
166                 return -1; // try cancel
167         }
168
169         request->access_time = (int)time(NULL);
170
171         if (request->state_cb == 1) {
172                 if (slot->client.notify < 0 ||
173                                 dp_notify_feedback(slot->client.notify, slot, request->id, request->state, request->error, 0) < 0) {
174                         TRACE_ERROR("id:%d disable state callback by IO_ERROR", request->id);
175                         request->state_cb = 0;
176                 }
177         }
178
179         return 0;
180 }
181
182 static int __precheck_request(dp_client_slots_fmt* slot, dp_request_fmt *request, int agentid)
183 {
184         if (request == NULL) {
185                 TRACE_ERROR("null-check req_id:%d", agentid);
186                 return -1;
187         }
188
189         dp_client_fmt *client = &slot->client;
190
191         for (dp_request_fmt *req = client->requests; req; req = req->next) {
192                 if (req == request) {
193                         if (request->id < 0 || (request->agent_id != agentid)) {
194                                 TRACE_ERROR("id-check request_id:%d agent_id:%d req_id:%d",
195                                                 request->id, request->agent_id, agentid);
196                                 return -1;
197                         }
198                         return 0;
199                 }
200         }
201         return -1;
202 }
203
204 static int __set_file_permission_to_client(dp_client_slots_fmt *slot, dp_request_fmt *request, char *saved_path)
205 {
206         if (slot == NULL || request == NULL || saved_path == NULL) {
207                 TRACE_ERROR("slot:%p request:%p id:%d agentid:%d saved_path:%s",
208                                 slot, request, (request == NULL ? 0 : request->id),
209                                 (request == NULL ? 0 : request->agent_id), saved_path ? saved_path : "");
210                 return DP_ERROR_INVALID_PARAMETER;
211         }
212
213         if (strncmp(saved_path, DP_EXTERNAL_STORAGE, strlen(DP_EXTERNAL_STORAGE)) == 0
214                         || strncmp(DP_SDCARD_MNT_POINT,
215                                 saved_path, strlen(DP_SDCARD_MNT_POINT)) == 0) {
216                 TRACE_INFO("Do not change permission for %s", saved_path);
217                 return DP_ERROR_NONE;
218         }
219
220         struct stat lstat_info;
221         int fd;
222         dp_credential cred = slot->credential;
223
224         if (lstat(saved_path, &lstat_info) == -1) {
225                 TRACE_ERROR("Cannot access to %s", saved_path);
226                 return DP_ERROR_PERMISSION_DENIED;
227         }
228
229         if ((lstat_info.st_mode & S_IFMT) == S_IFLNK) {
230                 TRACE_ERROR("%s is a symbolic link.", saved_path);
231                 return DP_ERROR_PERMISSION_DENIED;
232         }
233
234         fd = open(saved_path, O_RDONLY);
235         if (fd == -1) {
236                 TRACE_SECURE_ERROR("open failed for file : %s", saved_path);
237                 return DP_ERROR_IO_ERROR;
238         }
239
240         // Change the owner to client's uid.
241         if (fchown(fd, cred.uid, lstat_info.st_gid) != 0) {
242                 TRACE_ERROR("[ERROR][%d] permission user:%d group:%d",
243                                 request->id, cred.uid, lstat_info.st_gid);
244                 close(fd);
245                 return DP_ERROR_PERMISSION_DENIED;
246         }
247
248         TRACE_INFO("file owner has been changed to %d:%d", cred.uid, lstat_info.st_gid);
249
250         close(fd);
251         return DP_ERROR_NONE;
252 }
253
254 static void __finished_cb(finished_info_t *info, void *user_req_data,
255                 void *user_client_data)
256 {
257         if (info == NULL) {
258                 TRACE_ERROR("check download info address");
259                 return ;
260         }
261         dp_client_slots_fmt *slot = user_client_data;
262         dp_request_fmt *request = user_req_data;
263         if (slot == NULL || request == NULL) {
264                 TRACE_ERROR("check address slot:%p request:%p id:%d agentid:%d", slot, request, (request == NULL ? 0 : request->id), info->download_id);
265                 free(info->etag);
266                 free(info->saved_path);
267                 free(info);
268                 return ;
269         }
270         CLIENT_MUTEX_LOCK(&slot->mutex);
271         if (__precheck_request(slot, request, info->download_id) < 0) {
272                 TRACE_ERROR("error request agent_id:%d", info->download_id);
273                 if (dp_cancel_agent_download(info->download_id) < 0)
274                         TRACE_ERROR("failed to call cancel_download(%d)", info->download_id);
275                 free(info->etag);
276                 free(info->saved_path);
277                 free(info);
278                 CLIENT_MUTEX_UNLOCK(&slot->mutex);
279                 return ;
280         }
281
282         int state = DP_STATE_NONE;
283         int errorcode = DP_ERROR_NONE;
284
285         if (info->http_status > 0) {
286                 if (dp_db_replace_property(slot->client.dbhandle, request->id, DP_TABLE_DOWNLOAD, DP_DB_COL_HTTP_STATUS, (void *)&info->http_status, 0, 0, &errorcode) < 0)
287                         TRACE_ERROR("id:%d failed to set http_status(%d)", request->id, info->http_status);
288         }
289
290         TRACE_SECURE_DEBUG("[FINISH][%d][%s]", request->id, info->saved_path);
291         if (info->err == DA_RESULT_OK) {
292                 if (info->saved_path != NULL) {
293                         errorcode = __set_file_permission_to_client(slot,
294                                         request, info->saved_path);
295                 } else {
296                         TRACE_ERROR("[ERROR][%d] No SavedPath", request->id);
297                         errorcode = DP_ERROR_INVALID_DESTINATION;
298                 }
299                 if (errorcode == DP_ERROR_NONE)
300                         state = DP_STATE_COMPLETED;
301                 else
302                         state = DP_STATE_FAILED;
303         } else {
304                 if (info->err == DA_RESULT_USER_CANCELED) {
305
306                         TRACE_INFO("[CANCELED][%d]", request->id);
307
308                         // if state is canceled and error is DP_ERROR_IO_EAGAIN mean ip_changed
309                         if (request->error == DP_ERROR_IO_EAGAIN) {
310                                 request->error = DP_ERROR_NONE;
311                         } else {
312                                 state = DP_STATE_CANCELED;
313                                 errorcode = request->error;
314                         }
315
316                 } else {
317                         state = DP_STATE_FAILED;
318                         errorcode = __change_error(info->err);
319                         TRACE_ERROR("[FAILED][%d][%s] agent error:%d", request->id,
320                                         dp_print_errorcode(errorcode), info->err);
321                 }
322
323         }
324
325         if (errorcode == DP_ERROR_NONE && info->saved_path != NULL) {
326
327                 char *content_name = NULL;
328                 char *str = NULL;
329                 str = strrchr(info->saved_path, '/');
330                 if (str != NULL) {
331                         str++;
332                         content_name = dp_strdup(str);
333                 }
334                 if (request->file_size == 0) {// missed in download_cb
335                         request->file_size = request->received_size;
336                         if (dp_db_replace_property(slot->client.dbhandle, request->id, DP_TABLE_DOWNLOAD, DP_DB_COL_CONTENT_SIZE, (void *)&request->file_size, 0, 1, &errorcode) < 0)
337                                 TRACE_ERROR("id:%d failed to set content_size(%llu)", request->id, request->file_size);
338                 }
339                 // update contentname, savedpath
340                 if (content_name != NULL) {
341                         if (dp_db_replace_property(slot->client.dbhandle, request->id, DP_TABLE_DOWNLOAD, DP_DB_COL_CONTENT_NAME, (void *)content_name, 0, 2, &errorcode) < 0)
342                                 TRACE_ERROR("id:%d failed to set content_name", request->id);
343                 }
344                 if (dp_db_replace_property(slot->client.dbhandle, request->id, DP_TABLE_DOWNLOAD, DP_DB_COL_SAVED_PATH, (void *)info->saved_path, 0, 2, &errorcode) < 0)
345                         TRACE_ERROR("id:%d failed to set saved_path", request->id);
346                 free(content_name);
347                 /* update the received file size.
348                  * The last received file size cannot update
349                  * because of reducing update algorithm*/
350                 if (request->progress_cb == 1) {
351                         if (slot->client.notify < 0 ||
352                                         dp_notify_feedback(slot->client.notify, slot, request->id, DP_STATE_DOWNLOADING, DP_ERROR_NONE, request->received_size) < 0) {
353                                 TRACE_ERROR("id:%d disable progress callback by IO_ERROR", request->id);
354                                 request->progress_cb = 0;
355                         }
356                 }
357         }
358
359         request->state = state;
360         request->error = errorcode;
361
362         if (__dp_da_state_feedback(slot, request) < 0) {
363                 TRACE_ERROR("id:%d check notify channel", request->id);
364                 if (dp_cancel_agent_download_without_update(request->agent_id) < 0)
365                         TRACE_ERROR("[fail][%d]cancel_agent", request->id);
366         }
367         if (request->noti_type == DP_NOTIFICATION_TYPE_COMPLETE_ONLY ||
368                         request->noti_type == DP_NOTIFICATION_TYPE_ALL) {
369                 if (dp_notification_manager_push_notification(slot, request, DP_NOTIFICATION) < 0)
370                         TRACE_ERROR("failed to register notification for id:%d", request->id);
371         }
372         free(info->etag);
373         free(info->saved_path);
374         free(info);
375         CLIENT_MUTEX_UNLOCK(&slot->mutex);
376 }
377
378 static void __paused_cb(int download_id, void *user_req_data, void *user_client_data)
379 {
380         dp_client_slots_fmt *slot = user_client_data;
381         dp_request_fmt *request = user_req_data;
382         if (slot == NULL || request == NULL) {
383                 TRACE_ERROR("check address slot:%p request:%p id:%d agentid:%d", slot, request, (request == NULL ? 0 : request->id), download_id);
384                 return ;
385         }
386         dp_queue_manager_wake_up();
387 }
388
389 static void __download_info_cb(download_info_t *info, void *user_req_data, void *user_client_data)
390 {
391         if (info == NULL) {
392                 TRACE_ERROR("check download info address");
393                 return ;
394         }
395         dp_client_slots_fmt *slot = user_client_data;
396         dp_request_fmt *request = user_req_data;
397         if (slot == NULL || request == NULL) {
398                 TRACE_ERROR("check address slot:%p request:%p id:%d agentid:%d", slot, request, (request == NULL ? 0 : request->id), info->download_id);
399                 free(info->content_name);
400                 free(info->etag);
401                 free(info->file_type);
402                 free(info->tmp_saved_path);
403                 free(info);
404                 return ;
405         }
406         CLIENT_MUTEX_LOCK(&slot->mutex);
407         if (__precheck_request(slot, request, info->download_id) < 0) {
408                 TRACE_ERROR("error request agent_id:%d", info->download_id);
409                 if (dp_cancel_agent_download(info->download_id) < 0)
410                         TRACE_ERROR("failed to call cancel_download(%d)", info->download_id);
411                 free(info->content_name);
412                 free(info->etag);
413                 free(info->file_type);
414                 free(info->tmp_saved_path);
415                 free(info);
416                 CLIENT_MUTEX_UNLOCK(&slot->mutex);
417                 return ;
418         }
419
420         // update info before sending event
421         TRACE_SECURE_DEBUG("[DOWNLOAD][%d][%s]", request->id, info->tmp_saved_path);
422         if (info->tmp_saved_path != NULL) {
423                 int errorcode = DP_ERROR_NONE;
424                 if (dp_db_replace_property(slot->client.dbhandle, request->id, DP_TABLE_DOWNLOAD, DP_DB_COL_MIMETYPE, (void *)info->file_type, 0, 2, &errorcode) < 0)
425                         TRACE_ERROR("id:%d failed to set mimetype", request->id);
426                 if (dp_db_replace_property(slot->client.dbhandle, request->id, DP_TABLE_DOWNLOAD, DP_DB_COL_CONTENT_NAME, (void *)info->content_name, 0, 2, &errorcode) < 0)
427                         TRACE_ERROR("id:%d failed to set contentname", request->id);
428                 if (dp_db_replace_property(slot->client.dbhandle, request->id, DP_TABLE_DOWNLOAD, DP_DB_COL_TMP_SAVED_PATH, (void *)info->tmp_saved_path, 0, 2, &errorcode) < 0)
429                         TRACE_ERROR("id:%d failed to set tmp_saved_path", request->id);
430                 if (info->file_size > 0 && dp_db_replace_property(slot->client.dbhandle, request->id, DP_TABLE_DOWNLOAD, DP_DB_COL_CONTENT_SIZE, (void *)&(info->file_size), 0, 1, &errorcode) < 0)
431                         TRACE_ERROR("id:%d failed to set file size", request->id);
432                 if (info->etag && dp_db_replace_property(slot->client.dbhandle, request->id, DP_TABLE_DOWNLOAD, DP_DB_COL_ETAG, (void *)info->etag, 0, 2, &errorcode) < 0)
433                         TRACE_ERROR("id:%d failed to set etag", request->id);
434                 if (strncmp(DP_SDCARD_MNT_POINT, info->tmp_saved_path, strlen(DP_SDCARD_MNT_POINT)) != 0)
435                         errorcode = __set_file_permission_to_client(slot, request, info->tmp_saved_path);
436                 request->error = errorcode;
437         } else {
438                 request->error = DP_ERROR_IO_ERROR;
439         }
440
441         if (request->error != DP_ERROR_NONE) {
442                 request->state = DP_STATE_FAILED;
443                 TRACE_ERROR("id:%d try to cancel(%d)", request->id, info->download_id);
444                 if (dp_cancel_agent_download(request->agent_id) < 0) {
445                         TRACE_ERROR("[fail][%d] cancel_agent:%d", request->id,
446                                         info->download_id);
447                 }
448         } else {
449                 request->state = DP_STATE_DOWNLOADING;
450                 request->file_size = info->file_size; // unsigned
451                 TRACE_DEBUG("[STARTED] id:%d agentid:%d", request->id, info->download_id);
452         }
453
454         if (__dp_da_state_feedback(slot, request) < 0) {
455                 TRACE_ERROR("id:%d check notify channel", request->id);
456                 if (dp_cancel_agent_download(request->agent_id) < 0)
457                         TRACE_ERROR("[fail][%d]cancel_agent", request->id);
458         }
459         // notification
460         if (request->noti_type == DP_NOTIFICATION_TYPE_ALL) {
461                 if (dp_notification_manager_push_notification(slot, request, DP_NOTIFICATION_ONGOING_UPDATE) < 0)
462                         TRACE_ERROR("failed to register notification for id:%d", request->id);
463         }
464         //get the mime type for dp notification
465         if (request->noti_type > DP_NOTIFICATION_TYPE_NONE)
466                 request->content_type = __dp_get_content_type(info->file_type, info->tmp_saved_path);
467
468         free(info->content_name);
469         free(info->etag);
470         free(info->file_type);
471         free(info->tmp_saved_path);
472         free(info);
473         CLIENT_MUTEX_UNLOCK(&slot->mutex);
474 }
475
476 static void __progress_cb(int download_id, unsigned long long received_size,
477                 void *user_req_data, void *user_client_data)
478 {
479         dp_client_slots_fmt *slot = user_client_data;
480         dp_request_fmt *request = user_req_data;
481         if (slot == NULL || request == NULL) {
482                 TRACE_ERROR("check address slot:%p request:%p id:%d agentid:%d", slot, request, (request == NULL ? 0 : request->id), download_id);
483                 return ;
484         }
485         CLIENT_MUTEX_LOCK(&slot->mutex);
486         /*
487            if (CLIENT_MUTEX_TRYLOCK(&slot->mutex) != 0) {
488            TRACE_ERROR("slot busy agent_id:%d", download_id);
489            return ;
490            }
491            */
492         if (__precheck_request(slot, request, download_id) < 0) {
493                 TRACE_ERROR("error request agent_id:%d", download_id);
494                 if (dp_cancel_agent_download(download_id) < 0)
495                         TRACE_ERROR("failed to call cancel_download(%d)", download_id);
496                 CLIENT_MUTEX_UNLOCK(&slot->mutex);
497                 return ;
498         }
499
500         // For resume case after pause, it change state from connecting to downloading
501         if (request->state == DP_STATE_CONNECTING) {
502                 request->state = DP_STATE_DOWNLOADING;
503                 if (__dp_da_state_feedback(slot, request) < 0) {
504                         TRACE_ERROR("id:%d check notify channel", request->id);
505                         if (dp_cancel_agent_download(request->agent_id) < 0)
506                                 TRACE_ERROR("[fail][%d]cancel_agent", request->id);
507                 }
508         }
509
510         if (request->state == DP_STATE_DOWNLOADING) {
511                 request->received_size = received_size;
512                 time_t tt = time(NULL);
513                 struct tm localTime ;
514                 if (localtime_r(&tt, &localTime) == NULL) {
515                         TRACE_ERROR("Error localtime_r");
516                         CLIENT_MUTEX_UNLOCK(&slot->mutex);
517                         return;
518                 }
519                 // send event every 1 second.
520                 if (request->progress_lasttime != localTime.tm_sec) {
521                         request->progress_lasttime = localTime.tm_sec;
522
523                         if (request->progress_cb == 1) {
524                                 if (slot->client.notify < 0 ||
525                                                 dp_notify_feedback(slot->client.notify, slot,
526                                                         request->id, DP_STATE_DOWNLOADING, DP_ERROR_NONE, received_size) < 0) {
527                                         // failed to read from socket // ignore this status
528                                         TRACE_ERROR("id:%d disable progress callback by IO_ERROR", request->id);
529                                         request->progress_cb = 0;
530                                 }
531                         }
532
533                         if (request->noti_type == DP_NOTIFICATION_TYPE_ALL) {
534                                 if (dp_notification_manager_push_notification(slot, request, DP_NOTIFICATION_ONGOING_PROGRESS) < 0)
535                                         TRACE_ERROR("failed to register notification for id:%d", request->id);
536                         }
537
538                 }
539         }
540         CLIENT_MUTEX_UNLOCK(&slot->mutex);
541 }
542
543 static int __dp_is_ambiguous_mime_type(const char *mime_type)
544 {
545         if (mime_type == NULL)
546                 return -1;
547
548         int index = 0;
549         int listSize = sizeof(ambiguous_mime_type_list) / sizeof(const char *);
550         for (index = 0; index < listSize; index++) {
551                 if (0 == strcmp(mime_type, ambiguous_mime_type_list[index])) {
552                         TRACE_DEBUG("It is ambiguous");
553                         return 0;
554                 }
555         }
556         return -1;
557 }
558
559 static dp_content_type __dp_get_content_type(const char *mime, const char *file_path)
560 {
561         int i = 0;
562         int type = DP_CONTENT_UNKNOWN;
563         char *temp_mime = NULL;
564         if (mime == NULL || strlen(mime) < 1)
565                 return DP_CONTENT_UNKNOWN;
566
567         if ((file_path != NULL) && (strlen(file_path) > 0) &&
568                         (__dp_is_ambiguous_mime_type(mime) == 0)) {
569                 const char *ext = strrchr(file_path, '.');
570                 if (ext == NULL) {
571                         TRACE_ERROR("File Extension is NULL");
572                         return type;
573                 }
574                 mime_type_get_mime_type(ext + 1, &temp_mime);
575         }
576         if (temp_mime == NULL) {
577                 temp_mime = (char *)calloc(1, DP_MAX_FILE_PATH_LEN);
578                 if (temp_mime == NULL) {
579                         TRACE_ERROR("Fail to call calloc");
580                         return type;
581                 }
582                 strncpy(temp_mime, mime, DP_MAX_FILE_PATH_LEN - 1);
583         }
584         TRACE_SECURE_DEBUG("mime type [%s]", temp_mime);
585
586         /* Search a content type from mime table. */
587         for (i = 0; i < DP_MAX_MIME_TABLE_NUM; i++) {
588                 if (strcmp(mime_table[i].mime, temp_mime) == 0) {
589                         type = mime_table[i].content_type;
590                         break;
591                 }
592         }
593         if (type == DP_CONTENT_UNKNOWN) {
594                 const char *unaliased_mime = NULL;
595                 /* unaliased_mimetype means representative mime among similar types */
596                 unaliased_mime = xdg_mime_unalias_mime_type(temp_mime);
597
598                 if (unaliased_mime != NULL) {
599                         TRACE_SECURE_DEBUG("unaliased mime type[%s]", unaliased_mime);
600                         if (strstr(unaliased_mime, "video/") != NULL)
601                                 type = DP_CONTENT_VIDEO;
602                         else if (strstr(unaliased_mime, "audio/") != NULL)
603                                 type = DP_CONTENT_MUSIC;
604                         else if (strstr(unaliased_mime, "image/") != NULL)
605                                 type = DP_CONTENT_IMAGE;
606                 }
607         }
608         free(temp_mime);
609         TRACE_DEBUG("type[%d]", type);
610         return type;
611 }
612
613
614 int dp_init_agent()
615 {
616
617         g_da_handle = dlopen(LIB_AGENT_PATH, RTLD_LAZY | RTLD_GLOBAL);
618         if (!g_da_handle) {
619                 TRACE_ERROR("[dlopen] %s", dlerror());
620                 g_da_handle = NULL;
621                 return DP_ERROR_OUT_OF_MEMORY;
622         }
623         dlerror();    /* Clear any existing error */
624
625         *(void **) (&download_agent_init) = dlsym(g_da_handle, "da_init");
626         if (download_agent_init == NULL) {
627                 TRACE_ERROR("[dlsym] da_init:%s", dlerror());
628                 dlclose(g_da_handle);
629                 g_da_handle = NULL;
630                 return DP_ERROR_OUT_OF_MEMORY;
631         }
632
633         *(void **) (&download_agent_deinit) = dlsym(g_da_handle, "da_deinit");
634         if (download_agent_deinit == NULL) {
635                 TRACE_ERROR("[dlsym] da_deinit:%s", dlerror());
636                 dlclose(g_da_handle);
637                 g_da_handle = NULL;
638                 return DP_ERROR_OUT_OF_MEMORY;
639         }
640
641         *(void **) (&download_agent_is_alive) =
642                 dlsym(g_da_handle, "da_is_valid_download_id");
643         if (download_agent_is_alive == NULL) {
644                 TRACE_ERROR("[dlsym] da_is_valid_download_id:%s", dlerror());
645                 dlclose(g_da_handle);
646                 g_da_handle = NULL;
647                 return DP_ERROR_OUT_OF_MEMORY;
648         }
649
650         *(void **) (&download_agent_suspend) =
651                 dlsym(g_da_handle, "da_suspend_download");
652         if (download_agent_suspend == NULL) {
653                 TRACE_ERROR("[dlsym] da_suspend_download:%s", dlerror());
654                 dlclose(g_da_handle);
655                 g_da_handle = NULL;
656                 return DP_ERROR_OUT_OF_MEMORY;
657         }
658
659         *(void **) (&download_agent_resume) =
660                 dlsym(g_da_handle, "da_resume_download");
661         if (download_agent_resume == NULL) {
662                 TRACE_ERROR("[dlsym] da_resume_download:%s", dlerror());
663                 dlclose(g_da_handle);
664                 g_da_handle = NULL;
665                 return DP_ERROR_OUT_OF_MEMORY;
666         }
667
668         //      *(void **) (&download_agent_cancel) = dlsym(g_da_handle, "da_cancel_download_without_update");
669         *(void **) (&download_agent_cancel) =
670                 dlsym(g_da_handle, "da_cancel_download");
671         if (download_agent_cancel == NULL) {
672                 TRACE_ERROR("[dlsym] da_cancel_download:%s", dlerror());
673                 dlclose(g_da_handle);
674                 g_da_handle = NULL;
675                 return DP_ERROR_OUT_OF_MEMORY;
676         }
677
678         *(void **) (&download_agent_start) =
679                 dlsym(g_da_handle, "da_start_download");
680         if (download_agent_start == NULL) {
681                 TRACE_ERROR("[dlsym] da_start_download:%s", dlerror());
682                 dlclose(g_da_handle);
683                 g_da_handle = NULL;
684                 return DP_ERROR_OUT_OF_MEMORY;
685         }
686
687         *(void **) (&download_agent_cancel_without_update) = dlsym(g_da_handle, "da_cancel_download_without_update");
688         if (download_agent_cancel_without_update == NULL) {
689                 TRACE_ERROR("[dlsym] da_cancel_download_without_update:%s", dlerror());
690                 dlclose(g_da_handle);
691                 g_da_handle = NULL;
692                 return DP_ERROR_OUT_OF_MEMORY;
693         }
694
695         *(void **) (&download_agent_suspend_without_update) = dlsym(g_da_handle, "da_suspend_download_without_update");
696         if (download_agent_suspend_without_update == NULL) {
697                 TRACE_ERROR("[dlsym] da_suspend_download_without_update:%s", dlerror());
698                 dlclose(g_da_handle);
699                 g_da_handle = NULL;
700                 return DP_ERROR_OUT_OF_MEMORY;
701         }
702
703         int da_ret = -1;
704         da_ret = (*download_agent_init)();
705         if (da_ret != DA_RESULT_OK)
706                 return DP_ERROR_OUT_OF_MEMORY;
707         return DP_ERROR_NONE;
708 }
709
710 void dp_deinit_agent()
711 {
712         if (g_da_handle != NULL) {
713                 if (download_agent_deinit != NULL)
714                         (*download_agent_deinit)();
715
716                 // Do not unload a symbol file here.
717                 //dlclose(g_da_handle);
718                 //g_da_handle = NULL;
719         }
720 }
721
722 // 1 : alive
723 // 0 : not alive
724 int dp_is_alive_download(int req_id)
725 {
726         int da_ret = 0;
727         if (req_id < 0)
728                 return 0;
729         if (download_agent_is_alive != NULL)
730                 da_ret = (*download_agent_is_alive)(req_id);
731         return da_ret;
732 }
733
734 // 0 : success
735 // -1 : failed
736 int dp_cancel_agent_download(int req_id)
737 {
738         if (req_id < 0) {
739                 TRACE_ERROR("[NULL-CHECK] req_id");
740                 return -1;
741         }
742         if (dp_is_alive_download(req_id) == 0) {
743                 TRACE_ERROR("[CHECK agent-id:%d] dead request", req_id);
744                 return -1;
745         }
746         if (download_agent_cancel != NULL) {
747                 if ((*download_agent_cancel)(req_id) == DA_RESULT_OK)
748                         return 0;
749         }
750         return -1;
751 }
752
753 // 0 : success
754 // -1 : failed
755 int dp_pause_agent_download(int req_id)
756 {
757         if (req_id < 0) {
758                 TRACE_ERROR("[NULL-CHECK] req_id");
759                 return -1;
760         }
761         if (dp_is_alive_download(req_id) == 0) {
762                 TRACE_ERROR("[CHECK agent-id:%d] dead request", req_id);
763                 return -1;
764         }
765         if (download_agent_suspend != NULL) {
766                 if ((*download_agent_suspend)(req_id) == DA_RESULT_OK)
767                         return 0;
768         }
769         return -1;
770 }
771
772
773 // 0 : success
774 // -1 : failed
775 int dp_cancel_agent_download_without_update(int req_id)
776 {
777         if (req_id < 0) {
778                 TRACE_ERROR("[NULL-CHECK] req_id");
779                 return -1;
780         }
781         if (dp_is_alive_download(req_id) == 0) {
782                 TRACE_ERROR("[CHECK agent-id:%d] dead request", req_id);
783                 return -1;
784         }
785         if (download_agent_cancel_without_update != NULL) {
786                 if ((*download_agent_cancel_without_update)(req_id) == DA_RESULT_OK)
787                         return 0;
788         }
789         return -1;
790 }
791
792 // 0 : success
793 // -1 : failed
794 int dp_pause_agent_download_without_update(int req_id)
795 {
796         if (req_id < 0) {
797                 TRACE_ERROR("[NULL-CHECK] req_id");
798                 return -1;
799         }
800         if (dp_is_alive_download(req_id) == 0) {
801                 TRACE_ERROR("[CHECK agent-id:%d] dead request", req_id);
802                 return -1;
803         }
804         if (download_agent_suspend_without_update != NULL) {
805                 if ((*download_agent_suspend_without_update)(req_id) == DA_RESULT_OK)
806                         return 0;
807         }
808         return -1;
809 }
810
811 // 0 : success
812 // -1 : failed
813 // -2 : pended
814 int dp_start_agent_download(void *slot, void *request)
815 {
816         int da_ret = -1;
817         int req_dl_id = -1;
818         req_data_t *req_data = NULL;
819
820         dp_client_slots_fmt *base_slot = slot;
821         dp_request_fmt *base_req = request;
822
823         if (slot == NULL || request == NULL) {
824                 TRACE_ERROR("check slot or request address");
825                 return DP_ERROR_INVALID_PARAMETER;
826         }
827
828         da_cb_t da_cb = {
829                 __download_info_cb,
830                 __progress_cb,
831                 __finished_cb,
832                 __paused_cb
833         };
834
835         req_data = (req_data_t *)calloc(1, sizeof(req_data_t));
836         if (req_data == NULL) {
837                 TRACE_ERROR("[ERROR] calloc");
838                 return DP_ERROR_OUT_OF_MEMORY;
839         }
840
841         int errorcode = DP_ERROR_NONE;
842         unsigned length = 0;
843         char *url = NULL;
844         char *proxy = NULL;
845         char *destination = NULL;
846         char *tmp_saved_path = NULL;
847         char *user_tmp_file_path = NULL;
848         char *filename = NULL;
849         char *etag = NULL;
850         int user_network_bonding = 0;
851
852         if (dp_db_get_property_string(base_slot->client.dbhandle, base_req->id, DP_TABLE_REQUEST, DP_DB_COL_URL, (unsigned char **)&url, &length, &errorcode) < 0 ||
853                         url == NULL) {
854                 free(req_data);
855                 if (errorcode == DP_ERROR_NO_DATA) {
856                         TRACE_ERROR("url id:%d NO_DATA", base_req->id);
857                         return DP_ERROR_INVALID_URL;
858                 } else {
859                         TRACE_ERROR("url id:%d DISK_BUSY", base_req->id);
860                         return DP_ERROR_DISK_BUSY;
861                 }
862         }
863         if (dp_db_get_property_string(base_slot->client.dbhandle, base_req->id, DP_TABLE_REQUEST, DP_DB_COL_PROXY, (unsigned char **)&proxy, &length, &errorcode) < 0 ||
864                         proxy == NULL) {
865                 TRACE_DEBUG("proxy id:%d NO_DATA", base_req->id);
866                 req_data->proxy = NULL;
867         } else {
868                 req_data->proxy = proxy;
869         }
870         if (dp_db_get_property_string(base_slot->client.dbhandle, base_req->id, DP_TABLE_REQUEST, DP_DB_COL_TEMP_FILE_PATH, (unsigned char **)&user_tmp_file_path, &length, &errorcode) < 0 ||
871                         user_tmp_file_path == NULL) {
872                 TRACE_DEBUG("user_tmp_file_path id:%d NO_DATA", base_req->id);
873         }
874
875         if (user_tmp_file_path != NULL)
876                 req_data->temp_file_path = user_tmp_file_path;
877         else {
878                 if (dp_db_get_property_string(base_slot->client.dbhandle, base_req->id, DP_TABLE_REQUEST, DP_DB_COL_FILENAME, (unsigned char **)&filename, &length, &errorcode) < 0 ||
879                                 filename == NULL) {
880                         TRACE_DEBUG("filename id:%d NO_DATA", base_req->id);
881                 } else
882                         req_data->file_name = filename;
883                 if (dp_db_get_property_string(base_slot->client.dbhandle, base_req->id, DP_TABLE_REQUEST, DP_DB_COL_DESTINATION, (unsigned char **)&destination, &length, &errorcode) < 0 ||
884                                 destination == NULL) {
885                         TRACE_DEBUG("destination id:%d NO_DATA", base_req->id);
886                 } else
887                         req_data->install_path = destination;
888                 if (dp_db_get_property_string(base_slot->client.dbhandle, base_req->id, DP_TABLE_DOWNLOAD, DP_DB_COL_TMP_SAVED_PATH, (unsigned char **)&tmp_saved_path, &length, &errorcode) < 0 ||
889                                 tmp_saved_path == NULL) {
890                         TRACE_DEBUG("tmp_saved_path id:%d NO_DATA", base_req->id);
891                 }
892         }
893
894         if (tmp_saved_path != NULL) {
895                 if (dp_db_get_property_string(base_slot->client.dbhandle, base_req->id, DP_TABLE_DOWNLOAD, DP_DB_COL_ETAG, (unsigned char **)&etag, &length, &errorcode) < 0 ||
896                                 etag == NULL) {
897                         TRACE_DEBUG("etag id:%d NO_DATA", base_req->id);
898                 }
899                 if (etag != NULL) {
900                         TRACE_DEBUG("try to resume id:%d", base_req->id);
901                         req_data->etag = etag;
902                         req_data->temp_file_path = tmp_saved_path;
903                 } else {
904                         /* FIXME later : It is better to handle the unlink function in download agaent module
905                          * or in upload the request data to memory after the download provider process is restarted */
906                         TRACE_SECURE_INFO("try to restart id:%d remove tmp file:%s",
907                                         base_req->id, tmp_saved_path);
908                         if (dp_is_file_exist(tmp_saved_path) == 0) {
909                                 if (unlink(tmp_saved_path) != 0)
910                                         TRACE_ERROR("failed to remove file id:%d", base_req->id);
911                         }
912                 }
913         }
914         if (dp_db_get_property_int(base_slot->client.dbhandle, base_req->id, DP_TABLE_REQUEST, DP_DB_COL_NETWORK_BONDING, (int *)&user_network_bonding, &errorcode) < 0 ||
915                         user_network_bonding < 0) {
916                 TRACE_DEBUG("unable to get network bonding value for id:%d", base_req->id);
917         } else
918                 req_data->network_bonding = user_network_bonding;
919
920         req_data->disable_verify_host = base_req->disable_verify_host;
921         req_data->pkg_name = base_slot->pkgname;
922
923         // get headers list from header table(DB)
924         int headers_count = dp_db_check_duplicated_int(base_slot->client.dbhandle, DP_TABLE_HEADERS, DP_DB_COL_ID, base_req->id, &errorcode);
925         if (headers_count > 0) {
926                 req_data->request_header = calloc(headers_count, sizeof(char *));
927                 if (req_data->request_header != NULL) {
928                         headers_count = dp_db_get_http_headers_list(base_slot->client.dbhandle, base_req->id, (char **)req_data->request_header, &errorcode);
929                         if (headers_count > 0)
930                                 req_data->request_header_count = headers_count;
931                 }
932         }
933
934         req_data->user_client_data = (void *)slot;
935         req_data->user_req_data = (void *)request;
936
937         // call start API of agent lib
938         if (download_agent_start != NULL)
939                 da_ret = (*download_agent_start)(url, req_data, &da_cb, &req_dl_id);
940         if (req_data->request_header_count > 0) {
941                 int len = 0;
942                 int i = 0;
943                 len = req_data->request_header_count;
944                 if (req_data->request_header != NULL) {
945                         for (i = 0; i < len; i++)
946                                 free((void *)(req_data->request_header[i]));
947                 }
948                 free(req_data->request_header);
949         }
950         free(url);
951         free(destination);
952         free(tmp_saved_path);
953         free(user_tmp_file_path);
954         free(filename);
955         free(etag);
956         free(req_data);
957
958         if (da_ret == DA_RESULT_OK) {
959                 TRACE_DEBUG("request id :%d SUCCESS agent_id:%d", base_req->id, req_dl_id);
960                 base_req->agent_id = req_dl_id;
961         }
962         return __change_error(da_ret);
963 }
964
965 int dp_resume_agent_download(int req_id)
966 {
967         int da_ret = -1;
968         if (req_id < 0) {
969                 TRACE_ERROR("[NULL-CHECK] req_id");
970                 return DP_ERROR_INVALID_PARAMETER;
971         }
972         if (download_agent_resume != NULL)
973                 da_ret = (*download_agent_resume)(req_id);
974         if (da_ret == DA_RESULT_OK)
975                 return DP_ERROR_NONE;
976         else if (da_ret == DA_ERR_INVALID_STATE)
977                 return DP_ERROR_INVALID_STATE;
978         return __change_error(da_ret);
979 }
980