From 2f2a3918ee2d0a989b6099ec9ee484cdf3b7f04b Mon Sep 17 00:00:00 2001 From: Carlos Maddela Date: Thu, 5 Jan 2017 19:13:13 +1100 Subject: [PATCH] Resurrect old code to support opening URLs in a browser. --- .../27-allow-opening-in-browser-again.patch | 486 ++++++++++++++++++ debian/patches/series | 1 + 2 files changed, 487 insertions(+) create mode 100644 debian/patches/27-allow-opening-in-browser-again.patch diff --git a/debian/patches/27-allow-opening-in-browser-again.patch b/debian/patches/27-allow-opening-in-browser-again.patch new file mode 100644 index 0000000..cc9b782 --- /dev/null +++ b/debian/patches/27-allow-opening-in-browser-again.patch @@ -0,0 +1,486 @@ +From: Carlos Maddela +Date: Thu, 5 Jan 2017 19:11:38 +1100 +Subject: Resurrect old code to support opening URLs in a browser. + +Description: Resurrect old code to support opening URLs in a browser. +Author: Carlos Maddela +Origin: vendor +Forwarded: not-needed +Last-Update: 2016-12-21 +--- +This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ +--- + closure.c | 2 + + dvdisaster.h | 7 + + help-dialogs.c | 3 +- + show-html.c | 402 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 413 insertions(+), 1 deletion(-) + create mode 100644 show-html.c + +diff --git a/closure.c b/closure.c +index 0e2f889..632c103 100644 +--- a/closure.c ++++ b/closure.c +@@ -467,6 +467,7 @@ void InitClosure() + Closure->deviceNames = g_ptr_array_new(); + Closure->deviceNodes = g_ptr_array_new(); + Closure->viewer = g_strdup("xdg-open"); ++ Closure->browser = g_strdup("xdg-open"); + Closure->methodList = g_ptr_array_new(); + Closure->methodName = g_strdup("RS01"); + Closure->dDumpDir = g_strdup(Closure->homeDir); +@@ -598,6 +599,7 @@ void FreeClosure() + cond_free(Closure->binDir); + cond_free(Closure->docDir); + cond_free(Closure->viewer); ++ cond_free(Closure->browser); + cond_free(Closure->errorTitle); + cond_free(Closure->simulateCD); + cond_free(Closure->dDumpDir); +diff --git a/dvdisaster.h b/dvdisaster.h +index db2031e..22eab5a 100644 +--- a/dvdisaster.h ++++ b/dvdisaster.h +@@ -213,6 +213,7 @@ typedef struct _GlobalClosure + char *binDir; /* place where the binary resides */ + char *docDir; /* place where our documentation resides */ + char *viewer; /* Name of preferred PDF viewer */ ++ char *browser; /* Name of preferred browser */ + + GMutex progressLock; /* A mutex protected the stuff below */ + char bs[256]; /* A string of 255 backspace characters */ +@@ -1299,6 +1300,12 @@ int ProbeAltiVec(void); + void ShowPDF(char*); + + /*** ++ *** show-html.c ++ ***/ ++ ++void ShowHTML(char*); ++ ++/*** + *** smart-lec.c + ***/ + +diff --git a/help-dialogs.c b/help-dialogs.c +index 5065e76..3874463 100644 +--- a/help-dialogs.c ++++ b/help-dialogs.c +@@ -599,7 +599,8 @@ static gint about_cb(GtkWidget *widget, GdkEvent *event, gpointer data) + { case GDK_BUTTON_PRESS: + if(!inside) return FALSE; /* Defect in certain Gtk versions? */ + if(!strcmp(label,"GPL")) ShowGPL(); +- else if(!strcmp(label,"MODIFYING")) show_modifying(); ++ else if(!strcmp(label,"MODIFYING")) show_modifying(); ++ else if(strlen(label) > 4 && !strncmp(label, "http", 4)) ShowHTML(g_strdup(label)); + else ShowPDF(g_strdup(label)); + break; + case GDK_ENTER_NOTIFY: +diff --git a/show-html.c b/show-html.c +new file mode 100644 +index 0000000..608e8ec +--- /dev/null ++++ b/show-html.c +@@ -0,0 +1,402 @@ ++/* dvdisaster: Additional error correction for optical media. ++ * Copyright (C) 2004-2012 Carsten Gnoerlich. ++ * Project home page: http://www.dvdisaster.com ++ * Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org ++ * ++ * 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 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA, ++ * or direct your browser at http://www.gnu.org. ++ */ ++ ++#include "dvdisaster.h" ++ ++#if defined(SYS_LINUX) || defined(SYS_FREEBSD) || defined(SYS_NETBSD) ++#include ++#endif ++ ++#ifdef SYS_MINGW ++#include "windows.h" ++#include "shellapi.h" ++#endif ++ ++/*** ++ *** Ask user to specify his browser ++ ***/ ++ ++#if defined(SYS_LINUX) || defined(SYS_FREEBSD) || defined(SYS_NETBSD) ++ ++#define SEARCH_BUTTON 1 ++ ++typedef struct ++{ GtkWidget *dialog; ++ GtkWidget *entry; ++ GtkWidget *search; ++ GtkWidget *filesel; ++ GtkWidget *fileok; ++ GtkWidget *filecancel; ++ char *url; ++} browser_dialog_info; ++ ++static void response_cb(GtkWidget *widget, int response, gpointer data) ++{ browser_dialog_info *bdi = (browser_dialog_info*)data; ++ ++ switch(response) ++ { case GTK_RESPONSE_ACCEPT: ++ if(Closure->browser) g_free(Closure->browser); ++ Closure->browser = g_strdup(gtk_entry_get_text(GTK_ENTRY(bdi->entry))); ++ ShowHTML(bdi->url); ++ break; ++ ++ case GTK_RESPONSE_REJECT: ++ if(bdi->url) g_free(bdi->url); ++ break; ++ } ++ gtk_widget_destroy(widget); ++ if(bdi->filesel) ++ gtk_widget_destroy(bdi->filesel); ++ g_free(bdi); ++} ++ ++static void search_cb(GtkWidget *widget, gpointer data) ++{ browser_dialog_info *bdi = (browser_dialog_info*)data; ++ ++ if(widget == bdi->search) ++ { bdi->filesel = gtk_file_selection_new(_utf("windowtitle|Choose a browser")); ++ bdi->fileok = GTK_FILE_SELECTION(bdi->filesel)->ok_button; ++ bdi->filecancel = GTK_FILE_SELECTION(bdi->filesel)->cancel_button; ++ ReverseCancelOK(GTK_DIALOG(bdi->filesel)); ++ gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(bdi->filesel)); ++ g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(bdi->filesel)->ok_button), "clicked", ++ G_CALLBACK(search_cb), bdi); ++ ++ g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(bdi->filesel)->cancel_button), "clicked", ++ G_CALLBACK(search_cb), bdi); ++ ++ gtk_widget_show(bdi->filesel); ++ } ++ ++ if(widget == bdi->fileok) ++ { ++ if(Closure->browser) g_free(Closure->browser); ++ Closure->browser = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(bdi->filesel))); ++ ShowHTML(bdi->url); ++ gtk_widget_destroy(bdi->filesel); ++ gtk_widget_destroy(bdi->dialog); ++ g_free(bdi); ++ return; ++ } ++ ++ if(widget == bdi->filecancel) ++ { gtk_widget_destroy(bdi->filesel); ++ bdi->filesel = NULL; ++ } ++} ++ ++static void browser_dialog(char *url) ++{ GtkWidget *dialog, *vbox, *hbox, *label, *entry, *button; ++ browser_dialog_info *bdi = g_malloc0(sizeof(browser_dialog_info)); ++ ++ /* Create the dialog */ ++ ++ dialog = gtk_dialog_new_with_buttons(_utf("windowtitle|Browser required"), ++ Closure->window, GTK_DIALOG_DESTROY_WITH_PARENT, ++ GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, ++ GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL); ++ bdi->dialog = dialog; ++ if(url) ++ { bdi->url = g_strdup(url); ++ } ++ ++ vbox = gtk_vbox_new(FALSE, 0); ++ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox, FALSE, FALSE, 0); ++ gtk_container_set_border_width(GTK_CONTAINER(vbox), 10); ++ ++ /* Insert the contents */ ++ ++ label = gtk_label_new(NULL); ++ gtk_label_set_markup(GTK_LABEL(label), _utf("Could not find a suitable browser.\n\n" ++ "Which browser would you like to use\n" ++ "for reading the online documentation?\n\n" ++ "Please enter its name (e.g. mozilla) or\n" ++ "use the \"Search\" button for a file dialog.\n")), ++ gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 10); ++ ++ hbox = gtk_hbox_new(FALSE, 0); ++ gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 10); ++ ++ bdi->entry = entry = gtk_entry_new(); ++ gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 10); ++ ++ bdi->search = button = gtk_button_new_with_label(_utf("Search")); ++ g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(search_cb), bdi); ++ gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 10); ++ ++ /* Show it */ ++ ++ g_signal_connect(dialog, "response", G_CALLBACK(response_cb), bdi); ++ ++ gtk_widget_show_all(dialog); ++} ++#endif /* SYS_ unix-like */ ++ ++/*** ++ *** Show the manual in an external browser ++ ***/ ++ ++/* ++ * Check the child processes exit status ++ * to find whether the browser could be invoked. ++ */ ++ ++typedef struct ++{ pid_t pid; ++ char *url; ++ GtkWidget *msg; ++ int seconds; ++} browser_info; ++ ++ ++static void msg_destroy_cb(GtkWidget *widget, gpointer data) ++{ browser_info *bi = (browser_info*)data; ++ ++ bi->msg = NULL; ++} ++ ++#if defined(SYS_LINUX) || defined(SYS_FREEBSD) || defined(SYS_NETBSD) ++ ++/* ++ * The following list of browsers and html wrappers ++ * will be tried one at a time until one entry succeeds by: ++ * - returning zero ++ * - not returning within 60 seconds ++ */ ++ ++static int browser_index; ++static void try_browser(browser_info*); ++ ++static char *browsers[] = ++{ "user-selection", ++ "xdg-open", ++ "gnome-open", ++ "htmlview", ++ "firefox", ++ "mozilla", ++ "konqueror", ++ "epiphany", ++ "opera", ++ "/Applications/Safari.app/Contents/MacOS/Safari", /* better way to do this? */ ++ NULL ++}; ++ ++static gboolean browser_timeout_func(gpointer data) ++{ browser_info *bi = (browser_info*)data; ++ int status; ++ ++ waitpid(bi->pid, &status, WNOHANG); ++ ++ /* At least mozilla returns random values under FreeBSD on success, ++ so we can't rely on the return value exept our own 110 one. */ ++ ++ if(WIFEXITED(status)) ++ { ++ switch(WEXITSTATUS(status)) ++ { case 110: /* browser did not execute */ ++ browser_index++; ++ if(!browsers[browser_index]) /* all browsers from the list failed */ ++ { browser_dialog(bi->url); ++ ++ if(bi->msg) ++ gtk_widget_destroy(bi->msg); ++ if(bi->url) ++ g_free(bi->url); ++ g_free(bi); ++ } ++ else /* try next browser from list */ ++ { bi->seconds = 0; ++ try_browser(bi); ++ } ++ return FALSE; ++ ++ case 0: /* browser assumed to be successful */ ++ default: ++ if(bi->msg) ++ gtk_widget_destroy(bi->msg); ++ if(bi->url) ++ g_free(bi->url); ++ g_free(bi); ++ return FALSE; ++ } ++ } ++ ++ bi->seconds++; ++ if(bi->seconds == 10 && bi->msg) ++ { gtk_widget_destroy(bi->msg); ++ bi->msg = NULL; ++ } ++ ++ return bi->seconds > 60 ? FALSE : TRUE; ++} ++#endif /* SYS_ unix-like */ ++ ++#ifdef SYS_MINGW ++static gboolean browser_timeout_func(gpointer data) ++{ browser_info *bi = (browser_info*)data; ++ ++ bi->seconds++; ++ ++ if(bi->seconds >= 10) ++ { if(bi->msg) ++ { gtk_widget_destroy(bi->msg); ++ bi->msg = NULL; ++ } ++ if(bi->url) g_free(bi->url); ++ g_free(bi); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++#endif /* SYS_MINGW */ ++ ++/* ++ * Invoke the browser ++ */ ++ ++#if defined(SYS_LINUX) || defined(SYS_FREEBSD) || defined(SYS_NETBSD) ++static void try_browser(browser_info *bi) ++{ pid_t pid; ++ ++ bi->pid = pid = fork(); ++ ++ if(pid == -1) ++ { printf("fork failed\n"); ++ return; ++ } ++ ++ /* make the parent remember and wait() for the browser */ ++ ++ if(pid > 0) ++ { g_timeout_add(1000, browser_timeout_func, (gpointer)bi); ++ ++ if(browser_index) ++ { g_free(Closure->browser); ++ Closure->browser = g_strdup(browsers[browser_index]); ++ } ++ } ++ ++ /* try calling the browser */ ++ ++ if(pid == 0) ++ { char *argv[10]; ++ int argc = 0; ++ ++ argv[argc++] = browser_index ? browsers[browser_index] : Closure->browser; ++ argv[argc++] = bi->url; ++ argv[argc++] = NULL; ++ execvp(argv[0], argv); ++ ++ _exit(110); /* couldn't execute */ ++ } ++} ++#endif /* SYS_ unix-like */ ++ ++ ++void ShowHTML(char *target) ++{ browser_info *bi = g_malloc0(sizeof(browser_info)); ++ guint64 ignore; ++ const char *lang; ++ char *path = NULL; ++ int http_url; ++ ++ /* If no target is given, select between translations of the manual. */ ++ ++ if(!target) target = g_strdup("index.html"); ++ ++ http_url = strlen(target) > 4 && !strncmp(target, "http", 4); ++ ++ if(!http_url && !strchr(target, '/')) /* create full path */ ++ { ++ if(!Closure->docDir) ++ { ++ CreateMessage(_("Documentation not installed."), GTK_MESSAGE_ERROR); ++ g_free(bi); ++ return; ++ } ++ ++ lang = g_getenv("LANG"); ++ ++ if(lang) ++ { if(!strncmp(lang, "ru", 2)) ++#ifdef SYS_MINGW ++ path = g_strdup_printf("%s\\ru\\%s",Closure->docDir,target); ++#else ++ path = g_strdup_printf("%s/ru/%s",Closure->docDir,target); ++#endif ++ else if(!strncmp(lang, "de", 2)) ++#ifdef SYS_MINGW ++ path = g_strdup_printf("%s\\de\\%s",Closure->docDir,target); ++#else ++ path = g_strdup_printf("%s/de/%s",Closure->docDir,target); ++#endif ++ } ++ ++ if(!path) ++ { ++#ifdef SYS_MINGW ++ path = g_strdup_printf("%s\\en\\%s",Closure->docDir,target); ++#else ++ path = g_strdup_printf("%s/en/%s",Closure->docDir,target); ++#endif ++ } ++ ++#ifdef SYS_MINGW ++ if(!LargeStat(path, &ignore)) ++ { ++ g_free(path); /* the local dir is Windows specific */ ++ path = g_strdup_printf("%s\\local\\%s",Closure->docDir,target); ++ } ++#endif ++ g_free(target); ++ bi->url = path; ++ } ++ else bi->url = target; ++ ++ if(!http_url && !LargeStat(bi->url, &ignore)) ++ { ++ CreateMessage(_("Documentation file\n%s\nnot found.\n"), GTK_MESSAGE_ERROR, bi->url); ++ g_free(bi); ++ g_free(bi->url); ++ return; ++ } ++ ++ /* Lock the help button and show a message for 10 seconds. */ ++ ++ TimedInsensitive(Closure->helpButton, 10000); ++ bi->msg = CreateMessage(_("Please hang on until the browser comes up!"), GTK_MESSAGE_INFO); ++ g_signal_connect(G_OBJECT(bi->msg), "destroy", G_CALLBACK(msg_destroy_cb), bi); ++ ++#ifdef SYS_MINGW ++ /* Okay, Billy wins big time here ;-) */ ++ ++ ShellExecute(NULL, "open", bi->url, NULL, NULL, SW_SHOWNORMAL); ++ g_timeout_add(1000, browser_timeout_func, (gpointer)bi); ++#endif ++ ++#if defined(SYS_LINUX) || defined(SYS_FREEBSD) || defined(SYS_NETBSD) ++ /* Try the first browser */ ++ ++ browser_index = 0; ++ try_browser(bi); ++#endif ++} diff --git a/debian/patches/series b/debian/patches/series index efb177c..92f39c4 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -18,3 +18,4 @@ 24-show-gpl3-license.patch 25-fix-man-pages.patch 26-fix-display-of-manual.pdf.patch +27-allow-opening-in-browser-again.patch