aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/actions.c65
-rw-r--r--src/actions.h32
-rw-r--r--src/dillo.cc2
-rw-r--r--src/html.cc2
-rw-r--r--src/menu.cc121
-rw-r--r--src/menu.hh3
-rw-r--r--src/prefs.c1
-rw-r--r--src/prefs.h1
-rw-r--r--src/prefsparser.cc1
-rw-r--r--src/uicmd.cc4
-rw-r--r--src/uicmd.hh2
12 files changed, 220 insertions, 16 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index b2c7e28a..225a364a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -39,6 +39,8 @@ dillo_SOURCES = \
bw.c \
cookies.c \
cookies.h \
+ actions.c \
+ actions.h \
hsts.c \
hsts.h \
auth.c \
diff --git a/src/actions.c b/src/actions.c
new file mode 100644
index 00000000..7e197615
--- /dev/null
+++ b/src/actions.c
@@ -0,0 +1,65 @@
+/*
+ * File: actions.c
+ *
+ * Copyright (C) 2024 Rodrigo Arias Mallo <rodarima@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "actions.h"
+#include "msg.h"
+#include "../dlib/dlib.h"
+#include <errno.h>
+
+static Dlist *link_actions = NULL;
+
+void
+action_parse(char *line)
+{
+ char *label = strtok(line, ":");
+
+ if (label == NULL || strlen(label) == 0) {
+ MSG("Missing action label, ignoring '%s'\n", line);
+ return;
+ }
+
+ //MSG("Got label='%s'\n", label);
+
+ char *cmd = strtok(NULL, "");
+
+ if (cmd == NULL || strlen(cmd) == 0) {
+ MSG("Missing action command, ignoring '%s'\n", line);
+ return;
+ }
+
+ //MSG("Got action label='%s' cmd='%s'\n", label, cmd);
+
+ Action *action = dMalloc(sizeof(Action));
+ action->label = dStrdup(label);
+ action->cmd = dStrdup(cmd);
+
+ dList_append(link_actions, action);
+}
+
+void
+a_Actions_init(void)
+{
+ int n = dList_length(prefs.link_actions);
+
+ link_actions = dList_new(n);
+
+ for (int i = 0; i < n; i++) {
+ char *line = dList_nth_data(prefs.link_actions, i);
+ if (line)
+ action_parse(line);
+ }
+}
+
+Dlist *
+a_Actions_link_get(void)
+{
+ return link_actions;
+}
diff --git a/src/actions.h b/src/actions.h
new file mode 100644
index 00000000..b5319bea
--- /dev/null
+++ b/src/actions.h
@@ -0,0 +1,32 @@
+/*
+ * File: actions.h
+ *
+ * Copyright (C) 2024 Rodrigo Arias Mallo <rodarima@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef ACTIONS_H
+#define ACTIONS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include "dlib/dlib.h"
+
+typedef struct {
+ char *label;
+ char *cmd;
+} Action;
+
+void a_Actions_init(void);
+Dlist *a_Actions_link_get(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* ACTIONS_H*/
diff --git a/src/dillo.cc b/src/dillo.cc
index 2a65e12c..405f4c3e 100644
--- a/src/dillo.cc
+++ b/src/dillo.cc
@@ -57,6 +57,7 @@
#include "capi.h"
#include "dicache.h"
#include "cookies.h"
+#include "actions.h"
#include "hsts.h"
#include "domain.h"
#include "auth.h"
@@ -489,6 +490,7 @@ int main(int argc, char **argv)
a_Dicache_init();
a_Bw_init();
a_Cookies_init();
+ a_Actions_init();
a_Hsts_init(Paths::getPrefsFP(PATHS_HSTS_PRELOAD));
a_Auth_init();
a_UIcmd_init();
diff --git a/src/html.cc b/src/html.cc
index 1c5a08f4..69b495d6 100644
--- a/src/html.cc
+++ b/src/html.cc
@@ -780,7 +780,7 @@ bool DilloHtml::HtmlLinkReceiver::press (Widget *widget, int link, int img,
a_UIcmd_page_popup(bw, bw->num_page_bugs != 0, html->cssUrls);
ret = true;
} else {
- a_UIcmd_link_popup(bw, html->links->get(link));
+ a_UIcmd_link_popup(bw, html->links->get(link), html->page_url);
ret = true;
}
}
diff --git a/src/menu.cc b/src/menu.cc
index 7cea24a7..3cdc2f77 100644
--- a/src/menu.cc
+++ b/src/menu.cc
@@ -18,9 +18,12 @@
#include <FL/Fl.H>
#include <FL/Fl_Menu_Item.H>
+#include <unistd.h>
+#include <errno.h>
#include "lout/misc.hh" /* SimpleVector */
#include "msg.h"
#include "menu.hh"
+#include "actions.h"
#include "uicmd.hh"
#include "history.h"
#include "html.hh"
@@ -430,30 +433,123 @@ void a_Menu_page_popup(BrowserWindow *bw, const DilloUrl *url,
a_Timeout_add(0.0, Menu_popup_cb, (void*)&page_data);
}
-static Fl_Menu_Item link_menu[] = {
+static Fl_Menu_Item link_menu_[] = {
{"Open link in new tab", 0, Menu_open_url_nt_cb,0,0,0,0,0,0},
{"Open link in new window", 0, Menu_open_url_nw_cb,0,FL_MENU_DIVIDER,0,0,
0,0},
{"Bookmark this link", 0, Menu_add_bookmark_cb,0,0,0,0,0,0},
{"Copy link location", 0, Menu_copy_urlstr_cb,0,FL_MENU_DIVIDER,0,0,0,0},
- {"Save link as...", 0, Menu_save_link_cb,0,0,0,0,0,0},
+ {"Save link as...", 0, Menu_save_link_cb,0,FL_MENU_DIVIDER,0,0,0,0},
{0,0,0,0,0,0,0,0,0}
};
-static void Menu_set_link_menu_user_data(void *user_data)
+/* As we can only provide a pointer to the link menu items, we need to
+ * create an auxiliary structure to hold the current URL and the program
+ * that should run on each item. */
+struct link_menu_item {
+ const DilloUrl *url;
+ const DilloUrl *origin;
+ Action *action;
+};
+
+/**
+ * Open URL following a custom action
+ */
+static void Menu_open_url_action_cb(Fl_Widget*, void *user_data)
+{
+ /* Don't use popup_url because it is used for the image URL when coming from
+ * the image menu. We should get rid of the global variables and pass them
+ * via the user_data. */
+
+ struct link_menu_item *mitem = (struct link_menu_item *) user_data;
+ const DilloUrl *url = mitem->url;
+ const DilloUrl *origin = mitem->origin;
+ Action *action = mitem->action;
+
+ /* Set the environment variables */
+ setenv("url", URL_STR(url), 1);
+ setenv("origin", URL_STR(origin), 1);
+
+ if (fork() == 0) {
+ /* Child */
+ errno = 0;
+ int ret = system(action->cmd);
+ if (ret == -1) {
+ MSG("Cannot run '%s': %s\n", action->cmd, strerror(errno));
+ exit(1);
+ } else if (ret != 0) {
+ MSG("Command exited with '%d': %s\n", ret, action->cmd);
+ exit(1);
+ } else {
+ /* All good, terminate the child */
+ exit(0);
+ }
+ }
+}
+
+static Fl_Menu_Item *get_link_menu(void)
{
- int i;
+ static Fl_Menu_Item *link_menu = NULL;
+ static struct link_menu_item *link_menu_item = NULL;
+
+ /* Already initialized */
+ if (link_menu != NULL)
+ return link_menu;
- for (i = 0; link_menu[i].label(); i++)
- link_menu[i].user_data(user_data);
+ Dlist *actions = a_Actions_link_get();
+ int nactions = dList_length(actions);
+
+ /* Count static menu entries */
+ int nstatic = 0;
+ while (link_menu_[nstatic].text)
+ nstatic++;
+
+ int ntotal = nstatic + nactions;
+ link_menu = (Fl_Menu_Item *) calloc(ntotal + 1, sizeof(Fl_Menu_Item));
+ link_menu_item = (struct link_menu_item *) calloc(nactions, sizeof(struct link_menu_item));
+
+ /* Just copy the static entries */
+ for (int i = 0; i < nstatic; i++) {
+ memcpy(&link_menu[i], &link_menu_[i], sizeof(Fl_Menu_Item));
+ }
+
+ /* And append the dynamic ones */
+ for (int i = 0; i < nactions; i++) {
+ Action *action = (Action *) dList_nth_data(actions, i);
+ struct link_menu_item *mitem = &link_menu_item[i];
+ mitem->url = NULL; /* Not known yet */
+ mitem->action = action;
+
+ Fl_Menu_Item *item = &link_menu[nstatic + i];
+ item->text = action->label;
+ item->callback_ = Menu_open_url_action_cb;
+ item->user_data_ = mitem;
+ }
+
+ return link_menu;
+}
+
+static void Menu_set_link_menu_user_data(const DilloUrl *url, const DilloUrl *page_url)
+{
+ Fl_Menu_Item *link_menu = get_link_menu();
+ for (int i = 0; link_menu[i].label(); i++) {
+ if (link_menu[i].callback_ == Menu_open_url_action_cb) {
+ struct link_menu_item *mitem = (struct link_menu_item *) link_menu[i].user_data_;
+ /* Set the url and origin */
+ mitem->url = url;
+ mitem->origin = page_url;
+ } else {
+ link_menu[i].user_data_ = (void *) url;
+ }
+ }
}
/**
* Link popup menu (construction & popup)
*/
-void a_Menu_link_popup(BrowserWindow *bw, const DilloUrl *url)
+void a_Menu_link_popup(BrowserWindow *bw, const DilloUrl *url, const DilloUrl *page_url)
{
- static Menu_popup_data_t link_data = {"Link menu", NULL, link_menu};
+ static Menu_popup_data_t link_data = {"Link menu", NULL, NULL};
popup_x = Fl::event_x();
popup_y = Fl::event_y();
@@ -461,7 +557,10 @@ void a_Menu_link_popup(BrowserWindow *bw, const DilloUrl *url)
a_Url_free(popup_url);
popup_url = a_Url_dup(url);
- Menu_set_link_menu_user_data(popup_url);
+ Fl_Menu_Item *link_menu = get_link_menu();
+ link_data.menu = link_menu;
+
+ Menu_set_link_menu_user_data(popup_url, page_url);
a_Timeout_add(0.0, Menu_popup_cb, (void*)&link_data);
}
@@ -484,7 +583,7 @@ void a_Menu_image_popup(BrowserWindow *bw, const DilloUrl *url,
{"Bookmark this image", 0, Menu_add_bookmark_cb,0,0,0,0,0,0},
{"Copy image location", 0,Menu_copy_urlstr_cb,0,FL_MENU_DIVIDER,0,0,0,0},
{"Save image as...", 0, Menu_save_link_cb, 0, FL_MENU_DIVIDER,0,0,0,0},
- {"Link menu", 0, Menu_nop_cb, link_menu, FL_SUBMENU_POINTER,0,0,0,0},
+ {"Link menu", 0, Menu_nop_cb, get_link_menu(), FL_SUBMENU_POINTER,0,0,0,0},
{0,0,0,0,0,0,0,0,0}
};
static Menu_popup_data_t image_data = {"Image menu", NULL, pm};
@@ -517,7 +616,7 @@ void a_Menu_image_popup(BrowserWindow *bw, const DilloUrl *url,
if (link_url) {
pm[7].activate();
- Menu_set_link_menu_user_data(popup_link_url);
+ Menu_set_link_menu_user_data(popup_link_url, popup_page_url);
} else {
pm[7].deactivate();
}
diff --git a/src/menu.hh b/src/menu.hh
index a8170e89..60d230a4 100644
--- a/src/menu.hh
+++ b/src/menu.hh
@@ -9,7 +9,8 @@ extern "C" {
void a_Menu_page_popup(BrowserWindow *bw, const DilloUrl *url,
bool_t has_bugs, void *v_cssUrls);
-void a_Menu_link_popup(BrowserWindow *bw, const DilloUrl *url);
+void a_Menu_link_popup(BrowserWindow *bw, const DilloUrl *url,
+ const DilloUrl *page_url);
void a_Menu_image_popup(BrowserWindow *bw, const DilloUrl *url,
bool_t loaded_img, DilloUrl *page_url,
DilloUrl *link_url);
diff --git a/src/prefs.c b/src/prefs.c
index 4a68e4c9..a57c792c 100644
--- a/src/prefs.c
+++ b/src/prefs.c
@@ -85,6 +85,7 @@ void a_Prefs_init(void)
prefs.scroll_switches_tabs = TRUE;
prefs.scroll_switches_tabs_reverse = FALSE;
prefs.no_proxy = dStrdup(PREFS_NO_PROXY);
+ prefs.link_actions = dList_new(16);
prefs.panel_size = P_medium;
prefs.parse_embedded_css=TRUE;
prefs.save_dir = dStrdup(PREFS_SAVE_DIR);
diff --git a/src/prefs.h b/src/prefs.h
index 03bc1e56..0027e53c 100644
--- a/src/prefs.h
+++ b/src/prefs.h
@@ -124,6 +124,7 @@ typedef struct {
int penalty_hyphen, penalty_hyphen_2;
int penalty_em_dash_left, penalty_em_dash_right, penalty_em_dash_right_2;
int stretchability_factor;
+ Dlist *link_actions;
} DilloPrefs;
/** Global Data */
diff --git a/src/prefsparser.cc b/src/prefsparser.cc
index ee1d9d02..b5ab1b17 100644
--- a/src/prefsparser.cc
+++ b/src/prefsparser.cc
@@ -248,6 +248,7 @@ void PrefsParser::parse(FILE *fp)
PREFS_FRACTION_100, 0 },
{ "stretchability_factor", &prefs.stretchability_factor,
PREFS_FRACTION_100, 0 },
+ { "link_action", &prefs.link_actions, PREFS_STRINGS, 0 },
{ "zoom_factor", &prefs.zoom_factor, PREFS_DOUBLE, 0 }
};
// changing the LC_NUMERIC locale (temporarily) to C
diff --git a/src/uicmd.cc b/src/uicmd.cc
index 18ac2ff1..273bcb9f 100644
--- a/src/uicmd.cc
+++ b/src/uicmd.cc
@@ -1269,9 +1269,9 @@ void a_UIcmd_page_popup(void *vbw, bool_t has_bugs, void *v_cssUrls)
/*
* Popup the link menu
*/
-void a_UIcmd_link_popup(void *vbw, const DilloUrl *url)
+void a_UIcmd_link_popup(void *vbw, const DilloUrl *url, const DilloUrl *page_url)
{
- a_Menu_link_popup((BrowserWindow*)vbw, url);
+ a_Menu_link_popup((BrowserWindow*)vbw, url, page_url);
}
/*
diff --git a/src/uicmd.hh b/src/uicmd.hh
index f75d9a48..fe72486a 100644
--- a/src/uicmd.hh
+++ b/src/uicmd.hh
@@ -59,7 +59,7 @@ void a_UIcmd_findbar_toggle(BrowserWindow *bw, int on);
void a_UIcmd_focus_main_area(BrowserWindow *bw);
void a_UIcmd_focus_location(void *vbw);
void a_UIcmd_page_popup(void *vbw, bool_t has_bugs, void *v_cssUrls);
-void a_UIcmd_link_popup(void *vbw, const DilloUrl *url);
+void a_UIcmd_link_popup(void *vbw, const DilloUrl *url, const DilloUrl *page_url);
void a_UIcmd_image_popup(void *vbw, const DilloUrl *url, bool_t loaded_img,
DilloUrl *page_url, DilloUrl *link_url);
void a_UIcmd_form_popup(void *vbw, const DilloUrl *url, void *vform,