00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "config.h"
00035
00036
00037 #include <glib.h>
00038 #include <gtk/gtk.h>
00039 #include <webkit/webkit.h>
00040
00041
00042 #include <libermetadb/ermetadb.h>
00043
00044
00045 #include "log.h"
00046 #include "download.h"
00047 #include "i18n.h"
00048 #include "ipc.h"
00049 #include "view.h"
00050
00051 #define UNUSED(x) (void)(x)
00052
00053
00054
00055
00056
00057
00058 typedef struct _DowloadDialog {
00059 BrowserWindow *browser_window;
00060 WebKitDownload *download;
00061 GtkWidget *window;
00062 GtkWidget *progress_bar;
00063 GtkWidget *button;
00064 GtkWidget *uri_label;
00065 } DownloadDialog;
00066
00067
00068
00069
00070
00071
00072 const gchar *download_folder = "Downloads";
00073 const gint box_spacing = 12;
00074 const gint uri_label_width = 500;
00075 const gint progress_interval = 2;
00076
00077
00078
00079
00080
00081
00082 static guint g_update_progress = 0;
00083
00084
00085
00086
00087
00088
00089 static void download_error_cb (WebKitDownload *download,
00090 guint domain,
00091 WebKitDownloadError error,
00092 const gchar *message,
00093 DownloadDialog *dialog);
00094
00095 static void download_button_cancel_cb(GtkWidget *button, DownloadDialog *dialog);
00096
00097 static void download_set_ok (DownloadDialog *dialog, const gchar *message);
00098
00099 static void download_destroy_cb (GtkWidget *widget, DownloadDialog *dialog);
00100
00101 static void download_response_cb (GtkWidget *window, gint response, DownloadDialog *dialog);
00102
00103 static gboolean is_local_file (const gchar *uri);
00104
00105 static gboolean update_progress_cb (gpointer data);
00106
00107 static void add_file_to_metadata (const gchar *dirname, const gchar *filename);
00108
00109 static void add_folder_to_metadata (const gchar *dirname, const gchar *foldername);
00110
00111 static void download_status_changed_cb(WebKitDownload *download, GParamSpec *pspec, DownloadDialog *dialog);
00112
00113 static gchar *make_unique_filename(const gchar *dirname, const gchar *fn);
00114
00115
00116
00117
00118
00119
00120 gboolean download_requested_cb(WebKitWebView *web_view,
00121 WebKitDownload *download,
00122 BrowserWindow *browser_window)
00123 {
00124 LOGPRINTF("entry window [%p]", browser_window);
00125
00126 DownloadDialog *dialog = NULL;
00127
00128 if (is_local_file(webkit_download_get_uri(download)))
00129 {
00130 LOGPRINTF("You could open the file [%s] without transferring it", webkit_download_get_uri(download));
00131
00132 gchar *title;
00133 title = g_strdup_printf(_("Unable to open %s"), webkit_download_get_uri(download));
00134 view_show_error(title, _("The web browser is unable to display the document. "
00135 "Since it is on the SD card, you can open it from Documents."));
00136 g_free(title);
00137 return FALSE;
00138 }
00139
00140 if (!g_mountpoint)
00141 {
00142 ERRORPRINTF("No mountpoint, cannot download");
00143
00144
00145
00146 webkit_web_view_stop_loading(web_view);
00147
00148 GtkWidget *widget;
00149 widget = gtk_message_dialog_new(GTK_WINDOW(browser_window->window),
00150 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
00151 GTK_MESSAGE_WARNING,
00152 GTK_BUTTONS_OK,
00153 _("The download cannot be started because there is no SD card in this device. "
00154 "Please insert a card and try again."));
00155
00156 gtk_dialog_run(GTK_DIALOG(widget));
00157 gtk_widget_destroy(widget);
00158
00159 return FALSE;
00160 }
00161
00162
00163
00164 gchar *extension = g_strrstr(webkit_download_get_suggested_filename(download),".");
00165 if (extension && (strncmp(extension, ".acsm", 5) == 0))
00166 {
00167 LOGPRINTF("found .acsm file, download and open with Adobe Fullfilment");
00168 browser_window->open_download = TRUE;
00169 }
00170
00171
00172 gchar *download_path;
00173 #if MACHINE_IS_DR800SG || MACHINE_IS_DR800SW
00174 if (browser_window->open_download)
00175 {
00176 LOGPRINTF("open_download, set temp path");
00177 download_path = g_strdup(g_get_tmp_dir());
00178 }
00179 else
00180 #endif
00181 {
00182 download_path = g_build_path("/", g_mountpoint, download_folder, NULL);
00183
00184
00185 if (!g_file_test(download_path, G_FILE_TEST_IS_DIR))
00186 {
00187 if (g_mkdir_with_parents(download_path, 0777) >= 0)
00188 {
00189 add_folder_to_metadata(g_mountpoint, download_folder);
00190 }
00191 }
00192
00193 if (!g_file_test(download_path, G_FILE_TEST_IS_DIR))
00194 {
00195 ERRORPRINTF("Failed to create %s, error [%d] [%s]", download_path, errno, g_strerror(errno));
00196
00197
00198
00199 webkit_web_view_stop_loading(web_view);
00200
00201 GtkWidget *widget;
00202 widget = gtk_message_dialog_new(GTK_WINDOW(browser_window->window),
00203 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
00204 GTK_MESSAGE_WARNING,
00205 GTK_BUTTONS_OK,
00206 _("An error has occurred while saving the file to the SD card. It is possible the card is full or locked."));
00207
00208 gtk_dialog_run(GTK_DIALOG(widget));
00209 gtk_widget_destroy(widget);
00210
00211 g_free(download_path);
00212 return FALSE;
00213 }
00214 }
00215
00216
00217 gchar *filename = make_unique_filename(download_path, webkit_download_get_suggested_filename(download));
00218
00219 dialog = g_new0(DownloadDialog, 1);
00220 dialog->browser_window = browser_window;
00221 dialog->download = g_object_ref(download);
00222
00223
00224
00225
00226 dialog->window = gtk_dialog_new_with_buttons(_("Download Progress"),
00227 GTK_WINDOW(browser_window->window),
00228 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
00229 NULL);
00230 gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog->window)->vbox), box_spacing);
00231
00232
00233
00234 gchar *message;
00235 dialog->uri_label = gtk_label_new(NULL);
00236 message = g_strdup_printf(_("Downloading '%s'..."), filename);
00237 gtk_label_set_label(GTK_LABEL(dialog->uri_label), message);
00238 gtk_label_set_line_wrap(GTK_LABEL(dialog->uri_label), TRUE);
00239 gtk_widget_set_size_request(dialog->uri_label, uri_label_width, -1);
00240 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog->window)->vbox), dialog->uri_label, FALSE, FALSE, 0);
00241 g_free(message);
00242
00243
00244
00245 dialog->progress_bar = gtk_progress_bar_new();
00246 gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(dialog->progress_bar), GTK_PROGRESS_LEFT_TO_RIGHT);
00247 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(dialog->progress_bar), 0.0);
00248 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog->window)->vbox), dialog->progress_bar, FALSE, FALSE, 0);
00249
00250
00251
00252 GtkWidget *button_box = gtk_hbutton_box_new();
00253 GTK_DIALOG(dialog->window)->action_area = button_box;
00254 gtk_button_box_set_layout(GTK_BUTTON_BOX(button_box), GTK_BUTTONBOX_END);
00255 dialog->button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
00256 g_signal_connect(G_OBJECT(dialog->button), "clicked", G_CALLBACK(download_button_cancel_cb), dialog);
00257 gtk_box_pack_start(GTK_BOX(button_box), dialog->button, FALSE, FALSE, 0);
00258 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog->window)->vbox), button_box, FALSE, FALSE, 0);
00259
00260 gtk_widget_show_all(GTK_WIDGET(dialog->window));
00261
00262
00263 gchar *local_uri = NULL;
00264 local_uri = g_strconcat("file://", filename, NULL);
00265
00266 LOGPRINTF("Download file to [%s]", local_uri);
00267
00268 webkit_download_set_destination_uri(dialog->download, local_uri);
00269 g_free(local_uri);
00270 g_free(download_path);
00271 g_free(filename);
00272
00273 g_signal_connect(dialog->window, "close", G_CALLBACK(download_destroy_cb), dialog);
00274 g_signal_connect(dialog->window, "response", G_CALLBACK(download_response_cb), dialog);
00275
00276 g_signal_connect(G_OBJECT(download), "error", G_CALLBACK(download_error_cb), dialog);
00277 g_signal_connect(G_OBJECT(download), "notify::status", G_CALLBACK(download_status_changed_cb), dialog);
00278
00279
00280 g_update_progress = g_timeout_add_seconds(progress_interval, update_progress_cb, dialog);
00281
00282 ipc_sys_bg_busy(TRUE);
00283
00284 return TRUE;
00285 }
00286
00287
00288
00289
00290
00291
00292 static void download_status_changed_cb(WebKitDownload *download, GParamSpec *pspec, DownloadDialog *dialog)
00293 {
00294 UNUSED(download);
00295 UNUSED(pspec);
00296 LOGPRINTF("entry");
00297
00298 WebKitDownloadStatus status = webkit_download_get_status(dialog->download);
00299
00300 switch (status)
00301 {
00302 case WEBKIT_DOWNLOAD_STATUS_CREATED:
00303 LOGPRINTF("status WEBKIT_DOWNLOAD_STATUS_CREATED");
00304 break;
00305
00306 case WEBKIT_DOWNLOAD_STATUS_STARTED:
00307 LOGPRINTF("status WEBKIT_DOWNLOAD_STATUS_STARTED");
00308 update_progress_cb(dialog);
00309 break;
00310
00311 case WEBKIT_DOWNLOAD_STATUS_FINISHED:
00312 {
00313 LOGPRINTF("status WEBKIT_DOWNLOAD_STATUS_FINISHED");
00314
00315 const gchar *uri = webkit_download_get_destination_uri(dialog->download);
00316 const gchar *filename = NULL;
00317 if (is_local_file(uri))
00318 {
00319 filename = uri + strlen("file://");
00320 }
00321
00322 if (filename)
00323 {
00324 #if MACHINE_IS_DR800SG || MACHINE_IS_DR800SW
00325 if (dialog->browser_window->open_download)
00326 {
00327 gtk_dialog_response(GTK_DIALOG(dialog->window), GTK_RESPONSE_CLOSE);
00328
00329 gchar *cmd_line = g_strdup_printf("/usr/bin/adobe-fulfill --acsm %s", filename);
00330 LOGPRINTF("auto open: start task [%s]", cmd_line);
00331 ipc_sys_start_task(cmd_line, NULL, "Adobe DRM fullfillment", NULL, NULL);
00332 g_free(cmd_line);
00333 }
00334 else
00335 #endif
00336 {
00337 gchar *dirname = g_path_get_dirname(filename);
00338 gchar *basename = g_path_get_basename(filename);
00339
00340 add_file_to_metadata(dirname, basename);
00341
00342
00343 gchar *extension = g_strrstr(basename, ".");
00344 gchar *tag = NULL;
00345 if (extension && (strncasecmp(extension, ".np", 3) == 0))
00346 {
00347 tag = _("News");
00348 }
00349 else
00350 {
00351 tag = _("Books");
00352 }
00353
00354 gchar *message = g_strdup_printf(
00355 _("'%s' has successfully downloaded and can be found in %s."),
00356 basename, tag);
00357 download_set_ok(dialog, message);
00358
00359 g_free(message);
00360 g_free(dirname);
00361 g_free(basename);
00362 }
00363 }
00364 else
00365 {
00366 LOGPRINTF("Failed to get uri of downloaded file");
00367 }
00368
00369 if (g_update_progress)
00370 {
00371 LOGPRINTF("stop update progress timer");
00372 g_source_remove(g_update_progress);
00373 g_update_progress = 0;
00374 }
00375
00376 ipc_sys_bg_busy(FALSE);
00377 }
00378 break;
00379
00380 case WEBKIT_DOWNLOAD_STATUS_CANCELLED:
00381 LOGPRINTF("status WEBKIT_DOWNLOAD_STATUS_CANCELLED");
00382 WARNPRINTF("download state [%d]", status);
00383 break;
00384
00385 case WEBKIT_DOWNLOAD_STATUS_ERROR:
00386
00387 LOGPRINTF("status WEBKIT_DOWNLOAD_STATUS_ERROR");
00388 WARNPRINTF("download state [%d]", status);
00389 break;
00390
00391 default:
00392 WARNPRINTF("unknown download state [%d]", status);
00393 break;
00394 }
00395
00396 LOGPRINTF("leave");
00397 }
00398
00399
00400 static void download_error_cb(WebKitDownload *download,
00401 guint domain,
00402 WebKitDownloadError error,
00403 const gchar *message,
00404 DownloadDialog *dialog)
00405 {
00406 UNUSED(download);
00407 UNUSED(domain);
00408 UNUSED(message);
00409 LOGPRINTF("entry: error [%d] message [%s]", error, message);
00410
00411 switch (error)
00412 {
00413 case WEBKIT_DOWNLOAD_ERROR_CANCELLED_BY_USER:
00414 download_set_ok(dialog, _("The download has been canceled."));
00415 break;
00416
00417 case WEBKIT_DOWNLOAD_ERROR_DESTINATION:
00418 download_set_ok(dialog, _("An error has occurred while saving the file to the SD card. It is possible the card is full or locked."));
00419 break;
00420
00421 case WEBKIT_DOWNLOAD_ERROR_NETWORK:
00422 download_set_ok(dialog, _("A network error has occurred and the download was not completed. Please check your network connection and try again."));
00423 break;
00424
00425 default:
00426 WARNPRINTF("unknown download error [%d]", error);
00427 break;
00428 }
00429
00430 if (g_update_progress)
00431 {
00432 LOGPRINTF("stop update progress timer");
00433 g_source_remove(g_update_progress);
00434 g_update_progress = 0;
00435 }
00436
00437 ipc_sys_bg_busy(FALSE);
00438 }
00439
00440
00441 static gboolean update_progress_cb(gpointer data)
00442 {
00443 DownloadDialog *dialog = (DownloadDialog*) data;
00444 if (dialog && GTK_IS_PROGRESS_BAR(dialog->progress_bar))
00445 {
00446 gdouble progress = webkit_download_get_progress(dialog->download);
00447 LOGPRINTF("progress [%f]", progress);
00448 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(dialog->progress_bar), progress);
00449 }
00450
00451
00452 return TRUE;
00453 }
00454
00455
00456 static void add_file_to_metadata(const gchar *dirname, const gchar *filename)
00457 {
00458 LOGPRINTF("entry");
00459
00460 struct stat stats;
00461 gchar *buffer = g_strdup_printf("%s/%s", dirname, filename);
00462 int error = stat(buffer, &stats);
00463 g_free(buffer);
00464 if (error == -1)
00465 {
00466 ERRORPRINTF("Failed to add metadata for %s, error [%d] [%s]", filename, errno, g_strerror(errno));
00467 return;
00468 }
00469
00470
00471 gchar *extension = g_strrstr(filename, ".");
00472 const char* tag = "book";
00473 if (extension && (strncasecmp(extension, ".np", 3) == 0))
00474 {
00475 tag = "news";
00476 }
00477
00478
00479 erMetadb metadb = ermetadb_global_open("/media/mmcblk0p1", FALSE);
00480 if (metadb == NULL) {
00481 ERRORPRINTF("Opening metadb: returned");
00482 return;
00483 }
00484 int ret = ermetadb_global_add_file(metadb, dirname, filename, stats.st_size, stats.st_mtime, filename, NULL, tag);
00485 if (ret != ER_OK) {
00486 ERRORPRINTF("adding document, returned %d", ret);
00487 }
00488
00489 ermetadb_close(metadb);
00490 }
00491
00492
00493 static void add_folder_to_metadata(const gchar *dirname, const gchar *foldername)
00494 {
00495 LOGPRINTF("entry");
00496
00497
00498 erMetadb metadb = ermetadb_global_open("/media/mmcblk0p1", FALSE);
00499 if (metadb == NULL) {
00500 ERRORPRINTF("Opening metadb: returned");
00501 return;
00502 }
00503 gint64 time_modified = 0;
00504 int ret = ermetadb_global_add_folder(metadb, dirname, foldername, time_modified);
00505 if (ret != ER_OK) {
00506 ERRORPRINTF("adding document, returned %d", ret);
00507 }
00508
00509 ermetadb_close(metadb);
00510 }
00511
00512
00513 static void download_button_cancel_cb(GtkWidget *button, DownloadDialog *dialog)
00514 {
00515 UNUSED(button);
00516 LOGPRINTF("entry");
00517
00518 gint rc;
00519 GtkWidget *widget = NULL;
00520 gchar *message;
00521 const gchar *filename = webkit_download_get_suggested_filename(dialog->download);
00522
00523 message = g_strdup_printf( _("Do you wish to stop downloading '%s'?"), filename);
00524
00525 widget = gtk_message_dialog_new(GTK_WINDOW(dialog->window),
00526 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
00527 GTK_MESSAGE_WARNING,
00528 GTK_BUTTONS_YES_NO,
00529 message);
00530 rc = gtk_dialog_run(GTK_DIALOG(widget));
00531
00532 if (rc == GTK_RESPONSE_OK ||
00533 rc == GTK_RESPONSE_YES )
00534 {
00535 LOGPRINTF("User cancelled download");
00536 webkit_download_cancel(dialog->download);
00537 }
00538
00539 gtk_widget_destroy(widget);
00540 g_free(message);
00541 }
00542
00543
00544 static void download_set_ok(DownloadDialog *dialog, const gchar *message)
00545 {
00546 LOGPRINTF("entry");
00547
00548 gtk_label_set_label(GTK_LABEL(dialog->uri_label), message);
00549 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(dialog->progress_bar), 1.0);
00550 gtk_button_set_label(GTK_BUTTON(dialog->button), GTK_STOCK_OK);
00551
00552 g_signal_handlers_disconnect_by_func(dialog->button, download_button_cancel_cb, dialog);
00553 g_signal_handlers_disconnect_by_func(dialog->button, download_response_cb, dialog);
00554 g_signal_connect(G_OBJECT(dialog->button), "clicked", G_CALLBACK(download_destroy_cb), dialog);
00555 }
00556
00557
00558 static void download_response_cb(GtkWidget *window, gint response, DownloadDialog *dialog)
00559 {
00560 UNUSED(window);
00561 LOGPRINTF("entry: %d", response);
00562
00563 switch (response)
00564 {
00565 case GTK_RESPONSE_CANCEL:
00566 case GTK_RESPONSE_DELETE_EVENT:
00567 webkit_download_cancel(dialog->download);
00568 break;
00569
00570 case GTK_RESPONSE_CLOSE:
00571 gtk_widget_destroy(dialog->window);
00572 dialog->window = NULL;
00573 break;
00574
00575 default:
00576
00577 break;
00578 }
00579 }
00580
00581
00582 static void download_destroy_cb(GtkWidget *widget, DownloadDialog *dialog)
00583 {
00584 UNUSED(widget);
00585 LOGPRINTF("entry");
00586
00587 if (dialog->window)
00588 {
00589 gtk_widget_destroy(dialog->window);
00590 dialog->window = NULL;
00591 }
00592
00593 g_free(dialog);
00594 dialog = NULL;
00595 }
00596
00597
00598 static gboolean is_local_file(const gchar *uri)
00599 {
00600 return uri && g_str_has_prefix(uri, "file://");
00601 }
00602
00603
00604 static gchar *make_unique_filename(const gchar *dirname, const gchar *fn)
00605 {
00606 LOGPRINTF("entry [%s]", fn);
00607
00608 gchar *filename = g_strdup_printf("%s/%s", dirname, fn);
00609 gchar *name = g_strdup(fn);
00610 gchar *dot = g_strrstr(name, ".");
00611 gchar *ext = NULL;
00612 if (dot)
00613 {
00614 ext = g_strdup(dot+1);
00615 *dot = '\0';
00616 }
00617
00618 int i = 0;
00619 while (g_file_test(filename, G_FILE_TEST_IS_REGULAR | G_FILE_TEST_EXISTS) && i < 99)
00620 {
00621 g_free(filename);
00622 if (ext)
00623 {
00624 filename = g_strdup_printf("%s/%s_%02d.%s", dirname, name, ++i, ext);
00625 }
00626 else
00627 {
00628 filename = g_strdup_printf("%s/%s_%02d", dirname, name, ++i);
00629 }
00630 }
00631
00632 g_free(ext);
00633 g_free(name);
00634
00635 LOGPRINTF("leave [%s]", filename);
00636
00637 return filename;
00638 }