summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobert Timm <mail@rtti.de>2016-09-29 17:35:29 +0200
committerRobert Timm <mail@rtti.de>2016-10-12 23:28:53 +0700
commita4a6b0ff689c13e954552bbe9ba8fd7c822d449f (patch)
tree6373a0723f593a591aaa066c3376e45a2a115157 /src
parenta1f982e56162dc04facd6993116a5165b1f0d031 (diff)
Implements download path and tracking
Diffstat (limited to 'src')
-rw-r--r--src/main.c192
-rw-r--r--src/main.h2
-rw-r--r--src/setting.c1
3 files changed, 191 insertions, 4 deletions
diff --git a/src/main.c b/src/main.c
index 93141ad..77d7af7 100644
--- a/src/main.c
+++ b/src/main.c
@@ -49,7 +49,14 @@ static void input_print(Client *c, gboolean force, MessageType type,
gboolean hide, const char *message);
static void marks_clear(Client *c);
static void mode_free(Mode *mode);
+static void on_webctx_download_started(WebKitWebContext *webctx,
+ WebKitDownload *download, Client *c);
static void on_webctx_init_web_extension(WebKitWebContext *webctx, gpointer data);
+static gboolean on_webdownload_decide_destination(WebKitDownload *download,
+ gchar *suggested_filename, Client *c);
+static void on_webdownload_failed(WebKitDownload *download,
+ GError *error, Client *c);
+static void on_webdownload_finished(WebKitDownload *download, Client *c);
static void on_webview_close(WebKitWebView *webview, Client *c);
static WebKitWebView *on_webview_create(WebKitWebView *webview,
WebKitNavigationAction *navact, Client *c);
@@ -348,13 +355,12 @@ void vb_modelabel_update(Client *c, const char *label)
*/
void vb_quit(Client *c, gboolean force)
{
-#if 0 /* TODO don't quit on running downloads */
/* if not forced quit - don't quit if there are still running downloads */
if (!force && c->state.downloads) {
- vb_echo_force(c, VB_MSG_ERROR, TRUE, "Can't quit: there are running downloads");
+ vb_echo_force(c, MSG_ERROR, TRUE, "Can't quit: there are running downloads");
return;
}
-#endif
+
/* Don't run the quit synchronously, because this could lead to access of
* no more existing widget where some command response is written. */
g_idle_add((GSourceFunc)quit, c);
@@ -723,6 +729,22 @@ static void spawn_new_instance(const char *uri, gboolean embed)
}
/**
+ * Callback for the web contexts download-started signal.
+ */
+static void on_webctx_download_started(WebKitWebContext *webctx,
+ WebKitDownload *download, Client *c)
+{
+ g_signal_connect(download, "decide-destination", G_CALLBACK(on_webdownload_decide_destination), c);
+ g_signal_connect(download, "failed", G_CALLBACK(on_webdownload_failed), c);
+ g_signal_connect(download, "finished", G_CALLBACK(on_webdownload_finished), c);
+
+ c->state.downloads = g_list_append(c->state.downloads, download);
+
+ /* to reflect the correct download count */
+ vb_statusbar_update(c);
+}
+
+/**
* Callback for the web contexts initialize-web-extensions signal.
*/
static void on_webctx_init_web_extension(WebKitWebContext *webctx, gpointer data)
@@ -744,6 +766,168 @@ static void on_webctx_init_web_extension(WebKitWebContext *webctx, gpointer data
}
/**
+ * Callback for the webkit download decide destination signal.
+ * This signal is emitted after response is received to decide a destination
+ * URI for the download.
+ */
+static gboolean on_webdownload_decide_destination(WebKitDownload *download,
+ gchar *suggested_filename, Client *c)
+{
+ g_assert(download);
+ g_assert(suggested_filename);
+ g_assert(c);
+
+ char *path, *filename, *uri;
+ GString *expanded, *filepath;
+ const char *extension_dot;
+ int suffix;
+ gssize suffix_pos;
+
+ /* get the download path from settings */
+ path = GET_CHAR(c, "download-path");
+ g_assert(path);
+
+ /* expand any ~ or $VAR patterns in download path */
+ expanded = g_string_new(NULL);
+ util_parse_expansion(c, (const char**)&path, expanded, UTIL_EXP_TILDE|UTIL_EXP_DOLLAR, "");
+ g_string_append(expanded, path + 1);
+
+ /* for unnamed downloads set default filename */
+ filename = strlen(suggested_filename) ? suggested_filename : "vimb-download";
+
+ /* construct complete download filepath */
+ filepath = g_string_new(NULL);
+ g_string_printf(filepath, "%s%c%s", expanded->str, G_DIR_SEPARATOR, filename);
+
+ /* if the filepath exists already
+ * insert numerical suffix before file extension */
+ if (g_file_test(filepath->str, G_FILE_TEST_EXISTS)) {
+ suffix = 2;
+
+ /* position on .tar. (special case, extension with two dots),
+ * position on last dot (if any) otherwise */
+ if (!(extension_dot = strstr(filename, ".tar."))) {
+ extension_dot = strrchr(filename, '.');
+ }
+
+ /* the position to insert the suffix at */
+ if (extension_dot) {
+ suffix_pos = extension_dot - filename;
+ } else {
+ suffix_pos = strlen(filename);
+ }
+
+ /* construct a new complete download filepath and add the suffix before
+ * the filename extension, keep incrementing the suffix value as long
+ * as the filepath exists, stop on first unused filename. */
+ do {
+ g_string_printf(filepath, "%s%c%.*s_%i%s",
+ expanded->str, G_DIR_SEPARATOR,
+ (int)suffix_pos, filename,
+ suffix++, filename + suffix_pos);
+ } while (g_file_test(filepath->str, G_FILE_TEST_EXISTS));
+ }
+
+ /* build URI from filepath */
+ uri = g_filename_to_uri(filepath->str, NULL, NULL);
+ g_assert(uri);
+
+ /* configure download */
+ webkit_download_set_allow_overwrite(download, FALSE);
+ webkit_download_set_destination(download, uri);
+
+ /* cleanup */
+ g_string_free(expanded, TRUE);
+ g_string_free(filepath, TRUE);
+ g_free(uri);
+
+ return TRUE;
+}
+
+/**
+ * Callback for the webkit download failed signal.
+ * This signal is emitted when an error occurs during the download operation.
+ */
+static void on_webdownload_failed(WebKitDownload *download,
+ GError *error, Client *c)
+{
+ gchar *destination = NULL, *filename = NULL, *basename = NULL;
+
+ g_assert(download);
+ g_assert(error);
+ g_assert(c);
+
+ /* get the failed download's destination uri */
+ g_object_get(download, "destination", &destination, NULL);
+ g_assert(destination);
+
+ /* filename from uri */
+ if (destination) {
+ filename = g_filename_from_uri(destination, NULL, NULL);
+ g_free(destination);
+ }
+
+ /* basename from filename */
+ if (filename) {
+ basename = g_path_get_basename(filename);
+ g_free(filename);
+ }
+
+ /* report the error to the user */
+ if (basename) {
+ vb_echo(c, MSG_ERROR, FALSE, "Download of %s failed (%s)", basename, error->message);
+ g_free(basename);
+ }
+}
+
+/**
+ * Callback for the webkit download finished signal.
+ * This signal is emitted when download finishes successfully or due to an
+ * error. In case of errors “failed” signal is emitted before this one.
+ */
+static void on_webdownload_finished(WebKitDownload *download, Client *c)
+{
+ gchar *destination = NULL, *filename = NULL, *basename = NULL;
+
+ g_assert(download);
+ g_assert(c);
+
+ c->state.downloads = g_list_remove(c->state.downloads, download);
+
+ /* to reflect the correct download count */
+ vb_statusbar_update(c);
+
+ /* get the finished downloads destination uri */
+ g_object_get(download, "destination", &destination, NULL);
+ g_assert(destination);
+
+ /* filename from uri */
+ if (destination) {
+ filename = g_filename_from_uri(destination, NULL, NULL);
+ g_free(destination);
+ }
+
+ if (filename) {
+ /* basename from filename */
+ basename = g_path_get_basename(filename);
+
+ if (basename) {
+ /* Only report to the user if the downloaded file exists, so the
+ * download was successful. Otherwise, this is a failed download
+ * finished signal and it was reported to the user in
+ * on_webdownload_failed() already. */
+ if (g_file_test(filename, G_FILE_TEST_EXISTS)) {
+ vb_echo(c, MSG_NORMAL, FALSE, "Download of %s finished", basename);
+ }
+
+ g_free(basename);
+ }
+
+ g_free(filename);
+ }
+}
+
+/**
* Callback for the webview close signal.
*/
static void on_webview_close(WebKitWebView *webview, Client *c)
@@ -1168,6 +1352,8 @@ static WebKitWebView *webview_new(Client *c, WebKitWebView *webview)
NULL
);
+ g_signal_connect(webkit_web_context_get_default(), "download-started", G_CALLBACK(on_webctx_download_started), c);
+
/* Inject the user script file. */
if (g_file_get_contents(vb.files[FILES_SCRIPT], &js, NULL, NULL)) {
script = webkit_user_script_new(js,
diff --git a/src/main.h b/src/main.h
index c1e925e..a4c7d7f 100644
--- a/src/main.h
+++ b/src/main.h
@@ -213,7 +213,7 @@ struct Client {
struct Statusbar statusbar;
void *comp; /* pointer to data used in completion.c */
Mode *mode; /* current active browser mode */
- WebKitWebContext *webctx;
+ /* WebKitWebContext *webctx; */ /* not used atm, use webkit_web_context_get_default() instead */
GtkWidget *window, *input;
WebKitWebView *webview;
guint64 page_id; /* page id of the webview */
diff --git a/src/setting.c b/src/setting.c
index 373a9db..d8b0de0 100644
--- a/src/setting.c
+++ b/src/setting.c
@@ -140,6 +140,7 @@ void setting_init(Client *c)
setting_add(c, "fullscreen", TYPE_BOOLEAN, &off, fullscreen, 0, NULL);
i = 100;
setting_add(c, "default-zoom", TYPE_INTEGER, &i, default_zoom, 0, NULL);
+ setting_add(c, "download-path", TYPE_CHAR, &"~", NULL, 0, NULL);
/* initialize the shortcuts and set the default shortcuts */
shortcut_init(c);