r474 - in trunk: . examples/duke3d meta meta/xdg-utils

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Fri Jan 25 11:01:23 EST 2008


Author: icculus
Date: 2008-01-25 11:01:19 -0500 (Fri, 25 Jan 2008)
New Revision: 474

Added:
   trunk/meta/
   trunk/meta/xdg-utils/
   trunk/meta/xdg-utils/xdg-open
Modified:
   trunk/examples/duke3d/make.sh
   trunk/mojosetup.c
   trunk/platform_unix.c
Log:
Screw it, just run a shipped copy of xdg-open if the system doesn't have it.


Modified: trunk/examples/duke3d/make.sh
===================================================================
--- trunk/examples/duke3d/make.sh	2008-01-25 11:09:16 UTC (rev 473)
+++ trunk/examples/duke3d/make.sh	2008-01-25 16:01:19 UTC (rev 474)
@@ -103,6 +103,12 @@
 cp data/* image/data/
 cp meta/* image/meta/
 
+# Need these scripts to do things like install menu items, etc, on Unix.
+if [ "$OSTYPE" = "Linux" ]; then
+    mkdir image/meta/xdg-utils
+    cp -av ../../meta/xdg-utils/* image/meta/xdg-utils/
+fi
+
 # Make a .zip archive of the Base Archive dirs and nuke the originals...
 cd image
 zip -9r ../pdata.zip *

Added: trunk/meta/xdg-utils/xdg-open
===================================================================
--- trunk/meta/xdg-utils/xdg-open	                        (rev 0)
+++ trunk/meta/xdg-utils/xdg-open	2008-01-25 16:01:19 UTC (rev 474)
@@ -0,0 +1,436 @@
+#!/bin/sh
+#---------------------------------------------
+#   xdg-open
+#
+#   Utility script to open a URL in the registered default application.
+#
+#   Refer to the usage() function below for usage.
+#
+#   Copyright 2006, Kevin Krammer <kevin.krammer at gmx.at>
+#   Copyright 2006, Jeremy White <jwhite at codeweavers.com>
+#
+#   LICENSE:
+#
+#   Permission is hereby granted, free of charge, to any person obtaining a
+#   copy of this software and associated documentation files (the "Software"),
+#   to deal in the Software without restriction, including without limitation
+#   the rights to use, copy, modify, merge, publish, distribute, sublicense,
+#   and/or sell copies of the Software, and to permit persons to whom the
+#   Software is furnished to do so, subject to the following conditions:
+#
+#   The above copyright notice and this permission notice shall be included
+#   in all copies or substantial portions of the Software.
+#
+#   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+#   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+#   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+#   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+#   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+#   OTHER DEALINGS IN THE SOFTWARE.
+#
+#---------------------------------------------
+
+manualpage()
+{
+cat << _MANUALPAGE
+Name
+
+xdg-open - opens a file or URL in the user's preferred application
+
+Synopsis
+
+xdg-open { file | URL }
+
+xdg-open { --help | --manual | --version }
+
+Description
+
+xdg-open opens a file or URL in the user's preferred application. If a URL is
+provided the URL will be opened in the user's preferred web browser. If a file
+is provided the file will be opened in the preferred application for files of
+that type. xdg-open supports file, ftp, http and https URLs.
+
+xdg-open is for use inside a desktop session only. It is not recommended to use
+xdg-open as root.
+
+Options
+
+--help
+    Show command synopsis.
+--manual
+    Show this manualpage.
+--version
+    Show the xdg-utils version information.
+
+Exit Codes
+
+An exit code of 0 indicates success while a non-zero exit code indicates
+failure. The following failure codes can be returned:
+
+1
+    Error in command line syntax.
+2
+    One of the files passed on the command line did not exist.
+3
+    A required tool could not be found.
+4
+    The action failed.
+
+Examples
+
+xdg-open 'http://www.freedesktop.org/'
+
+Opens the Freedesktop.org website in the user's default browser
+
+xdg-open /tmp/foobar.png
+
+Opens the PNG image file /tmp/foobar.png in the user's default image viewing
+application.
+
+_MANUALPAGE
+}
+
+usage()
+{
+cat << _USAGE
+xdg-open - opens a file or URL in the user's preferred application
+
+Synopsis
+
+xdg-open { file | URL }
+
+xdg-open { --help | --manual | --version }
+
+_USAGE
+}
+
+#@xdg-utils-common@
+
+#----------------------------------------------------------------------------
+#   Common utility functions included in all XDG wrapper scripts
+#----------------------------------------------------------------------------
+
+DEBUG()
+{
+  [ -z "${XDG_UTILS_DEBUG_LEVEL}" ] && return 0;
+  [ ${XDG_UTILS_DEBUG_LEVEL} -lt $1 ] && return 0;
+  shift
+  echo "$@" >&2
+}
+
+#-------------------------------------------------------------
+# Exit script on successfully completing the desired operation
+
+exit_success()
+{
+    if [ $# -gt 0 ]; then
+        echo "$@"
+        echo
+    fi
+
+    exit 0
+}
+
+
+#-----------------------------------------
+# Exit script on malformed arguments, not enough arguments
+# or missing required option.
+# prints usage information
+
+exit_failure_syntax()
+{
+    if [ $# -gt 0 ]; then
+        echo "xdg-open: $@" >&2
+        echo "Try 'xdg-open --help' for more information." >&2
+    else
+        usage
+        echo "Use 'man xdg-open' or 'xdg-open --manual' for additional info."
+    fi
+
+    exit 1
+}
+
+#-------------------------------------------------------------
+# Exit script on missing file specified on command line
+
+exit_failure_file_missing()
+{
+    if [ $# -gt 0 ]; then
+        echo "xdg-open: $@" >&2
+    fi
+
+    exit 2
+}
+
+#-------------------------------------------------------------
+# Exit script on failure to locate necessary tool applications
+
+exit_failure_operation_impossible()
+{
+    if [ $# -gt 0 ]; then
+        echo "xdg-open: $@" >&2
+    fi
+
+    exit 3
+}
+
+#-------------------------------------------------------------
+# Exit script on failure returned by a tool application
+
+exit_failure_operation_failed()
+{
+    if [ $# -gt 0 ]; then
+        echo "xdg-open: $@" >&2
+    fi
+
+    exit 4
+}
+
+#------------------------------------------------------------
+# Exit script on insufficient permission to read a specified file
+
+exit_failure_file_permission_read()
+{
+    if [ $# -gt 0 ]; then
+        echo "xdg-open: $@" >&2
+    fi
+
+    exit 5
+}
+
+#------------------------------------------------------------
+# Exit script on insufficient permission to read a specified file
+
+exit_failure_file_permission_write()
+{
+    if [ $# -gt 0 ]; then
+        echo "xdg-open: $@" >&2
+    fi
+
+    exit 6
+}
+
+check_input_file()
+{
+    if [ ! -e "$1" ]; then
+        exit_failure_file_missing "file '$1' does not exist"
+    fi
+    if [ ! -r "$1" ]; then
+        exit_failure_file_permission_read "no permission to read file '$1'"
+    fi
+}
+
+check_vendor_prefix()
+{
+    file_label="$2"
+    [ -n "$file_label" ] || file_label="filename"
+    file=`basename "$1"`
+    case "$file" in
+       [a-zA-Z]*-*)
+         return
+         ;;
+    esac
+
+    echo "xdg-open: $file_label '$file' does not have a proper vendor prefix" >&2
+    echo 'A vendor prefix consists of alpha characters ([a-zA-Z]) and is terminated' >&2
+    echo 'with a dash ("-"). An example '"$file_label"' is '"'example-$file'" >&2
+    echo "Use --novendor to override or 'xdg-open --manual' for additional info." >&2
+    exit 1
+}
+
+check_output_file()
+{
+    # if the file exists, check if it is writeable
+    # if it does not exists, check if we are allowed to write on the directory
+    if [ -e "$1" ]; then
+        if [ ! -w "$1" ]; then
+            exit_failure_file_permission_write "no permission to write to file '$1'"
+        fi
+    else
+        DIR=`dirname "$1"`
+        if [ ! -w "$DIR" -o ! -x "$DIR" ]; then
+            exit_failure_file_permission_write "no permission to create file '$1'"
+        fi
+    fi
+}
+
+#----------------------------------------
+# Checks for shared commands, e.g. --help
+
+check_common_commands()
+{
+    while [ $# -gt 0 ] ; do
+        parm="$1"
+        shift
+
+        case "$parm" in
+            --help)
+            usage
+            echo "Use 'man xdg-open' or 'xdg-open --manual' for additional info."
+            exit_success
+            ;;
+
+            --manual)
+            manualpage
+            exit_success
+            ;;
+
+            --version)
+            echo "xdg-open 1.0.1"
+            exit_success
+            ;;
+        esac
+    done
+}
+
+check_common_commands "$@"
+
+[ -z "${XDG_UTILS_DEBUG_LEVEL}" ] && unset XDG_UTILS_DEBUG_LEVEL;
+if [ ${XDG_UTILS_DEBUG_LEVEL-0} -lt 1 ]; then
+    # Be silent
+    xdg_redirect_output=" > /dev/null 2> /dev/null"
+else
+    # All output to stderr
+    xdg_redirect_output=" >&2"
+fi
+
+#--------------------------------------
+# Checks for known desktop environments
+# set variable DE to the desktop environments name, lowercase
+
+detectDE()
+{
+    if [ x"$KDE_FULL_SESSION" = x"true" ]; then DE=kde;
+    elif [ x"$GNOME_DESKTOP_SESSION_ID" != x"" ]; then DE=gnome;
+    elif xprop -root _DT_SAVE_MODE | grep ' = \"xfce4\"$' >/dev/null 2>&1; then DE=xfce;
+    fi
+}
+
+#----------------------------------------------------------------------------
+# kfmclient exec/openURL can give bogus exit value in KDE <= 3.5.4
+# It also always returns 1 in KDE 3.4 and earlier
+# Simply return 0 in such case
+
+kfmclient_fix_exit_code()
+{
+    version=`kde-config --version 2>/dev/null | grep KDE`
+    major=`echo $version | sed 's/KDE: \([0-9]\).*/\1/'`
+    minor=`echo $version | sed 's/KDE: [0-9]*\.\([0-9]\).*/\1/'`
+    release=`echo $version | sed 's/KDE: [0-9]*\.[0-9]*\.\([0-9]\).*/\1/'`
+    test "$major" -gt 3 && return $1
+    test "$minor" -gt 5 && return $1
+    test "$release" -gt 4 && return $1
+    return 0
+}
+
+open_kde()
+{
+    kfmclient exec "$1"
+    kfmclient_fix_exit_code $?
+
+    if [ $? -eq 0 ]; then
+        exit_success
+    else
+        exit_failure_operation_failed
+    fi
+}
+
+open_gnome()
+{
+    gnome-open "$1"
+
+    if [ $? -eq 0 ]; then
+        exit_success
+    else
+        exit_failure_operation_failed
+    fi
+}
+
+open_xfce()
+{
+    exo-open "$1"
+
+    if [ $? -eq 0 ]; then
+        exit_success
+    else
+        exit_failure_operation_failed
+    fi
+}
+
+open_generic()
+{
+    IFS=":"
+    for browser in $BROWSER; do
+        if [ x"$browser" != x"" ]; then
+
+            browser_with_arg=`echo "$browser" | sed s#%s#"$1"#`
+
+            if [ x"$browser_with_arg" = x"$browser" ]; then "$browser" "$1";
+            else $browser_with_arg;
+            fi
+
+            if [ $? -eq 0 ]; then exit_success;
+            fi
+        fi
+    done
+
+    exit_failure_operation_impossible "no method available for opening '$1'"
+}
+
+[ x"$1" != x"" ] || exit_failure_syntax
+
+url=
+while [ $# -gt 0 ] ; do
+    parm="$1"
+    shift
+
+    case "$parm" in
+      -*)
+        exit_failure_syntax "unexpected option '$parm'"
+        ;;
+
+      *)
+        if [ -n "$url" ] ; then
+            exit_failure_syntax "unexpected argument '$parm'"
+        fi
+        url="$parm"
+        ;;
+    esac
+done
+
+if [ -z "${url}" ] ; then
+    exit_failure_syntax "file or URL argument missing"
+fi
+
+detectDE
+
+if [ x"$DE" = x"" ]; then
+    # if BROWSER variable is not set, check some well known browsers instead
+    if [ x"$BROWSER" = x"" ]; then
+        BROWSER=firefox:mozilla:netscape
+    fi
+    DE=generic
+fi
+
+case "$DE" in
+    kde)
+    open_kde "$url"
+    ;;
+
+    gnome)
+    open_gnome "$url"
+    ;;
+
+    xfce)
+    open_xfce "$url"
+    ;;
+
+    generic)
+    open_generic "$url"
+    ;;
+
+    *)
+    exit_failure_operation_impossible "no method available for opening '$url'"
+    ;;
+esac


Property changes on: trunk/meta/xdg-utils/xdg-open
___________________________________________________________________
Name: svn:executable
   + *

Modified: trunk/mojosetup.c
===================================================================
--- trunk/mojosetup.c	2008-01-25 11:09:16 UTC (rev 473)
+++ trunk/mojosetup.c	2008-01-25 16:01:19 UTC (rev 474)
@@ -749,12 +749,18 @@
 int MojoSetup_testLaunchBrowserCode(int argc, char **argv)
 {
     int i;
+
+    if (!MojoArchive_initBaseArchive())  // Maybe need for xdg-open script.
+        panic("Initial setup failed. Cannot continue.");
+
     printf("Testing browser launching code...\n\n");
     for (i = 1; i < argc; i++)
     {
         const boolean rc = MojoPlatform_launchBrowser(argv[i]);
         printf("Launch '%s': %s\n", argv[i], rc ? "success" : "failure");
     } // for
+
+    MojoArchive_deinitBaseArchive();
     return 0;
 } // MojoSetup_testLaunchBrowserCode
 #endif

Modified: trunk/platform_unix.c
===================================================================
--- trunk/platform_unix.c	2008-01-25 11:09:16 UTC (rev 473)
+++ trunk/platform_unix.c	2008-01-25 16:01:19 UTC (rev 474)
@@ -26,6 +26,7 @@
 #include <syslog.h>
 #include <dirent.h>
 #include <fcntl.h>
+#include <wait.h>
 
 #if MOJOSETUP_HAVE_SYS_UCRED_H
 #  ifdef MOJOSETUP_HAVE_MNTENT_H
@@ -55,6 +56,7 @@
 
 #include "platform.h"
 #include "gui.h"
+#include "fileio.h"
 
 static struct timeval startup_time;
 
@@ -933,39 +935,98 @@
 
 
 #if !PLATFORM_MACOSX && !PLATFORM_BEOS
-typedef enum
+static int runScriptString(const char *str, boolean devnull, const char **_argv)
 {
-    DESKTOP_MUST_CHECK,
-    DESKTOP_UNKNOWN,
-    DESKTOP_GNOME,
-    DESKTOP_KDE,
-    DESKTOP_XFCE4,
-} UnixDesktopType;
+    int retval = 127;
+    pid_t pid = 0;
+    int pipes[2];
 
+    if (pipe(pipes) == -1)
+        return retval;
 
-static UnixDesktopType getDesktopType(void)
-{
-    static UnixDesktopType retval = DESKTOP_MUST_CHECK;
-    if (retval == DESKTOP_MUST_CHECK)
+    pid = fork();
+    if (pid == -1)  // -1 == fork() failed.
     {
-        const char *envr = getenv("KDE_FULL_SESSION");
-        if ( (envr != NULL) && (strcmp(envr, "true") == 0) )
-            retval = DESKTOP_KDE;
-        else if (getenv("GNOME_DESKTOP_SESSION_ID") != NULL)
-            retval = DESKTOP_GNOME;
-        else if (system("xprop -root _DT_SAVE_MODE |"
-                       " grep ' = \"xfce4\"$' >/dev/null 2>&1") == 0)
+        close(pipes[0]);
+        close(pipes[1]);
+        return retval;
+    } // if
+
+    else if (pid == 0)  // we're the child process.
+    {
+        int argc = 0;
+        const char **argv = NULL;
+
+        close(pipes[1]);  // close the writing end.
+        dup2(pipes[0], 0);  // replace stdin.
+        if (devnull)
         {
-            retval = DESKTOP_XFCE4;  // this nasty compliments of xdg-open.
-        } // else if
-        else
+            dup2(open("/dev/null", O_WRONLY), 1);  // replace stdout
+            dup2(open("/dev/null", O_WRONLY), 2);  // replace stderr
+        } // if
+
+        while (_argv[argc++] != NULL) { /* no-op */ }
+        argv = (const char **) xmalloc(sizeof (char *) * argc+3);
+        argv[0] = "/bin/sh";
+        argv[1] = "-s";
+        for (argc = 0; _argv[argc] != NULL; argc++)
+            argv[argc+2] = _argv[argc];
+        argv[argc+2] = NULL;
+
+        execv(argv[0], (char **) argv);
+        _exit(retval);  // uhoh, failed.
+    } // else if
+
+    else  // we're the parent (pid == child process id).
+    {
+        int status = 0;
+        size_t len = strlen(str);
+        boolean failed = false;
+        close(pipes[0]);  // close the reading end.
+        failed |= (write(pipes[1], str, len) != len);
+        failed |= (close(pipes[1]) == -1);
+
+        // !!! FIXME: we need a GGui->pump() or something here if we'll block.
+        if (waitpid(pid, &status, 0) != -1)
         {
-            retval = DESKTOP_UNKNOWN;
-        } // else
+            if (WIFEXITED(status))
+                retval = WEXITSTATUS(status);
+        } // if
+    } // else
+
+    return retval;
+} // runScriptString
+
+
+static int runScript(const char *script, boolean devnull, const char **argv)
+{
+    int retval = 127;
+    char *str = NULL;
+    MojoInput *in = MojoInput_newFromArchivePath(GBaseArchive, script);
+    if (in != NULL)
+    {
+        int64 len = in->length(in);
+        if (len > 0)
+        {
+            str = (char *) xmalloc(len + 1);
+            if (in->read(in, str, len) == len)
+                str[len] = '\0';
+            else
+            {
+                free(str);
+                str = NULL;
+            } // else
+        } // if
+
+        in->close(in);
     } // if
 
+    if (str != NULL)
+        retval = runScriptString(str, devnull, argv);
+
+    free(str);
     return retval;
-} // getDesktopType
+} // runScript
 
 
 static char *shellEscape(const char *str)
@@ -1002,108 +1063,27 @@
 } // shellEscape
 
 
-static const char *defaultBrowsers(void)
-{
-    const boolean ttyonly = ( (GGui == NULL) ||
-                              (strcmp(GGui->name(), "stdio") == 0) ||
-                              (strcmp(GGui->name(), "ncurses") == 0) );
-
-    return ((ttyonly) ? "links:lynx" : "firefox -raise:mozilla:netscape");
-} // defaultBrowsers
-
-
-static boolean launchGenericBrowser(const char *escapedurl)
-{
-    // See http://catb.org/~esr/BROWSER/ for details.
-    // !!! FIXME: this isn't actually entirely right...we're not parsing
-    // !!! FIXME:  out %s sequences or anything...the spec seems to think
-    // !!! FIXME:  we should either parse the commands into an execv() array
-    // !!! FIXME:  ourselves, duplicating the shell's parser exactly, or
-    // !!! FIXME:  just pass them unmolested to system(), and hope that
-    // !!! FIXME:  the url is escaped correctly since no one is declared to
-    // !!! FIXME:  be in charge of that.
-    // !!! FIXME: esr probably shouldn't have done the %s thing, and just
-    // !!! FIXME:  said "plug the url on as argv[1] and be done with it,
-    // !!! FIXME:  if they need fancy scripting, let them write a script file."
-    // !!! FIXME: Also, it doesn't talk about if you should block, or fork(),
-    // !!! FIXME:  but it looks like blocking is the only reasonable thing.
-    // !!! FIXME: ...soooo, that's what I'm doing here. Sorry, Eric.  :/
-    boolean retval = false;
-    const char *defenvr = defaultBrowsers();
-    const char *_envr = getenv("BROWSER");
-    char *envr = xstrdup(_envr ? _envr : defenvr);
-    char *ptr = envr;
-    char *prev = envr;
-    char *cmd = NULL;
-
-    while (1)
-    {
-        const char ch = *ptr;
-        const boolean lastone = (ch == '\0');
-        if ((ch == ':') || (lastone))
-        {
-            *ptr = '\0';
-            if (ptr != prev)
-            {
-                cmd = format("%0 %1", prev, escapedurl);
-                retval = (system(cmd) == 0);
-                free(cmd);
-                if (retval)
-                    break;
-            } // if
-            prev = ptr++;
-        } // if
-
-        if (lastone)
-            break;
-
-        ptr++;
-    } // for
-
-    free(envr);
-    return retval;
-} // launchGenericBrowser
-
-
 static boolean unix_launchBrowser(const char *url)
 {
     boolean retval = false;
-    char *escapedurl = shellEscape(url);
-    char *cmd = format("xdg-open %0 >/dev/null 2>&1", escapedurl);
+    char *path = findBinaryInPath("dfdfxdg-open");
 
-    retval = (system(cmd) == 0);
-    free(cmd);
-
-    if (!retval)
+    if (path != NULL)  // it's installed on the system; use that.
     {
-        // no xdg-open in the $PATH, or it failed. Try to do it ourselves...
-        const UnixDesktopType desktop = getDesktopType();
-        if (desktop == DESKTOP_KDE)
-            cmd = format("kfmclient exec %0 >/dev/null 2>&1", escapedurl);
-        else if (desktop == DESKTOP_GNOME)
-            cmd = format("gnome-open %0 >/dev/null 2>&1", escapedurl);
-        else if (desktop == DESKTOP_XFCE4)
-            cmd = format("exo-open %0 >/dev/null 2>&1", escapedurl);
-        else // (desktop == DESKTOP_UNKNOWN) or we missed something here.
-        {
-            cmd = NULL;
-            retval = launchGenericBrowser(escapedurl);
-        } // else
+        char *escapedurl = shellEscape(url);
+        char *cmd = format("xdg-open %0 >/dev/null 2>&1", escapedurl);
+        retval = (system(cmd) == 0);
+        free(cmd);
+        free(escapedurl);
+        free(path);
+    } // if
 
-        if (cmd != NULL)
-        {
-            retval = (system(cmd) == 0);
-            free(cmd);
-
-            // !!! FIXME: apparently you can't trust the return value from
-            // !!! FIXME:  KDE <= 3.5.4, so for now we just always ignore
-            // !!! FIXME:  it and pretend it worked out.
-            if (desktop == DESKTOP_KDE)
-                retval = true;
-        } // if
+    else  // try our fallback copy of xdg-utils in GBaseArchive?
+    {
+        const char *argv[] = { url, NULL };
+        retval = (runScript("meta/xdg-utils/xdg-open", true, argv) == 0);
     } // if
 
-    free(escapedurl);
     return retval;
 } // unix_launchBrowser
 #endif




More information about the mojosetup-commits mailing list