1 /*
2  * browser.c - unix interface to web browser
3  *
4  * Copyright (C) 2000 Stephen F. White, 2003 J. "MUFTI" Scheurich
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program (see the file "COPYING" for details); if
18  * not, write to the Free Software Foundation, Inc., 675 Mass Ave,
19  * Cambridge, MA 02139, USA.
20  */
21 
22 #ifdef __sun
23 # define BSD_COMP
24 #endif
25 #include <fcntl.h>
26 
27 #include <X11/Intrinsic.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <signal.h>
31 #include <unistd.h>
32 #include <errno.h>
33 #include <sys/wait.h>
34 
35 #include "config.h"
36 
37 #ifdef HAVE_TERM
38 # define TERM HAVE_TERM
39 #else
40 # define TERM "xterm"
41 #endif
42 
43 #ifdef HAS_MLOCK
44 # include <sys/mman.h>
45 #endif
46 
47 #include "swt.h"
48 #include "mysnprintf.h"
49 #include "WriteFlags.h"
50 
51 typedef struct SBrowser {
52     STABLE prefs;
53     char  *command;
54     int    vrmlLevel;
55     int    useFork;
56     int    useRemote;
57     char  *remoteCommand;
58     pid_t  pid;
59 } SBrowser;
60 
61 extern XtAppContext TheAppContext;
62 
63 static int console = 2;
64 
65 static int browserLaunch(SBROWSER browser, const char *path, SWND wnd);
66 static int browserRemote(SBROWSER browser, const char *path);
67 static void childInput(XtPointer closure , int *source, XtInputId *id);
68 static int waitForProcess(pid_t pid);
69 static pid_t createProcess(const char *cmdline, SWND wnd);
70 static pid_t createSimpleProcess(const char *cmdline);
71 
72 static int errorToConsole = 1;
73 
74 /*******************/
75 /* browser preview */
76 /*******************/
77 
78 SBROWSER
swBrowserInit(STABLE prefs)79 swBrowserInit(STABLE prefs)
80 {
81     SBrowser *browser = malloc(sizeof(SBrowser));
82     browser->prefs = prefs;
83     browser->command = mystrdup(swGetPreference(prefs, "PreviewCommand",
84                                                 VRML_BROWSER));
85     browser->useFork = swGetIntPreference(prefs, "PreviewUseFork", FALSE);
86     browser->vrmlLevel = swGetIntPreference(prefs, "PreviewVrmlLevel", X3DOM);
87     browser->useRemote = swGetIntPreference(prefs, "PreviewUseRemote", FALSE);
88     browser->remoteCommand = mystrdup(swGetPreference(prefs,
89                                                       "PreviewRemoteCommand",
90                                                       VRML_REMOTE_BROWSER));
91     browser->pid = 0;
92 
93     errorToConsole = swGetIntPreference(prefs, "PreviewErrorToConsole", FALSE);
94 
95     console = open("/dev/console", O_WRONLY | O_NONBLOCK);
96     if (console == -1)
97         console = 2;
98 
99     return browser;
100 }
101 
102 int
swBrowserGetVrmlLevel(SBROWSER browser)103 swBrowserGetVrmlLevel(SBROWSER browser)
104 {
105     return browser->vrmlLevel;
106 }
107 
108 int
swBrowserGetRemote(SBROWSER browser)109 swBrowserGetRemote(SBROWSER browser)
110 {
111     return browser->useRemote;
112 }
113 
114 void
swBrowserSetRemote(SBROWSER browser,int remote)115 swBrowserSetRemote(SBROWSER browser, int remote)
116 {
117     browser->useRemote = remote;
118 }
119 
120 int
swBrowserGetUseFork(SBROWSER browser)121 swBrowserGetUseFork(SBROWSER browser)
122 {
123     return browser->useFork;
124 }
125 
126 void
swBrowserGetSettings(SBROWSER browser,const char ** command,int * vrmlLevel,int * useRemote,int * useFork,const char ** remoteCommand,const char ** application,const char ** topic)127 swBrowserGetSettings(SBROWSER browser, const char **command,
128                      int* vrmlLevel, int *useRemote, int *useFork,
129                      const char **remoteCommand, const char **application,
130                      const char **topic)
131 {
132     *command = browser->command;
133     *vrmlLevel = browser->vrmlLevel;
134     *useRemote = browser->useRemote;
135     *useFork = browser->useFork;
136     *remoteCommand = browser->remoteCommand;
137     *application = NULL;
138     *topic = NULL;
139 }
140 
141 void
swBrowserSetSettings(SBROWSER browser,const char * command,int vrmlLevel,int useRemote,int useFork,const char * remoteCommand,const char * application,const char * topic)142 swBrowserSetSettings(SBROWSER browser, const char *command,
143                      int vrmlLevel, int useRemote, int useFork,
144                      const char *remoteCommand, const char *application,
145                      const char *topic)
146 {
147     char *oldCommand = mystrdup(command);
148     char *oldRemoteCommand = mystrdup(remoteCommand);
149     free(browser->command);
150     free(browser->remoteCommand);
151 
152     browser->command = oldCommand;
153     browser->vrmlLevel = vrmlLevel;
154     browser->useRemote = useRemote;
155     browser->useFork = useFork;
156     browser->remoteCommand = oldRemoteCommand;
157 
158     swSetPreference(browser->prefs, "PreviewCommand", browser->command);
159     swSetIntPreference(browser->prefs, "PreviewUseRemote", browser->useRemote);
160     swSetIntPreference(browser->prefs, "PreviewVrmlLevel", browser->vrmlLevel);
161     swSetIntPreference(browser->prefs, "PreviewUseFork", browser->useFork);
162     swSetPreference(browser->prefs, "PreviewRemoteCommand", browser->remoteCommand);
163 }
164 
swBrowserGetSettingsErrorToConsole(SBROWSER browser)165 int swBrowserGetSettingsErrorToConsole(SBROWSER browser)
166 {
167     return errorToConsole;
168 }
169 
swBrowserSetSettingsErrorToConsole(SBROWSER browser,int toConsole)170 void swBrowserSetSettingsErrorToConsole(SBROWSER browser, int toConsole)
171 {
172     errorToConsole = toConsole;
173     swSetIntPreference(browser->prefs, "PreviewErrorToConsole", errorToConsole);
174 }
175 
176 void
swBrowserSetDefault(SBROWSER browser)177 swBrowserSetDefault(SBROWSER browser)
178 {
179     browser->command = mystrdup(VRML_BROWSER);
180 #ifdef VRML_REMOTE
181     browser->useRemote = TRUE;
182 #else
183     browser->useRemote = FALSE;
184 #endif
185     browser->vrmlLevel = X3DOM;
186     browser->useFork = TRUE;
187     browser->remoteCommand = mystrdup(VRML_REMOTE_BROWSER);
188     browser->pid = 0;
189 }
190 
191 void
swBrowserPreview(SBROWSER browser,const char * path,SWND wnd)192 swBrowserPreview(SBROWSER browser, const char *path, SWND wnd)
193 {
194     if (browser->useRemote) {
195         if (!browserRemote(browser, path)) {
196             browserLaunch(browser, path, wnd);
197         }
198     } else {
199         browserLaunch(browser, path, wnd);
200     }
201 }
202 
203 void
swBrowserShutdown(SBROWSER browser)204 swBrowserShutdown(SBROWSER browser)
205 {
206     if (!browser) return;
207 
208     if (browser->pid != 0) {
209         kill(browser->pid, SIGTERM);
210         waitForProcess(browser->pid);
211     }
212     free(browser->command);
213     free(browser->remoteCommand);
214     free(browser);
215 }
216 
217 static int
browserLaunch(SBROWSER browser,const char * path,SWND wnd)218 browserLaunch(SBROWSER browser, const char *path, SWND wnd)
219 {
220     char arg[1024];
221 
222     mysnprintf(arg, 1023, browser->command, path);
223     if (browser->useFork) {
224         browser->pid = createProcess(arg, wnd);
225         if (browser->pid != 0)
226             return TRUE;
227         else
228             return FALSE;
229     } else
230         return system(arg);
231 }
232 
233 static int
browserRemote(SBROWSER browser,const char * path)234 browserRemote(SBROWSER browser, const char *path)
235 {
236     char url[1024];
237     char arg[1024];
238     pid_t pid;
239     int ret;
240     int i;
241 
242     mysnprintf(url, 1023, "file://%s", path);
243     mysnprintf(arg, 1023, browser->remoteCommand, url);
244     pid = createSimpleProcess(arg);
245     ret = waitForProcess(pid);
246     if (!ret) {
247         for (i = 0; (browser->remoteCommand[i] != ' ') &&
248                     (browser->remoteCommand[i] != 0) && (i < 1023); i++)
249             arg[i] = browser->remoteCommand[i];
250         arg[i] = ' ';
251         arg[i + 1] = 0;
252         mysnprintf(arg + i + 1, 1023 - i, url);
253         if (i != 0) {
254             pid = createSimpleProcess(arg);
255             ret = waitForProcess(pid);
256         }
257     }
258     return ret;
259 }
260 
261 static pid_t
createProcess(const char * cmdline,SWND wnd)262 createProcess(const char *cmdline, SWND wnd)
263 {
264     pid_t pid;
265     int fd[2];
266     const char *argv[4];
267 
268     if (!cmdline || !wnd) return 0;
269 
270     argv[0] = "sh";
271     argv[1] = "-c";
272     argv[2] = cmdline;
273     argv[3] = NULL;
274 
275     if (pipe(fd) != 0) return 0;
276 
277     pid = fork();
278     switch(pid) {
279       case -1:
280         /* error */
281         close(fd[0]);
282         close(fd[1]);
283         return 0;
284       case 0:
285         /* child process */
286         if (fd[1] != STDERR_FILENO) {
287             dup2(fd[1], STDERR_FILENO); /* pipe output is now stderr */
288             close(fd[1]);  /* close old pipe fds */
289         }
290         close(fd[0]);
291         execv("/bin/sh", (char * const *) argv);
292         swCleanup();
293         exit(1);  /* if we get this far, it's an error */
294       default:
295         /* parent process */
296         /* add fd[0] to list of inputs, so we can watch the shell's output */
297 //        XtAppAddInput(TheAppContext, fd[0], (XtPointer) XtInputReadMask,
298 //                      childInput, (XtPointer) wnd);
299 /*      close(fd[1]); */
300         break;
301     }
302     return pid;
303 }
304 
305 static pid_t
createSimpleProcess(const char * cmdline)306 createSimpleProcess(const char *cmdline)
307 {
308     pid_t       pid;
309     const char *argv[4];
310 
311     if (!cmdline) return 0;
312 
313     argv[0] = "sh";
314     argv[1] = "-c";
315     argv[2] = cmdline;
316     argv[3] = NULL;
317     pid = fork();
318     switch(pid) {
319       case -1:
320         /* error */
321         return 0;
322       case 0:
323         /* child process */
324         execv("/bin/sh", (char * const *) argv);
325         swCleanup();
326         exit(1);  /* if we get this far, it's an error */
327       default:
328         /* parent process */
329         break;
330     }
331     return pid;
332 }
333 
334 static void
childInput(XtPointer closure,int * source,XtInputId * id)335 childInput(XtPointer closure , int *source, XtInputId *id)
336 {
337     char buf[1024];
338     int bytes;
339 
340     bytes = read(*source, buf, 1023);
341     buf[bytes] = '\0';
342     if (errorToConsole)
343         mywritestr(console, buf);
344     else
345         swMessageBox((SWND) closure, buf, "Preview", SW_MB_OK, SW_MB_WARNING);
346 }
347 
348 static int
waitForProcess(pid_t pid)349 waitForProcess(pid_t pid)
350 {
351     int status;
352 
353     for (;;) {
354         if (waitpid(pid, &status, 0) == -1) {
355             if (errno != EINTR)
356                 return 0;
357         } else {
358             return WIFEXITED(status) && WEXITSTATUS(status) == 0;
359         }
360     }
361 }
362 
swRemoveFile(const char * filename)363 void swRemoveFile(const char* filename)
364 {
365     unlink(filename);
366 }
367 
368 /*****************/
369 /* help browser  */
370 /*****************/
371 
372 typedef struct SHelpBrowser {
373     STABLE prefs;
374     char *helpCommand;
375     char *helpUrl;
376     char *vrmlUrl;
377     char *x3dUrl;
378     pid_t pid;
379 } SHelpBrowser;
380 
381 int helpBrowserRemote(SHBROWSER browser, const char *path, SWND wnd);
382 
383 SHBROWSER
swHelpBrowserInit(STABLE prefs)384 swHelpBrowserInit(STABLE prefs)
385 {
386     char *dunedocs = NULL;
387     SHelpBrowser *browser = malloc(sizeof(SHelpBrowser));
388     browser->prefs = prefs;
389     browser->helpCommand = mystrdup(swGetPreference(prefs,"HelpCommand",
390                                                     WWW_BROWSER));
391     dunedocs = getenv("DUNEDOCS");
392     if (dunedocs != NULL) {
393         char *url;
394         url = (char *) malloc(strlen(dunedocs) + /* strlen(html) */ + 1);
395         strcpy(url, dunedocs);
396         browser->helpUrl = mystrdup(swGetPreference(prefs, "HelpURL", url));
397         free(url);
398     } else {
399         char *url;
400         const char *index = "index.html";
401         const char *helpDir = HELP_URL;
402         int helpDirLen;
403         url = (char *) malloc(strlen(HELP_URL) + strlen(index) + 2);
404         strcpy(url, HELP_URL);
405         helpDirLen = strlen(helpDir);
406         if (helpDirLen > 0)
407             if (helpDir[helpDirLen - 1] != '/')
408                 strcat(url, "/");
409         strcat(url, index);
410         browser->helpUrl = mystrdup(swGetPreference(prefs, "HelpURL", url));
411         free(url);
412     }
413     browser->vrmlUrl = mystrdup(swGetPreference(prefs, "HelpVrml",
414                                                 VRML_NODES_URL));
415     browser->x3dUrl = mystrdup(swGetPreference(prefs, "HelpX3D",
416                                                X3D_URL));
417 
418     browser->pid = 0;
419 
420     return browser;
421 }
422 
423 void
swHelpBrowserSetDefaults(SHBROWSER browser)424 swHelpBrowserSetDefaults(SHBROWSER browser)
425 {
426     char *dunedocs = NULL;
427 
428     browser->helpCommand = mystrdup(WWW_BROWSER);
429     dunedocs = getenv("DUNEDOCS");
430     if (dunedocs != NULL) {
431         char *url;
432         url = (char *) malloc(strlen(dunedocs) + /* strlen(html) */ + 1);
433         strcpy(url, dunedocs);
434         browser->helpUrl = mystrdup(url);
435         free(url);
436     } else
437         browser->helpUrl = mystrdup(HELP_URL);
438     browser->vrmlUrl = mystrdup(VRML_NODES_URL);
439     browser->x3dUrl = mystrdup(X3D_URL);
440 
441     browser->pid = 0;
442 }
443 
444 void
swHelpBrowserGetSettings(SHBROWSER browser,const char ** helpCommand,const char ** helpRemoteCommand,const char ** helpUrl,const char ** vrmlUrl,const char ** x3dUrl,const char ** application,const char ** topic)445 swHelpBrowserGetSettings(SHBROWSER browser,
446                          const char **helpCommand,
447                          const char **helpRemoteCommand,
448                          const char **helpUrl,
449                          const char **vrmlUrl, const char **x3dUrl,
450                          const char **application, const char **topic)
451 {
452     *helpCommand = browser->helpCommand;
453     *helpUrl = browser->helpUrl;
454     *vrmlUrl = browser->vrmlUrl;
455     *x3dUrl = browser->x3dUrl;
456     *application = NULL;
457     *topic = NULL;
458 }
459 
460 void
swHelpBrowserSetSettings(SHBROWSER browser,const char * helpCommand,const char * helpRemoteCommand,const char * helpUrl,const char * vrmlUrl,const char * x3dUrl,const char * application,const char * topic)461 swHelpBrowserSetSettings(SHBROWSER browser,
462                          const char *helpCommand,
463                          const char *helpRemoteCommand,
464                          const char *helpUrl,
465                          const char *vrmlUrl, const char *x3dUrl,
466                          const char *application, const char *topic)
467 {
468     free(browser->helpCommand);
469     browser->helpCommand = mystrdup(helpCommand);
470 
471     free(browser->helpUrl);
472     browser->helpUrl = mystrdup(helpUrl);
473 
474     free(browser->vrmlUrl);
475     browser->vrmlUrl = mystrdup(vrmlUrl);
476 
477     free(browser->x3dUrl);
478     browser->x3dUrl = mystrdup(vrmlUrl);
479 
480     swSetPreference(browser->prefs, "HelpCommand", browser->helpCommand);
481     swSetPreference(browser->prefs, "HelpURL", browser->helpUrl);
482     swSetPreference(browser->prefs, "HelpVrml", browser->vrmlUrl);
483     swSetPreference(browser->prefs, "HelpX3d", browser->x3dUrl);
484 }
485 
486 void
swHelpBrowserHTML(SHBROWSER browser,SWND wnd)487 swHelpBrowserHTML(SHBROWSER browser, SWND wnd)
488 {
489     char* path=browser->helpUrl;
490 
491     helpBrowserRemote(browser, path, wnd);
492 }
493 
swGetHelpUrl(SHBROWSER browser)494 char *swGetHelpUrl(SHBROWSER browser)
495 {
496     return browser->helpUrl;
497 }
498 
499 void
swHelpBrowserPath(SHBROWSER browser,const char * path,SWND wnd)500 swHelpBrowserPath(SHBROWSER browser, const char *path, SWND wnd)
501 {
502     helpBrowserRemote(browser, path, wnd);
503 }
504 
505 
506 void
swHelpBrowserVRML(SHBROWSER browser,const char * selection_string,int isCover,SWND wnd)507 swHelpBrowserVRML(SHBROWSER browser, const char* selection_string,
508                   int isCover, SWND wnd)
509 {
510     int pathLen=strlen(browser->vrmlUrl);
511     const char *coverFile="/coverNodes/nodesRef.html";
512     char* path;
513     if (isCover)
514         pathLen=strlen(browser->helpUrl)+strlen(coverFile)+1;
515     path=malloc(pathLen+strlen(selection_string)+2);
516     if (isCover) {
517        strcpy(path, browser->helpUrl);
518        strcat(path, coverFile);
519     } else
520        strcpy(path,browser->vrmlUrl);
521     strcat(path,"#");
522     strcat(path,selection_string);
523     helpBrowserRemote(browser, path , wnd);
524     free(path);
525 }
526 
527 void
swHelpBrowserX3d(SHBROWSER browser,const char * string,SWND wnd)528 swHelpBrowserX3d(SHBROWSER browser, const char* string, SWND wnd)
529 {
530     int pathLen=strlen(browser->x3dUrl);
531     char *path=malloc(pathLen+strlen(string)+2);
532     strcpy(path,browser->x3dUrl);
533     strcat(path,string);
534     helpBrowserRemote(browser, path , wnd);
535     free(path);
536 }
537 
538 void
swHelpBrowserShutdown(SHBROWSER browser)539 swHelpBrowserShutdown(SHBROWSER browser)
540 {
541     if (!browser) return;
542 
543     if (browser->pid != 0) {
544         kill(browser->pid, SIGTERM);
545         waitForProcess(browser->pid);
546     }
547     free(browser->helpCommand);
548     free(browser->helpUrl);
549     free(browser->vrmlUrl);
550     free(browser->x3dUrl);
551     free(browser);
552 }
553 
554 int
helpBrowserRemote(SHBROWSER browser,const char * path,SWND wnd)555 helpBrowserRemote(SHBROWSER browser, const char *path, SWND wnd)
556 {
557     char url[1024];
558     char arg[1024];
559     char command[1024];
560     pid_t pid;
561     int i;
562 
563     if (path[0] == '/')
564         mysnprintf(url, 1023, "file://%s", path);
565     else
566         mysnprintf(url, 1023, path);
567     mysnprintf(arg, 1023, browser->helpCommand, url);
568     pid = createSimpleProcess(arg);
569     /* if failed, search first string (till blank) as command */
570     if (waitForProcess(pid)==0) {
571         for (i=0;(i<strlen(browser->helpCommand)) && (i<1024-3);i++) {
572             command[i]=browser->helpCommand[i];
573             if ((browser->helpCommand[i]  !=' ') &&
574                 (browser->helpCommand[i+1]==' ')) {
575                 i++;
576                 break;
577             }
578         }
579         command[i]=0;
580         strcat(command," %s");
581         mysnprintf(arg, 1024, command, path);
582         browser->pid = createProcess(arg, wnd);
583     }
584     if (browser->pid != 0) {
585         return TRUE;
586     } else {
587         return FALSE;
588     }
589 }
590 
591 
592 /****************/
593 /* text editor */
594 /**************/
595 
596 static int fdpipe_message[2];
597 static int fdpipe_close[2];
598 
599 int
swCheckRunningProcess(void)600 swCheckRunningProcess(void)
601 {
602     char message[2] = { 'l' , '\0' };
603     /* check if there is something in the pipe (process ended) */
604     int byteFromPipe = 0;
605     if (read(fdpipe_message[0],message,1) == 1)
606         byteFromPipe = 1;
607     if (byteFromPipe) {
608         while (write(fdpipe_close[1], message, 1) == -1)
609         /*
610            send notification to other process
611            (otherwise data possibly would die with close of pipe)
612         */
613         close(fdpipe_close[1]);
614         close(fdpipe_message[0]);
615 
616     }
617     return !byteFromPipe;
618 }
619 
620 int
swCreateCheckableProcess(const char * cmdline)621 swCreateCheckableProcess(const char *cmdline)
622 {
623     char message[2] = { 'l' , '\0' };
624     pid_t       pid;
625 
626     if (pipe(fdpipe_message) != 0) return -1;
627 
628     if (pipe(fdpipe_close) != 0) {
629         close(fdpipe_message[0]);
630         close(fdpipe_message[1]);
631         return -1;
632     }
633 
634     /* switch to non blocking io for pipe of first message */
635     fcntl(fdpipe_message[0],F_SETFL,O_NONBLOCK);
636     fcntl(fdpipe_message[1],F_SETFL,O_NONBLOCK);
637 
638     pid = fork();
639     switch(pid) {
640       case -1:
641         /* error */
642         close(fdpipe_message[0]);
643         close(fdpipe_message[1]);
644         close(fdpipe_close[0]);
645         close(fdpipe_close[1]);
646         return -1;
647       case 0:
648         /* child process */
649         close(fdpipe_message[0]);
650         close(fdpipe_close[1]);
651         if (system(cmdline)!=0) {
652             if (fprintf(stderr,"failed: %s\n",cmdline)==0) {}
653         }
654         /* send message to pipe */
655         while (write(fdpipe_message[1],message,1)==-1);
656         /* wait for notification */
657         while (read(fdpipe_close[0],message,1)==-1);
658         close(fdpipe_message[1]);
659         close(fdpipe_close[0]);
660 #ifdef EXIT_HANDLER
661         _exit(0);
662 #else
663         exit(0);
664 #endif
665       default:
666         /* parent process */
667         close(fdpipe_message[1]);
668         close(fdpipe_close[0]);
669         break;
670     }
671     return 0;
672 }
673 
674 typedef struct STextedit {
675     STABLE prefs;
676     char  *textEditCommand;
677     char  *textEditLinenumberOption;
678     int   textEditUseExtensionTxt;
679     char  *imageEditCommand;
680     char  *imageEdit4KidsCommand;
681     char  *soundEditCommand;
682     char  *movieEditCommand;
683 } STextedit;
684 
685 
686 STEXTEDIT
swTextEditInit(STABLE prefs)687 swTextEditInit(STABLE prefs)
688 {
689     char *editor = NULL;
690     STextedit *textEdit = malloc(sizeof(STextedit));
691     textEdit->prefs = prefs;
692 
693     if (getenv("WINEDITOR") != NULL) {
694         textEdit->textEditCommand = mystrdup(swGetPreference(
695               prefs, "TextEditCommand", getenv("WINEDITOR")));
696         textEdit->textEditLinenumberOption = mystrdup(swGetPreference(
697               prefs, "TextEditLinenumberOption", "+"));
698     } else if (getenv("EDITOR") != NULL) {
699         editor = getenv("EDITOR");
700         textEdit->textEditLinenumberOption = mystrdup(swGetPreference(
701               prefs, "TextEditLinenumberOption", "+"));
702     } else {
703 #ifndef MACOSX
704         editor = "vi";
705         textEdit->textEditLinenumberOption = mystrdup(swGetPreference(
706               prefs, "TextEditLinenumberOption", "+"));
707 #else
708         /*
709            typical MacOS X users would die if they should use vi,
710            but the normal MacOS X textEditor:
711            "/usr/bin/open /Applications/TextEdit.app"
712            is useless here, cause it can not wait for the completion of editing
713          */
714         textEdit->textEditCommand = mystrdup(swGetPreference(
715               prefs, "TextEditCommand", "/usr/X11R6/bin/xedit"));
716         textEdit->textEditLinenumberOption = mystrdup(swGetPreference(
717               prefs, "TextEditLinenumberOption", ""));
718 #endif
719     }
720 #ifdef HAVE_X11_EDITOR
721     textEdit->textEditCommand = mystrdup(swGetPreference(prefs,
722          "TextEditCommand", HAVE_X11_EDITOR));
723 #else
724     if (editor != NULL) {
725         const char *term = TERM;
726         const char *executeoption = " -e ";
727         char *command;
728         command = (char *) malloc(strlen(term) + strlen(executeoption) +
729                                   strlen(editor) + 1);
730         strcpy(command, term);
731         strcat(command, executeoption);
732         strcat(command, editor);
733 
734         textEdit->textEditCommand = mystrdup(swGetPreference(prefs,
735               "TextEditCommand", command));
736     }
737 #endif
738     textEdit->textEditUseExtensionTxt = swGetIntPreference(
739           prefs, "TextEditUseExtensionTxt", 1);
740     textEdit->imageEditCommand = mystrdup(swGetPreference(
741           prefs, "ImageEditCommand", HAVE_IMAGE_EDITOR));
742     textEdit->imageEdit4KidsCommand = mystrdup(swGetPreference(
743           prefs, "ImageEdit4KidsCommand", HAVE_IMAGE_EDITOR4KIDS));
744     textEdit->soundEditCommand = mystrdup(swGetPreference(
745           prefs, "SoundEditCommand", HAVE_SOUND_EDITOR));
746     textEdit->movieEditCommand = mystrdup(swGetPreference(
747           prefs, "MovieEditCommand", HAVE_MOVIE_EDITOR));
748 
749     return textEdit;
750 }
751 
swTextEditGetSettingsUseExtensionTxt(STEXTEDIT textEdit,int * textEditUseExtensionTxt)752 void swTextEditGetSettingsUseExtensionTxt(STEXTEDIT textEdit,
753                                           int *textEditUseExtensionTxt)
754 {
755     *textEditUseExtensionTxt = textEdit->textEditUseExtensionTxt;
756 }
757 
758 void
swTextEditGetSettings(STEXTEDIT textEdit,const char ** textEditCommand,const char ** textEditLinenumberOption,int * textEditUseExtensionTxt)759 swTextEditGetSettings(STEXTEDIT textEdit,
760                       const char **textEditCommand,
761                       const char **textEditLinenumberOption,
762                       int *textEditUseExtensionTxt)
763 {
764     *textEditCommand = textEdit->textEditCommand;
765     *textEditLinenumberOption = textEdit->textEditLinenumberOption;
766     *textEditUseExtensionTxt = textEdit->textEditUseExtensionTxt;
767 }
768 
swTextEditGetCommand(STEXTEDIT textEdit)769 char *swTextEditGetCommand(STEXTEDIT textEdit)
770 {
771     return textEdit->textEditCommand;
772 }
773 
swImageEditGetSettings(STEXTEDIT textEdit)774 char *swImageEditGetSettings(STEXTEDIT textEdit)
775 {
776     return textEdit->imageEditCommand;
777 }
778 
swImageEdit4KidsGetSettings(STEXTEDIT textEdit)779 char *swImageEdit4KidsGetSettings(STEXTEDIT textEdit)
780 {
781     return textEdit->imageEdit4KidsCommand;
782 }
783 
swSoundEditGetSettings(STEXTEDIT textEdit)784 char *swSoundEditGetSettings(STEXTEDIT textEdit)
785 {
786     return textEdit->soundEditCommand;
787 }
788 
swMovieEditGetSettings(STEXTEDIT textEdit)789 char *swMovieEditGetSettings(STEXTEDIT textEdit)
790 {
791     return textEdit->movieEditCommand;
792 }
793 
794 void
swTextEditSetSettings(STEXTEDIT textEdit,const char * textEditCommand,const char * textEditLinenumberOption,int textEditUseExtensionTxt)795 swTextEditSetSettings(STEXTEDIT textEdit,
796                       const char *textEditCommand,
797                       const char *textEditLinenumberOption,
798                       int textEditUseExtensionTxt)
799 {
800     free(textEdit->textEditCommand);
801     textEdit->textEditCommand = mystrdup(textEditCommand);
802 
803     free(textEdit->textEditLinenumberOption);
804     textEdit->textEditLinenumberOption = mystrdup(textEditLinenumberOption);
805 
806     textEdit->textEditUseExtensionTxt = textEditUseExtensionTxt;
807 
808     swSetPreference(textEdit->prefs, "TextEditCommand",
809                     textEdit->textEditCommand);
810     swSetPreference(textEdit->prefs, "TextEditLinenumberOption",
811                     textEdit->textEditLinenumberOption);
812     swSetIntPreference(textEdit->prefs, "TextEditUseExtensionTxt",
813                        textEdit->textEditUseExtensionTxt);
814 }
815 
816 void
swImageEditSetSettings(STEXTEDIT textEdit,const char * imageEditCommand)817 swImageEditSetSettings(STEXTEDIT textEdit,
818                        const char *imageEditCommand)
819 {
820     free(textEdit->imageEditCommand);
821     textEdit->imageEditCommand = mystrdup(imageEditCommand);
822     swSetPreference(textEdit->prefs, "ImageEditCommand",
823                     textEdit->imageEditCommand);
824 }
825 
826 void
swImageEdit4KidsSetSettings(STEXTEDIT textEdit,const char * imageEditCommand)827 swImageEdit4KidsSetSettings(STEXTEDIT textEdit,
828                             const char *imageEditCommand)
829 {
830     free(textEdit->imageEdit4KidsCommand);
831     textEdit->imageEdit4KidsCommand = mystrdup(imageEditCommand);
832     swSetPreference(textEdit->prefs, "ImageEdit4KidsCommand",
833                     textEdit->imageEdit4KidsCommand);
834 }
835 
836 void
swSoundEditSetSettings(STEXTEDIT textEdit,const char * soundEditCommand)837 swSoundEditSetSettings(STEXTEDIT textEdit,
838                        const char *soundEditCommand)
839 {
840     free(textEdit->soundEditCommand);
841     textEdit->soundEditCommand = mystrdup(soundEditCommand);
842     swSetPreference(textEdit->prefs, "SoundEditCommand",
843                     textEdit->soundEditCommand);
844 }
845 
846 void
swMovieEditSetSettings(STEXTEDIT textEdit,const char * movieEditCommand)847 swMovieEditSetSettings(STEXTEDIT textEdit,
848                        const char *movieEditCommand)
849 {
850     free(textEdit->movieEditCommand);
851     textEdit->movieEditCommand = mystrdup(movieEditCommand);
852     swSetPreference(textEdit->prefs, "MovieEditCommand",
853                     textEdit->movieEditCommand);
854 }
855 
856 
857 /**********/
858 /* upload */
859 /**********/
860 
861 typedef struct SUpload {
862     STABLE prefs;
863     char  *commandline;
864     char  *htmlTag;
865     char  *password;
866 } SUpload;
867 
868 SUPLOAD
swUploadInit(STABLE prefs)869 swUploadInit(STABLE prefs)
870 {
871     SUpload *upload = malloc(sizeof(SUpload));
872     upload->prefs = prefs;
873     upload->commandline = mystrdup(swGetPreference(prefs, "UploadCommandLine",
874                                                    ""));
875     upload->htmlTag = mystrdup(swGetPreference(prefs, "UploadHtmlTags",
876                                                ""));
877     /* do not read/store password for security reasons */
878     upload->password = malloc(1024);
879     upload->password[0] = 0;
880 #ifdef HAS_MLOCK
881     mlock(upload->password, 1024);
882 #endif
883     return upload;
884 }
885 
886 void
swUploadGetSettings(SUPLOAD upload,const char ** commandline,const char ** htmlTag,const char ** password)887 swUploadGetSettings(SUPLOAD upload,
888                     const char **commandline,
889                     const char **htmlTag,
890                     const char **password)
891 {
892     *commandline = upload->commandline;
893     *htmlTag = upload->htmlTag;
894     *password = upload->password;
895 }
896 
897 void
swUploadSetSettings(SUPLOAD upload,const char * commandline,const char * htmlTag,const char * password)898 swUploadSetSettings(SUPLOAD upload,
899                     const char *commandline,
900                     const char *htmlTag,
901                     const char *password)
902 {
903     free(upload->commandline);
904     free(upload->htmlTag);
905 
906     upload->commandline = mystrdup(commandline);
907     upload->htmlTag = mystrdup(htmlTag);
908     if (password != NULL)
909         mystrncpy_secure(upload->password, password, 1023);
910     else
911         upload->password[0] = 0;
912 
913     swSetPreference(upload->prefs, "UploadCommandLine", upload->commandline);
914     swSetPreference(upload->prefs, "UploadHtmlTags", upload->htmlTag);
915     /* do not read/store password for security reasons */
916 }
917 
918 int
swHasUpload(SUPLOAD upload)919 swHasUpload(SUPLOAD upload)
920 {
921     if (strlen(upload->commandline) > 0)
922         return 1;
923     else
924         return 0;
925 }
926 
927 char*
swUpload(SUPLOAD upload,char * fileToUpload,SHBROWSER browser,SWND wnd)928 swUpload(SUPLOAD upload, char *fileToUpload, SHBROWSER browser, SWND wnd)
929 {
930     static char uploadCommand[1024];
931     FILE *cmd;
932     int f = -1;
933     int i;
934     int needPassword = 0;
935     static char htmlTags[1024];
936     char *htmlpath = (char *) malloc(1024);
937     htmlpath[0] = 0;
938 
939     if ((upload->password != NULL) && (strlen(upload->password) != 0))
940         if (strstr(upload->commandline, "%s")  !=  NULL)
941             if (strstr(strstr(upload->commandline, "%s") + 2, "%s") !=  NULL)
942                 needPassword = 1; /* if commandline has two %s */
943 #ifdef HAS_MLOCK
944     mlock(uploadCommand, 1024);
945 #endif
946     if (needPassword)
947         mysnprintf(uploadCommand, 1023, upload->commandline, upload->password,
948                    fileToUpload);
949     else
950         mysnprintf(uploadCommand, 1023, upload->commandline, fileToUpload, "");
951 
952     if ((cmd = popen(uploadCommand, "w")) != NULL) {
953         if ((upload->password != NULL) && (strlen(upload->password) != 0))
954             fputs(upload->password, cmd);
955         if (pclose(cmd) != 0) {
956             swMessageBox(wnd, "upload failed", "Upload failed",
957                          SW_MB_OK, SW_MB_WARNING);
958             htmlpath[0] = 0;
959             return htmlpath;
960         }
961     }
962 
963     swGetTempPath(htmlpath, ".dune_upload_reload", ".html", 1024);
964     f = open(htmlpath, O_WRONLY | O_CREAT, 00666);
965     if (f == -1) {
966         swMessageBox(wnd, "open of html file failed", "Upload reload error",
967                      SW_MB_OK, SW_MB_WARNING);
968         htmlpath[0] = 0;
969         return htmlpath;
970     }
971     if ((upload->password != NULL) && (strlen(upload->password) != 0))
972         mysnprintf(htmlTags, 1023, upload->htmlTag, upload->password);
973     else
974         mysnprintf(htmlTags, 1023, upload->htmlTag, "");
975     if (write(f, htmlTags, sizeof(htmlTags)) != sizeof(htmlTags)) {
976         swMessageBox(wnd, "open of html file failed", "Upload reload error",
977                      SW_MB_OK, SW_MB_WARNING);
978         return htmlpath;
979     }
980     close(f);
981     helpBrowserRemote(browser, htmlpath, wnd);
982     for (i = 0; i < 1024; i++)
983         uploadCommand[i] = (char) 0;
984 #ifdef HAS_MLOCK
985     munlock(uploadCommand, 1024);
986 #endif
987     return htmlpath;
988 }
989 
990 void
swUploadCleanupPasswd(SUPLOAD upload)991 swUploadCleanupPasswd(SUPLOAD upload)
992 {
993     int i;
994     for (i = 0; i < strlen(upload->password); i++)
995         upload->password[i] = (char) 0;
996 #ifdef HAS_MLOCK
997     munlock(upload->password, 1024);
998 #endif
999 }
1000