Logo Search packages:      
Sourcecode: whitedune version File versions  Download package

browser.c

/*
 * browser.c - unix interface to web browser
 *
 * Copyright (C) 2000 Stephen F. White, 2003 J. "MUFTI" Scheurich
 * 
 * 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 (see the file "COPYING" for details); if 
 * not, write to the Free Software Foundation, Inc., 675 Mass Ave, 
 * Cambridge, MA 02139, USA.
 */

#ifdef __sun
# define BSD_COMP
#endif
#include <fcntl.h>

#include <X11/Intrinsic.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>

#include "config.h"
#include "swt.h"

typedef struct SBrowser {
    STABLE              prefs;
    char                 *command;
    int                         pureVRML97;
    int                         useFork;
    int                       useRemote;
    char                 *remoteCommand;
    pid_t               pid;
} SBrowser;

extern XtAppContext TheAppContext;

static int console = 2;

static int  browserLaunch(SBROWSER browser, const char *path, SWND wnd);
static int  browserRemote(SBROWSER browser, const char *path);
static void childInput(XtPointer closure , int *source, XtInputId *id);
static int  waitForProcess(pid_t pid);
static pid_t      createProcess(const char *cmdline, SWND wnd);
static pid_t      createSimpleProcess(const char *cmdline);

static int errorToConsole = 1;

/*******************/
/* browser preview */
/*******************/

SBROWSER
swBrowserInit(STABLE prefs)
{
    SBrowser      *browser = malloc(sizeof(SBrowser));
    browser->prefs = prefs;
    browser->command = strdup(swGetPreference(prefs, "PreviewCommand",
                                              VRML_BROWSER));
#ifdef VRML_REMOTE
    browser->useRemote = swGetIntPreference(prefs, "PreviewUseRemote", TRUE);
#else
    browser->useRemote = swGetIntPreference(prefs, "PreviewUseRemote", FALSE);
#endif
    browser->pureVRML97 = swGetIntPreference(prefs, "PreviewPureVRML97", TRUE);
    browser->useFork = swGetIntPreference(prefs, "PreviewUseFork", TRUE);
    browser->remoteCommand = strdup(swGetPreference(prefs,
                                                    "PreviewRemoteCommand",
                                            VRML_REMOTE_BROWSER));
    browser->pid = 0;

    errorToConsole = swGetIntPreference(prefs, "PreviewErrorToConsole", FALSE);

    console = open("/dev/console", O_WRONLY | O_NONBLOCK);
    if (console == -1)
        console = 2;

    return browser;
}

int
swBrowserGetPureVRML97(SBROWSER browser)
{
    return browser->pureVRML97;
}

int
swBrowserGetUseFork(SBROWSER browser)
{
    return browser->useFork;
}

void
swBrowserGetSettings(SBROWSER browser, const char **command, 
                     int* pureVRML97, int *useRemote, int *useFork,
                 const char **remoteCommand, const char **application,
                 const char **topic)
{
    *command = browser->command;
    *pureVRML97 = browser->pureVRML97;
    *useRemote = browser->useRemote;
    *useFork = browser->useFork;
    *remoteCommand = browser->remoteCommand;
    *application = NULL;
    *topic = NULL;
}

void
swBrowserSetSettings(SBROWSER browser, const char *command, 
                     int pureVRML97, int useRemote, int useFork,
                 const char *remoteCommand, const char *application,
                 const char *topic)
{
    free(browser->command);
    free(browser->remoteCommand);

    browser->command = strdup(command);
    browser->pureVRML97 = pureVRML97;
    browser->useRemote = useRemote;
    browser->useFork = useFork;
    browser->remoteCommand = strdup(remoteCommand);

    swSetPreference(browser->prefs, "PreviewCommand", browser->command);
    swSetIntPreference(browser->prefs, "PreviewUseRemote", browser->useRemote);
    swSetIntPreference(browser->prefs, "PreviewPureVRML97", browser->pureVRML97);
    swSetIntPreference(browser->prefs, "PreviewUseFork", browser->useFork);
    swSetPreference(browser->prefs, "PreviewRemoteCommand", browser->remoteCommand);
}

int swBrowserGetSettingsErrorToConsole(SBROWSER browser)
{
    return errorToConsole;
}

void swBrowserSetSettingsErrorToConsole(SBROWSER browser, int toConsole)
{
    errorToConsole = toConsole;    
    swSetIntPreference(browser->prefs, "PreviewErrorToConsole", errorToConsole);
}

void
swBrowserSetDefault(SBROWSER browser)
{
    browser->command = strdup(VRML_BROWSER);
#ifdef VRML_REMOTE
    browser->useRemote = TRUE;
#else
    browser->useRemote = FALSE;
#endif
    browser->pureVRML97 = TRUE;
    browser->useFork = TRUE;
    browser->remoteCommand = strdup(VRML_REMOTE_BROWSER);
    browser->pid = 0;
}

void
swBrowserPreview(SBROWSER browser, const char *path, SWND wnd)
{
    if (browser->useRemote) {
        if (!browserRemote(browser, path)) {
            browserLaunch(browser, path, wnd);
        }
    } else {
        browserLaunch(browser, path, wnd);
    }
}

void
swBrowserShutdown(SBROWSER browser)
{
    if (!browser) return;

    if (browser->pid != 0) {
      kill(browser->pid, SIGTERM);
      waitForProcess(browser->pid);
    }
    free(browser->command);
    free(browser->remoteCommand);
    free(browser);
}

static int
browserLaunch(SBROWSER browser, const char *path, SWND wnd)
{
    char        arg[1024];

    snprintf(arg, 1023, browser->command, path);
    if (browser->useFork) {
        browser->pid = createProcess(arg, wnd);
        if (browser->pid != 0)
            return TRUE;
        else
            return FALSE;
    } else
        return system(arg);
}

static int
browserRemote(SBROWSER browser, const char *path)
{
    char    url[1024];
    char        arg[1024];
    pid_t   pid;

    snprintf(url, 1023, "file://%s", path);
    snprintf(arg, 1023, browser->remoteCommand, url);
    pid = createSimpleProcess(arg);
    return waitForProcess(pid);
}

static pid_t
createProcess(const char *cmdline, SWND wnd)
{
    pid_t       pid;
    int           fd[2];
    const char *argv[4];

    if (!cmdline || !wnd) return 0;

    argv[0] = "sh";
    argv[1] = "-c";
    argv[2] = cmdline;
    argv[3] = NULL;

    if (pipe(fd) != 0) return 0;

    pid = fork();
    switch(pid) {
      case -1:
      /* error */
      close(fd[0]);
      close(fd[1]);
      return 0;
      case 0:
      /* child process */
      if (fd[1] != STDERR_FILENO) {
          dup2(fd[1], STDERR_FILENO); /* pipe output is now stderr */
          close(fd[1]);         /* close old pipe fds */
      }
      close(fd[0]);
      execv("/bin/sh", (char * const *) argv);
        swCleanup();
      exit(1);                /* if we get this far, it's an error */
      default:
      /* parent process */
      /* add fd[0] to list of inputs, so we can watch the shell's output */
      XtAppAddInput(TheAppContext, fd[0], (XtPointer) XtInputReadMask,
                  childInput, (XtPointer) wnd);
/*      close(fd[1]); */
      break;
    }
    return pid;
}

static pid_t
createSimpleProcess(const char *cmdline)
{
    pid_t       pid;
    const char *argv[4];

    if (!cmdline) return 0;

    argv[0] = "sh";
    argv[1] = "-c";
    argv[2] = cmdline;
    argv[3] = NULL;
    pid = fork();
    switch(pid) {
      case -1:
      /* error */
      return 0;
      case 0:
      /* child process */
      execv("/bin/sh", (char * const *) argv);
        swCleanup();
      exit(1);          /* if we get this far, it's an error */
      default:
      /* parent process */
      break;
    }
    return pid;
}

static void
childInput(XtPointer closure , int *source, XtInputId *id)
{
    char                buf[1024];
    int                 bytes;

    bytes = read(*source, buf, 1023);
    buf[bytes] = '\0';
    if (errorToConsole)
        mywritestr(console, buf);
    else
        swMessageBox((SWND) closure, buf, "Preview", SW_MB_OK, SW_MB_WARNING);
}

static int
waitForProcess(pid_t pid)
{
    int           status;

    for(;;) {
      if (waitpid(pid, &status, 0) == -1) {
          if (errno != EINTR)
            return 0;
      } else {
          return WIFEXITED(status) && WEXITSTATUS(status) == 0;
      }
    }
}

void swRemoveFile(const char* filename)
{
    unlink(filename);
}

/**********/
/* upload */
/**********/

typedef struct SUpload {
    STABLE              prefs;
    char                 *commandline;
    char                 *htmlTag;
    char                 *password;
} SUpload;

SUPLOAD   
swUploadInit(STABLE prefs)
{
    SUpload *upload = malloc(sizeof(SUpload));
    upload->prefs = prefs;
    upload->commandline = strdup(swGetPreference(prefs, "UploadCommandLine",
                                                 ""));
    upload->htmlTag = strdup(swGetPreference(prefs, "UploadHtmlTags",
                                             ""));
    /* do not read/store password for security reasons */
    upload->password = malloc(1024);
    upload->password[0] = 0;
    mlock(upload->password, 1024);
    return upload;
}

void      
swUploadGetSettings(SUPLOAD upload, 
                    const char **commandline, 
                    const char **htmlTag, 
                    const char **password)
{
    *commandline = upload->commandline;
    *htmlTag = upload->htmlTag;
    *password = upload->password;
}

void      
swUploadSetSettings(SUPLOAD upload, 
                    const char *commandline, 
                    const char *htmlTag, 
                    const char *password)
{
    free(upload->commandline);
    free(upload->htmlTag);

    upload->commandline = strdup(commandline);
    upload->htmlTag = strdup(htmlTag);
    if (password != NULL)
         mystrncpy_secure(upload->password, password, 1023);
    else
        upload->password[0] = 0;

    swSetPreference(upload->prefs, "UploadCommandLine", upload->commandline);
    swSetPreference(upload->prefs, "UploadHtmlTags", upload->htmlTag);
    /* do not read/store password for security reasons */
}

int      
swHasUpload(SUPLOAD upload) 
{
    if (strlen(upload->commandline) > 0)
        return 1;
    else
        return 0;
}

char*
swUpload(SUPLOAD upload, char *fileToUpload, SHBROWSER browser, SWND wnd)
{
    static char uploadCommand[1024];
    FILE *cmd;
    int f = -1;
    int i;
    int needPassword = 0;
    static char htmlTags[1024];
    char *htmlpath = (char *) malloc(1024);
    htmlpath[0] = 0;

    if ((upload->password != NULL) && (strlen(upload->password) != 0))
        if (strstr(upload->commandline, "%s")  !=  NULL)
            if (strstr(strstr(upload->commandline, "%s") + 2, "%s") !=  NULL)
                needPassword = 1; /* if commandline has two %s */
    mlock(uploadCommand, 1024);
    if (needPassword)
        mysnprintf(uploadCommand, 1023, upload->commandline, upload->password,
                   fileToUpload);
    else
        mysnprintf(uploadCommand, 1023, upload->commandline, fileToUpload, "");

    if ((cmd = popen(uploadCommand, "w")) != NULL) {
        if ((upload->password != NULL) && (strlen(upload->password) != 0))
            fputs(upload->password, cmd);
        if (pclose(cmd) != 0) {
            swMessageBox(wnd, "upload failed", "Upload failed",
                         SW_MB_OK, SW_MB_WARNING);
            htmlpath[0] = 0;
            return htmlpath;
        }
    }
 
    swGetTempPath(htmlpath, ".dune_upload_reload", ".html", 1024);
    f = open(htmlpath, O_WRONLY | O_CREAT, 00666);
    if (f == -1) {
        swMessageBox(wnd, "open of html file failed", "Upload reload error", 
                     SW_MB_OK, SW_MB_WARNING);
        htmlpath[0] = 0;
        return htmlpath;
    }
    if ((upload->password != NULL) && (strlen(upload->password) != 0))
        mysnprintf(htmlTags, 1023, upload->htmlTag, upload->password);
    else
        mysnprintf(htmlTags, 1023, upload->htmlTag, "");
    if (write(f, htmlTags, sizeof(htmlTags)) != sizeof(htmlTags)) {
        swMessageBox(wnd, "open of html file failed", "Upload reload error", 
                     SW_MB_OK, SW_MB_WARNING);
        return htmlpath;
    }
    close(f);
    helpBrowserRemote(browser, htmlpath, wnd);
    for (i = 0; i < 1024; i++)
        uploadCommand[i] = (char) 0;
    munlock(uploadCommand, 1024);    
    return htmlpath;
}

void
swUploadCleanupPasswd(SUPLOAD upload)
{
    int i;
    for (i = 0; i < strlen(upload->password); i++)
        upload->password[i] = (char) 0;
    munlock(upload->password, 1024);
}

/*****************/
/* help browser  */
/*****************/

typedef struct SHelpBrowser {
    STABLE              prefs;
    char                 *helpCommand;
    char                 *helpUrl;
    char                 *vrmlUrl;
    pid_t               pid;
} SHelpBrowser;

int helpBrowserRemote(SHBROWSER browser, const char *path, SWND wnd);

SHBROWSER
swHelpBrowserInit(STABLE prefs)
{
    char *dunedocs = NULL;
    SHelpBrowser *browser = malloc(sizeof(SHelpBrowser));
    browser->prefs = prefs;
    browser->helpCommand = strdup(swGetPreference(prefs,"HelpCommand",
                                                  WWW_BROWSER));
    dunedocs = getenv("DUNEDOCS");
    if (dunedocs != NULL) {
        char *html = "/index.html";
        char *url;
        url = (char *) malloc(strlen(dunedocs) + strlen(html) + 1);
        strcpy(url, dunedocs);
        strcat(url, html);
        browser->helpUrl = strdup(swGetPreference(prefs, "HelpURL", url));
        free(url);
    } else
        browser->helpUrl = strdup(swGetPreference(prefs, "HelpURL", HELP_URL));
    browser->vrmlUrl = strdup(swGetPreference(prefs,
                                              "HelpVrmlNodes",VRML_NODES_URL));

    browser->pid = 0;

    return browser;
}

void
swHelpBrowserGetSettings(SHBROWSER browser, 
                         const char **helpCommand, 
                         const char **helpRemoteCommand, 
                         const char **helpUrl, const char **vrmlUrl,
                         const char **application, const char **topic)
{
    *helpCommand = browser->helpCommand;
    *helpUrl = browser->helpUrl;
    *vrmlUrl = browser->vrmlUrl;
    *application = NULL;
    *topic = NULL;
}

void
swHelpBrowserSetSettings(SHBROWSER browser, 
                         const char *helpCommand, 
                         const char *helpRemoteCommand, 
                         const char *helpUrl, const char *vrmlUrl,
                     const char *application, const char *topic)
{
    free(browser->helpCommand);
    browser->helpCommand = strdup(helpCommand);

    free(browser->helpUrl);
    browser->helpUrl = strdup(helpUrl);
    
    free(browser->vrmlUrl);
    browser->vrmlUrl = strdup(vrmlUrl);
    
    swSetPreference(browser->prefs, "HelpCommand", 
                    browser->helpCommand);
    swSetPreference(browser->prefs, "HelpURL", 
                    browser->helpUrl);
    swSetPreference(browser->prefs, "HelpVrmlNodes", 
                    browser->vrmlUrl);
}

void
swHelpBrowserHTML(SHBROWSER browser, SWND wnd)
{
    char* path=browser->helpUrl;
    
    helpBrowserRemote(browser, path, wnd);
}

void
swHelpBrowserVRML(SHBROWSER browser, const char* selection_string, SWND wnd)
{
    char* path=malloc(strlen(browser->vrmlUrl)+strlen(selection_string)+2);
    strcpy(path,browser->vrmlUrl);
    strcat(path,"#");
    strcat(path,selection_string);
    helpBrowserRemote(browser, path , wnd);
    free(path);
}

void
swHelpBrowserShutdown(SHBROWSER browser)
{
    if (!browser) return;

    if (browser->pid != 0) {
      kill(browser->pid, SIGTERM);
      waitForProcess(browser->pid);
    }
    free(browser->helpCommand);
    free(browser->helpUrl);
    free(browser->vrmlUrl);
    free(browser);
}

int
helpBrowserRemote(SHBROWSER browser, const char *path, SWND wnd)
{
    char    url[1024];
    char        arg[1024];
    char        command[1024];
    pid_t   pid;
    int i;

    snprintf(url, 1023, path);
    snprintf(arg, 1023, browser->helpCommand, url);
    pid = createSimpleProcess(arg);
    /* if failed, search first string (till blank) as command */
    if (waitForProcess(pid)==0) {
        for (i=0;(i<strlen(browser->helpCommand)) && (i<1024-3);i++) {
            command[i]=browser->helpCommand[i];
            if ((browser->helpCommand[i]  !=' ') &&   
                (browser->helpCommand[i+1]==' ')) {
                i++;
                break;
            }
        }
        command[i]=0;
        strcat(command," %s");
        mysnprintf(arg, 1024, command, path);
        browser->pid = createProcess(arg, wnd);
    }
    if (browser->pid != 0) {
        return TRUE;
    } else {
        return FALSE;
    }   
}


/****************/
/* text editor */
/**************/

static int fdpipe_message[2];
static int fdpipe_close[2];

int 
swCheckRunningProcess(void)
{
    char message[2] = { 'l' , '\0' };
    /* check if there is something in the pipe (process ended) */
    int byteFromPipe = 0;
    if (read(fdpipe_message[0],message,1) == 1)
        byteFromPipe = 1;       
    if (byteFromPipe) {
        write(fdpipe_close[1], message, 1);
        /* 
           send notification to other process
           (otherwise data possibly would die with close of pipe)
        */
        close(fdpipe_close[1]);
        close(fdpipe_message[0]);

    } 
    return !byteFromPipe;
}

int
swCreateCheckableProcess(const char *cmdline)
{
    char message[2] = { 'l' , '\0' };
    pid_t       pid;

    if (pipe(fdpipe_message) != 0) return -1;
    
    if (pipe(fdpipe_close) != 0) {
      close(fdpipe_message[0]);
      close(fdpipe_message[1]);        
        return -1;
    }

    /* switch to non blocking io for pipe of first message */
    fcntl(fdpipe_message[0],F_SETFL,O_NONBLOCK);
    fcntl(fdpipe_message[1],F_SETFL,O_NONBLOCK);

    pid = fork();
    switch(pid) {
      case -1:
      /* error */
      close(fdpipe_message[0]);
      close(fdpipe_message[1]);
      close(fdpipe_close[0]);
      close(fdpipe_close[1]);
      return -1;
      case 0:
      /* child process */
      close(fdpipe_message[0]);
      close(fdpipe_close[1]);
        system(cmdline);
        /* send message to pipe */
        write(fdpipe_message[1],message,1);
        /* wait for notification */
        read(fdpipe_close[0],message,1);
        close(fdpipe_message[1]);
        close(fdpipe_close[0]);
      exit(0);                
      default:
      /* parent process */
        close(fdpipe_message[1]);
        close(fdpipe_close[0]);
      break;
    }
    return 0;
}


typedef struct STextedit {
    STABLE              prefs;
    char                 *texteditCommand;
    char                 *texteditLinenumberOption;
    int                 texteditUseExtensionTxt;
    int                 texteditAllowPopup;
} STextedit;


STEXTEDIT
swTexteditInit(STABLE prefs)
{
    STextedit *textedit = malloc(sizeof(STextedit));
    textedit->prefs = prefs;
    if (getenv("WINEDITOR") != NULL) {
        textedit->texteditCommand = strdup(swGetPreference(prefs,
                                                  "TextEditCommand",
                                                  getenv("WINEDITOR")));
        textedit->texteditLinenumberOption = strdup(swGetPreference(prefs,
                                                  "TextEditLinenumberOption",
                                                  "+"));
    } else {
#ifndef MACOSX
        textedit->texteditCommand = strdup(swGetPreference(prefs,
                                                  "TextEditCommand",
                                                  "xterm -e vi"));
        textedit->texteditLinenumberOption = strdup(swGetPreference(prefs,
                                                  "TextEditLinenumberOption",
                                                  "+"));
#else
        /* 
           typical MacOS X users would die if they should use vi, 
           but the normal MacOS X texteditor: 
           "/usr/bin/open /Applications/TextEdit.app"
           is useless here, cause it can not wait for the completion of editing
         */ 
        textedit->texteditCommand = strdup(swGetPreference(prefs,
                                                  "TextEditCommand",
                                                  "/usr/X11R6/bin/xedit"));
        textedit->texteditLinenumberOption = strdup(swGetPreference(prefs,
                                                  "TextEditLinenumberOption",
                                                  ""));
#endif
    }
    textedit->texteditUseExtensionTxt = swGetIntPreference(prefs,
                                                  "TextEditUseExtensionTxt",
                                                  1);
    textedit->texteditAllowPopup = swGetIntPreference(prefs,
                                                  "TextEditAllowPopup",
                                                  1);
    return textedit;
}

void swTexteditGetSettingsUseExtensionTxt(STEXTEDIT textedit,
                                       int *texteditUseExtensionTxt)
{
    *texteditUseExtensionTxt = textedit->texteditUseExtensionTxt;
}

void
swTexteditGetSettings(STEXTEDIT textedit, 
                         const char **texteditCommand,
                         const char **texteditLinenumberOption,
                         int *texteditUseExtensionTxt,
                         int *texteditAllowPopup)
{
    *texteditCommand = textedit->texteditCommand;
    *texteditLinenumberOption = textedit->texteditLinenumberOption;
    *texteditUseExtensionTxt = textedit->texteditUseExtensionTxt;
/* not yet  
    *texteditAllowPopup = textedit->texteditAllowPopup;
 */
    *texteditAllowPopup = 1;
}

void
swTexteditSetSettings(STEXTEDIT textedit, 
                         const char *texteditCommand,
                         const char *texteditLinenumberOption,
                         int texteditUseExtensionTxt,
                         int texteditAllowPopup)
{
    free(textedit->texteditCommand);
    textedit->texteditCommand = strdup(texteditCommand);

    free(textedit->texteditLinenumberOption);
    textedit->texteditLinenumberOption = strdup(texteditLinenumberOption);

    textedit->texteditUseExtensionTxt = texteditUseExtensionTxt;
    textedit->texteditAllowPopup = texteditAllowPopup;

    swSetPreference(textedit->prefs, "TextEditCommand", 
                    textedit->texteditCommand);
    swSetPreference(textedit->prefs, "TextEditLinenumberOption", 
                    textedit->texteditLinenumberOption);    
    swSetIntPreference(textedit->prefs, "TextEditUseExtensionTxt", 
                    textedit->texteditUseExtensionTxt);
    swSetIntPreference(textedit->prefs, "TextEditAllowPopup", 
                    textedit->texteditAllowPopup);
    
}



Generated by  Doxygen 1.6.0   Back to index