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