~ubuntu-branches/ubuntu/warty/lynx/warty-security

« back to all changes in this revision

Viewing changes to src/LYLocal.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2004-09-16 12:14:10 UTC
  • Revision ID: james.westby@ubuntu.com-20040916121410-cz1gu92c4nqfeyrg
Tags: upstream-2.8.5
ImportĀ upstreamĀ versionĀ 2.8.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
**  Routines to manipulate the local filesystem.
 
3
**  Written by: Rick Mallett, Carleton University
 
4
**  Report problems to rmallett@ccs.carleton.ca
 
5
**  Modified 18-Dec-95 David Trueman (david@cs.dal.ca):
 
6
**      Added OK_PERMIT compilation option.
 
7
**      Support replacement of compiled-in f)ull menu configuration via
 
8
**        DIRED_MENU definitions in lynx.cfg, so that more than one menu
 
9
**        can be driven by the same executable.
 
10
**  Modified Oct-96 Klaus Weide (kweide@tezcat.com):
 
11
**      Changed to use the library's HTList_* functions and macros for
 
12
**        managing the list of tagged file URLs.
 
13
**      Keep track of proper level of URL escaping, so that unusual filenames
 
14
**        which contain #% etc. are handled properly (some HTUnEscapeSome()'s
 
15
**        left in to be conservative, and to document where superfluous
 
16
**        unescaping took place before).
 
17
**      Dynamic memory instead of fixed length buffers in a few cases.
 
18
**      Other minor changes to make things work as intended.
 
19
**  Modified Jun-97 Klaus Weide (kweide@tezcat.com) & FM:
 
20
**      Modified the code handling DIRED_MENU to do more careful
 
21
**        checking of the selected file.  In addition to "TAG", "FILE", and
 
22
**        "DIR", DIRED_MENU definitions in lynx.cfg now also recognize LINK as
 
23
**        a type.  DIRED_MENU definitions with a type field of "LINK" are only
 
24
**        used if the current selection is a symbolic link ("FILE" and "DIR"
 
25
**        definitions are not used in that case).  The default menu
 
26
**        definitions have been updated to reflect this change, and to avoid
 
27
**        the showing of menu items whose action would always fail - KW
 
28
**      Cast all code into the Lynx programming style. - FM
 
29
*/
 
30
 
 
31
#include <HTUtils.h>
 
32
#include <HTAAProt.h>
 
33
#include <HTFile.h>
 
34
#include <HTAlert.h>
 
35
#include <HTParse.h>
 
36
#include <LYCurses.h>
 
37
#include <LYGlobalDefs.h>
 
38
#include <LYUtils.h>
 
39
#include <LYStrings.h>
 
40
#include <LYCharUtils.h>
 
41
#include <LYStructs.h>
 
42
#include <LYHistory.h>
 
43
#include <LYUpload.h>
 
44
#include <LYLocal.h>
 
45
#include <LYClean.h>
 
46
#include <www_wait.h>
 
47
 
 
48
#ifdef SUPPORT_CHDIR
 
49
#include <LYMainLoop.h>
 
50
#endif
 
51
 
 
52
#include <LYLeaks.h>
 
53
 
 
54
#undef USE_COMPRESS
 
55
 
 
56
#ifdef __DJGPP__
 
57
#define EXT_TAR_GZ ".tgz"
 
58
#define EXT_TAR_Z  ".taz"
 
59
#define EXT_Z      ".z"
 
60
#else
 
61
#define EXT_TAR_GZ ".tar.gz"
 
62
#define EXT_TAR_Z  ".tar.Z"
 
63
#define EXT_Z      ".Z"
 
64
#endif
 
65
 
 
66
#ifndef DIRED_MAXBUF
 
67
#define DIRED_MAXBUF 512
 
68
#endif
 
69
 
 
70
#ifdef DIRED_SUPPORT
 
71
 
 
72
#ifdef OK_INSTALL
 
73
#ifdef FNAMES_8_3
 
74
#define INSTALLDIRS_FILE "instdirs.htm"
 
75
#else
 
76
#define INSTALLDIRS_FILE ".installdirs.html"
 
77
#endif /* FNAMES_8_3 */
 
78
#endif /* OK_INSTALL */
 
79
 
 
80
PRIVATE char *get_filename PARAMS((
 
81
        char *          prompt,
 
82
        char *          buf,
 
83
        size_t          bufsize));
 
84
 
 
85
#ifdef OK_PERMIT
 
86
PRIVATE int permit_location PARAMS((
 
87
        char *          destpath,
 
88
        char *          srcpath,
 
89
        char **         newpath));
 
90
#endif /* OK_PERMIT */
 
91
 
 
92
PRIVATE char *render_item PARAMS((
 
93
        CONST char *    s,
 
94
        CONST char *    path,
 
95
        CONST char *    dir,
 
96
        char *          buf,
 
97
        int             bufsize,
 
98
        BOOLEAN         url_syntax));
 
99
 
 
100
PRIVATE struct dired_menu *menu_head = NULL;
 
101
struct dired_menu {
 
102
    int cond;
 
103
#define DE_TAG     1
 
104
#define DE_DIR     2
 
105
#define DE_FILE    3
 
106
#define DE_SYMLINK 4
 
107
    char *sfx;
 
108
    char *link;
 
109
    char *rest;
 
110
    char *href;
 
111
    struct dired_menu *next;
 
112
} defmenu[] = {
 
113
 
 
114
/*
 
115
 *  The following initializations determine the contents of the f)ull menu
 
116
 *  selection when in dired mode.  If any menu entries are defined in the
 
117
 *  configuration file via DIRED_MENU lines, then these default entries
 
118
 *  are discarded entirely.
 
119
 */
 
120
#ifdef SUPPORT_CHDIR
 
121
{ 0,                  "", "Change directory",
 
122
                      "", "LYNXDIRED://CHDIR",                  NULL },
 
123
#endif
 
124
{ 0,                  "", "New File",
 
125
"(in current directory)", "LYNXDIRED://NEW_FILE%d",             NULL },
 
126
 
 
127
{ 0,                  "", "New Directory",
 
128
"(in current directory)", "LYNXDIRED://NEW_FOLDER%d",           NULL },
 
129
 
 
130
#ifdef OK_INSTALL
 
131
{ DE_FILE,            "", "Install",
 
132
"selected file to new location", "LYNXDIRED://INSTALL_SRC%p",   NULL },
 
133
/* The following (installing a directory) doesn't work for me, at least
 
134
   with the "install" from GNU fileutils 4.0.  I leave it in anyway, in
 
135
   case one compiles with INSTALL_PATH / INSTALL_ARGS defined to some
 
136
   other command for which it works (like a script, or maybe "cp -a"). - kw
 
137
*/
 
138
{ DE_DIR,             "", "Install",
 
139
"selected directory to new location", "LYNXDIRED://INSTALL_SRC%p",      NULL },
 
140
#endif /* OK_INSTALL */
 
141
 
 
142
{ DE_FILE,            "", "Modify File Name",
 
143
"(of current selection)", "LYNXDIRED://MODIFY_NAME%p",          NULL },
 
144
{ DE_DIR,             "", "Modify Directory Name",
 
145
"(of current selection)", "LYNXDIRED://MODIFY_NAME%p",          NULL },
 
146
#ifdef S_IFLNK
 
147
{ DE_SYMLINK,         "", "Modify Name",
 
148
"(of selected symbolic link)", "LYNXDIRED://MODIFY_NAME%p",     NULL },
 
149
#endif  /* S_IFLNK */
 
150
 
 
151
#ifdef OK_PERMIT
 
152
{ DE_FILE,            "", "Modify File Permissions",
 
153
"(of current selection)", "LYNXDIRED://PERMIT_SRC%p",           NULL },
 
154
{ DE_DIR,             "", "Modify Directory Permissions",
 
155
"(of current selection)", "LYNXDIRED://PERMIT_SRC%p",           NULL },
 
156
#endif /* OK_PERMIT */
 
157
 
 
158
{ DE_FILE,            "", "Change Location",
 
159
"(of selected file)"    , "LYNXDIRED://MODIFY_LOCATION%p",      NULL },
 
160
{ DE_DIR,             "", "Change Location",
 
161
"(of selected directory)", "LYNXDIRED://MODIFY_LOCATION%p",     NULL },
 
162
#ifdef S_IFLNK
 
163
{ DE_SYMLINK,         "", "Change Location",
 
164
"(of selected symbolic link)", "LYNXDIRED://MODIFY_LOCATION%p", NULL },
 
165
#endif /* S_IFLNK */
 
166
 
 
167
{ DE_FILE,            "", "Remove File",
 
168
   "(current selection)", "LYNXDIRED://REMOVE_SINGLE%p",        NULL },
 
169
{ DE_DIR,             "", "Remove Directory",
 
170
   "(current selection)", "LYNXDIRED://REMOVE_SINGLE%p",        NULL },
 
171
#ifdef S_IFLNK
 
172
{ DE_SYMLINK,         "", "Remove Symbolic Link",
 
173
   "(current selection)", "LYNXDIRED://REMOVE_SINGLE%p",        NULL },
 
174
#endif /* S_IFLNK */
 
175
 
 
176
#if defined(OK_UUDECODE) && !defined(ARCHIVE_ONLY)
 
177
{ DE_FILE,            "", "UUDecode",
 
178
   "(current selection)", "LYNXDIRED://UUDECODE%p",             NULL },
 
179
#endif /* OK_UUDECODE && !ARCHIVE_ONLY */
 
180
 
 
181
#if defined(OK_TAR) && !defined(ARCHIVE_ONLY)
 
182
{ DE_FILE,      EXT_TAR_Z, "Expand",
 
183
   "(current selection)", "LYNXDIRED://UNTAR_Z%p",              NULL },
 
184
#endif /* OK_TAR && !ARCHIVE_ONLY */
 
185
 
 
186
#if defined(OK_TAR) && defined(OK_GZIP) && !defined(ARCHIVE_ONLY)
 
187
{ DE_FILE,     ".tar.gz", "Expand",
 
188
   "(current selection)", "LYNXDIRED://UNTAR_GZ%p",             NULL },
 
189
 
 
190
{ DE_FILE,        ".tgz", "Expand",
 
191
   "(current selection)", "LYNXDIRED://UNTAR_GZ%p",             NULL },
 
192
#endif /* OK_TAR && OK_GZIP && !ARCHIVE_ONLY */
 
193
 
 
194
#ifndef ARCHIVE_ONLY
 
195
{ DE_FILE,         EXT_Z, "Uncompress",
 
196
   "(current selection)", "LYNXDIRED://DECOMPRESS%p",           NULL },
 
197
#endif /* ARCHIVE_ONLY */
 
198
 
 
199
#if defined(OK_GZIP) && !defined(ARCHIVE_ONLY)
 
200
{ DE_FILE,         ".gz", "Uncompress",
 
201
   "(current selection)", "LYNXDIRED://UNGZIP%p",               NULL },
 
202
#endif /* OK_GZIP && !ARCHIVE_ONLY */
 
203
 
 
204
#if defined(OK_ZIP) && !defined(ARCHIVE_ONLY)
 
205
{ DE_FILE,        ".zip", "Uncompress",
 
206
   "(current selection)", "LYNXDIRED://UNZIP%p",                NULL },
 
207
#endif /* OK_ZIP && !ARCHIVE_ONLY */
 
208
 
 
209
#if defined(OK_TAR) && !defined(ARCHIVE_ONLY)
 
210
{ DE_FILE,        ".tar", "UnTar",
 
211
   "(current selection)", "LYNXDIRED://UNTAR%p",                NULL },
 
212
#endif /* OK_TAR && !ARCHIVE_ONLY */
 
213
 
 
214
#ifdef OK_TAR
 
215
{ DE_DIR,             "", "Tar",
 
216
   "(current selection)", "LYNXDIRED://TAR%p",                  NULL },
 
217
#endif /* OK_TAR */
 
218
 
 
219
#if defined(OK_TAR) && defined(OK_GZIP)
 
220
{ DE_DIR,             "", "Tar and compress",
 
221
      "(using GNU gzip)", "LYNXDIRED://TAR_GZ%p",               NULL },
 
222
#endif /* OK_TAR && OK_GZIP */
 
223
 
 
224
#if defined(OK_TAR) && defined(USE_COMPRESS)
 
225
{ DE_DIR,             "", "Tar and compress",
 
226
      "(using compress)", "LYNXDIRED://TAR_Z%p",                NULL },
 
227
#endif /* OK_TAR && USE_COMPRESS */
 
228
 
 
229
#ifdef OK_ZIP
 
230
{ DE_DIR,             "", "Package and compress",
 
231
           "(using zip)", "LYNXDIRED://ZIP%p",                  NULL },
 
232
#endif /* OK_ZIP */
 
233
 
 
234
{ DE_FILE,            "", "Compress",
 
235
 "(using Unix compress)", "LYNXDIRED://COMPRESS%p",             NULL },
 
236
 
 
237
#ifdef OK_GZIP
 
238
{ DE_FILE,            "", "Compress",
 
239
          "(using gzip)", "LYNXDIRED://GZIP%p",                 NULL },
 
240
#endif /* OK_GZIP */
 
241
 
 
242
#ifdef OK_ZIP
 
243
{ DE_FILE,            "", "Compress",
 
244
           "(using zip)", "LYNXDIRED://ZIP%p",                  NULL },
 
245
#endif /* OK_ZIP */
 
246
 
 
247
{ DE_TAG,             "", "Move all tagged items to another location.",
 
248
                      "", "LYNXDIRED://MOVE_TAGGED%d",          NULL },
 
249
 
 
250
#ifdef OK_INSTALL
 
251
{ DE_TAG,             "", "Install tagged files into another directory.",
 
252
                      "", "LYNXDIRED://INSTALL_SRC%00",         NULL },
 
253
#endif
 
254
 
 
255
{ DE_TAG,             "", "Remove all tagged files and directories.",
 
256
                      "", "LYNXDIRED://REMOVE_TAGGED",          NULL },
 
257
 
 
258
{ DE_TAG,             "", "Untag all tagged files and directories.",
 
259
                      "", "LYNXDIRED://CLEAR_TAGGED",           NULL },
 
260
 
 
261
{ 0,                NULL, NULL,
 
262
                    NULL, NULL,                                 NULL }
 
263
};
 
264
 
 
265
PRIVATE BOOLEAN cannot_stat ARGS1(CONST char *, name)
 
266
{
 
267
    char *tmpbuf = 0;
 
268
    HTSprintf0(&tmpbuf, gettext("Unable to get status of '%s'."), name);
 
269
    HTAlert(tmpbuf);
 
270
    FREE(tmpbuf);
 
271
    return FALSE;
 
272
}
 
273
 
 
274
#define OK_STAT(name, sb) (stat(name, sb) == 0)
 
275
 
 
276
PRIVATE BOOLEAN ok_stat ARGS2(CONST char *, name, struct stat*, sb)
 
277
{
 
278
    CTRACE((tfp, "testing ok_stat(%s)\n", name));
 
279
    if (!OK_STAT(name, sb)) {
 
280
        return cannot_stat(name);
 
281
    }
 
282
    return TRUE;
 
283
}
 
284
 
 
285
#ifdef HAVE_LSTAT
 
286
PRIVATE BOOLEAN ok_lstat ARGS2(char *, name, struct stat*, sb)
 
287
{
 
288
    CTRACE((tfp, "testing ok_lstat(%s)\n", name));
 
289
    if (lstat(name, sb) < 0) {
 
290
        return cannot_stat(name);
 
291
    }
 
292
    return TRUE;
 
293
}
 
294
#else
 
295
#define ok_lstat(name,sb) ok_stat(name,sb)
 
296
#endif
 
297
 
 
298
PRIVATE BOOLEAN ok_file_or_dir ARGS1(struct stat*, sb)
 
299
{
 
300
    if (!S_ISDIR(sb->st_mode)
 
301
     && !S_ISREG(sb->st_mode)) {
 
302
        HTAlert(gettext("The selected item is not a file or a directory!  Request ignored."));
 
303
        return FALSE;
 
304
    }
 
305
    return TRUE;
 
306
}
 
307
 
 
308
#ifdef OK_INSTALL               /* currently only used in local_install */
 
309
PRIVATE BOOLEAN ok_localname ARGS2(char*, dst, CONST char*, src)
 
310
{
 
311
    struct stat dir_info;
 
312
 
 
313
    if (!ok_stat(src, &dir_info)
 
314
     || !ok_file_or_dir(&dir_info)) {
 
315
        return FALSE;
 
316
    }
 
317
    if (strlen(src) >= DIRED_MAXBUF) {
 
318
        CTRACE((tfp, "filename too long in ok_localname!\n"));
 
319
        return FALSE;
 
320
    }
 
321
    strcpy(dst, src);
 
322
    return TRUE;
 
323
}
 
324
#endif /* OK_INSTALL */
 
325
 
 
326
/*
 
327
 *  Execute DIRED command, return -1 or 0 on failure, 1 success.
 
328
 */
 
329
PRIVATE int LYExecv ARGS3(
 
330
        CONST char *,   path,
 
331
        char **,        argv,
 
332
        char *,         msg)
 
333
{
 
334
    int rc = 0;
 
335
#if defined(VMS) || defined(_WINDOWS)
 
336
    CTRACE((tfp, "LYExecv:  Called inappropriately! (path=%s)\n", path));
 
337
#else
 
338
    int n;
 
339
    char *tmpbuf = 0;
 
340
#ifdef __DJGPP__
 
341
    stop_curses();
 
342
    HTSprintf0(&tmpbuf, "%s", path);
 
343
    for (n = 1; argv[n] != 0; n++)
 
344
        HTSprintf(&tmpbuf, " %s", argv[n]);
 
345
    HTSprintf(&tmpbuf, "\n");
 
346
    rc = LYSystem(tmpbuf) ? 0 : 1;
 
347
#else
 
348
    int pid;
 
349
#ifdef HAVE_TYPE_UNIONWAIT
 
350
    union wait wstatus;
 
351
#else
 
352
    int wstatus;
 
353
#endif
 
354
 
 
355
    if (TRACE) {
 
356
        CTRACE((tfp, "LYExecv path='%s'\n", path));
 
357
        for (n = 0; argv[n] != 0; n++)
 
358
            CTRACE((tfp, "argv[%d] = '%s'\n", n, argv[n]));
 
359
    }
 
360
 
 
361
    rc = 1;             /* It will work */
 
362
    stop_curses();
 
363
    pid = fork();       /* fork and execute command */
 
364
 
 
365
    switch (pid) {
 
366
        case -1:
 
367
            HTSprintf0(&tmpbuf, gettext("Unable to %s due to system error!"), msg);
 
368
            rc = 0;
 
369
            break;      /* don't fall thru! - KW */
 
370
 
 
371
        case 0:  /* child */
 
372
#ifdef USE_EXECVP
 
373
            execvp(path, argv); /* this uses our $PATH */
 
374
#else
 
375
            execv(path, argv);
 
376
#endif
 
377
            exit(EXIT_FAILURE); /* execv failed, give wait() something to look at */
 
378
            /*NOTREACHED*/
 
379
 
 
380
        default:  /* parent */
 
381
#if !HAVE_WAITPID
 
382
            while (wait(&wstatus) != pid)
 
383
                ; /* do nothing */
 
384
#else
 
385
            while (-1 == waitpid(pid, &wstatus, 0)) { /* wait for child */
 
386
#ifdef EINTR
 
387
                if (errno == EINTR)
 
388
                    continue;
 
389
#endif /* EINTR */
 
390
#ifdef ERESTARTSYS
 
391
                if (errno == ERESTARTSYS)
 
392
                    continue;
 
393
#endif /* ERESTARTSYS */
 
394
                break;
 
395
            }
 
396
#endif /* !HAVE_WAITPID */
 
397
            if ((WIFEXITED(wstatus)
 
398
              && (WEXITSTATUS(wstatus) != 0))
 
399
             || (WIFSIGNALED(wstatus)
 
400
              && (WTERMSIG(wstatus) > 0)))      { /* error return */
 
401
                HTSprintf0(&tmpbuf, gettext("Probable failure to %s due to system error!"),
 
402
                                   msg);
 
403
                rc = 0;
 
404
            }
 
405
    }
 
406
#endif /* __DJGPP__ */
 
407
 
 
408
    if (rc == 0) {
 
409
        /*
 
410
         *  Screen may have message from the failed execv'd command.
 
411
         *  Give user time to look at it before screen refresh.
 
412
         */
 
413
        LYSleepAlert();
 
414
    }
 
415
    start_curses();
 
416
    if (tmpbuf != 0) {
 
417
        if (rc == 0)
 
418
            HTAlert(tmpbuf);
 
419
        FREE(tmpbuf);
 
420
    }
 
421
 
 
422
#endif /* VMS || _WINDOWS */
 
423
    return(rc);
 
424
}
 
425
 
 
426
PRIVATE int make_directory ARGS1(char *, path)
 
427
{
 
428
    int code;
 
429
    CONST char *program;
 
430
 
 
431
    if ((program = HTGetProgramPath(ppMKDIR)) != NULL) {
 
432
        char *args[5];
 
433
        char *msg = 0;
 
434
 
 
435
        HTSprintf0(&msg,"make directory %s", path);
 
436
        args[0] = "mkdir";
 
437
        args[1] = path;
 
438
        args[2] = (char *) 0;
 
439
        code = (LYExecv(program, args, msg) <= 0) ? -1 : 1;
 
440
        FREE(msg);
 
441
    } else {
 
442
#ifdef _WINDOWS
 
443
        code = mkdir(path) ? -1 : 1;
 
444
#else
 
445
        code = mkdir(path, 0777) ? -1 : 1;
 
446
#endif
 
447
    }
 
448
    return (code);
 
449
}
 
450
 
 
451
PRIVATE int remove_file ARGS1(char *, path)
 
452
{
 
453
    int code;
 
454
    CONST char *program;
 
455
 
 
456
    if ((program = HTGetProgramPath(ppRM)) != NULL) {
 
457
        char *args[5];
 
458
        char *tmpbuf = NULL;
 
459
 
 
460
        args[0] = "rm";
 
461
        args[1] = "-f";
 
462
        args[2] = path;
 
463
        args[3] = (char *) 0;
 
464
        HTSprintf0(&tmpbuf, gettext("remove %s"), path);
 
465
        code = LYExecv(program, args, tmpbuf);
 
466
        FREE(tmpbuf);
 
467
    } else {
 
468
        code = remove(path) ? -1 : 1;
 
469
    }
 
470
    return (code);
 
471
}
 
472
 
 
473
PRIVATE int remove_directory ARGS1(char *, path)
 
474
{
 
475
    int code;
 
476
    CONST char *program;
 
477
 
 
478
    if ((program = HTGetProgramPath(ppRMDIR)) != NULL) {
 
479
        char *args[5];
 
480
        char *tmpbuf = NULL;
 
481
 
 
482
        args[0] = "rmdir";
 
483
        args[1] = path;
 
484
        args[2] = (char *) 0;
 
485
        HTSprintf0(&tmpbuf, gettext("remove %s"), path);
 
486
        code = LYExecv(program, args, tmpbuf);
 
487
        FREE(tmpbuf);
 
488
    } else {
 
489
        code = rmdir(path) ? -1 : 1;
 
490
    }
 
491
    return (code);
 
492
}
 
493
 
 
494
PRIVATE int touch_file ARGS1(char *, path)
 
495
{
 
496
    int code;
 
497
    CONST char *program;
 
498
 
 
499
    if ((program = HTGetProgramPath(ppTOUCH)) != NULL) {
 
500
        char *args[5];
 
501
        char *msg = NULL;
 
502
 
 
503
        HTSprintf0(&msg, gettext("touch %s"), path);
 
504
        args[0] = "touch";
 
505
        args[1] = path;
 
506
        args[2] = (char *) 0;
 
507
        code = (LYExecv(program, args, msg) <= 0) ? -1 : 1;
 
508
        FREE(msg);
 
509
    } else {
 
510
        FILE *fp;
 
511
        if ((fp = fopen(path, "w")) != 0) {
 
512
            fclose(fp);
 
513
            code = 1;
 
514
        } else {
 
515
            code = -1;
 
516
        }
 
517
    }
 
518
    return (code);
 
519
}
 
520
 
 
521
PRIVATE int move_file ARGS2(char *, source, char *, target)
 
522
{
 
523
    int code;
 
524
    CONST char *program;
 
525
 
 
526
    if ((program = HTGetProgramPath(ppMV)) != NULL) {
 
527
        char *msg = 0;
 
528
        char *args[5];
 
529
 
 
530
        HTSprintf0(&msg, gettext("move %s to %s"), source, target);
 
531
        args[0] = "mv";
 
532
        args[1] = source;
 
533
        args[2] = target;
 
534
        args[3] = (char *) 0;
 
535
        code = (LYExecv(program, args, msg) <= 0) ? -1 : 1;
 
536
        FREE(msg);
 
537
    } else {
 
538
        struct stat sb;
 
539
        char *actual = 0;
 
540
        /* the caller sets up a target directory; we need a file path */
 
541
        if (stat(target, &sb) == 0
 
542
         && S_ISDIR(sb.st_mode)) {
 
543
            HTSprintf0(&actual, "%s/%s", target, LYPathLeaf(source));
 
544
            CTRACE((tfp, "move_file source=%s, target=%s\n", source, target));
 
545
            target = actual;
 
546
        }
 
547
        if ((code = rename(source, target)) != 0)
 
548
            if ((code = LYCopyFile(source, target)) >= 0)
 
549
                code = remove(source);
 
550
        if (code == 0)
 
551
            code = 1;
 
552
        if (actual != target) {
 
553
            FREE(actual);
 
554
        }
 
555
    }
 
556
    return code;
 
557
}
 
558
 
 
559
PRIVATE BOOLEAN not_already_exists ARGS1(char *, name)
 
560
{
 
561
    struct stat dir_info;
 
562
 
 
563
    if (!OK_STAT(name, &dir_info)) {
 
564
        if (errno != ENOENT) {
 
565
            cannot_stat(name);
 
566
        } else {
 
567
            return TRUE;
 
568
        }
 
569
    } else if (S_ISDIR(dir_info.st_mode)) {
 
570
        HTAlert(gettext("There is already a directory with that name!  Request ignored."));
 
571
    } else if (S_ISREG(dir_info.st_mode)) {
 
572
        HTAlert(gettext("There is already a file with that name!  Request ignored."));
 
573
    } else {
 
574
        HTAlert(gettext("The specified name is already in use!  Request ignored."));
 
575
    }
 
576
    return FALSE;
 
577
}
 
578
 
 
579
PRIVATE BOOLEAN dir_has_same_owner ARGS2(struct stat *, info, int, owner)
 
580
{
 
581
    if (S_ISDIR(info->st_mode)) {
 
582
        if ((int) info->st_uid == owner) {
 
583
            return TRUE;
 
584
        } else {
 
585
            HTAlert(gettext("Destination has different owner!  Request denied."));
 
586
        }
 
587
    } else {
 
588
        HTAlert(gettext("Destination is not a valid directory!  Request denied."));
 
589
    }
 
590
    return FALSE;
 
591
}
 
592
 
 
593
/*
 
594
 *  Remove all tagged files and directories.
 
595
 */
 
596
PRIVATE int remove_tagged NOARGS
 
597
{
 
598
    int ans;
 
599
    BOOL will_clear = TRUE;
 
600
    char *cp;
 
601
    char *tmpbuf = NULL;
 
602
    char *testpath = NULL;
 
603
    struct stat dir_info;
 
604
    int count;
 
605
    HTList *tag;
 
606
 
 
607
    if (HTList_isEmpty(tagged))  /* should never happen */
 
608
        return 0;
 
609
 
 
610
    ans = HTConfirm(gettext("Remove all tagged files and directories?"));
 
611
 
 
612
    count = 0;
 
613
    tag = tagged;
 
614
    while (ans == YES && (cp = (char *)HTList_nextObject(tag)) != NULL) {
 
615
        if (is_url(cp) == FILE_URL_TYPE) { /* unnecessary check */
 
616
            testpath = HTfullURL_toFile(cp);
 
617
            LYTrimPathSep(testpath);
 
618
            will_clear = TRUE;
 
619
 
 
620
            /*
 
621
             *  Check the current status of the path to be deleted.
 
622
             */
 
623
            if (!ok_stat(testpath, &dir_info)) {
 
624
                will_clear = FALSE;
 
625
                break;
 
626
            } else {
 
627
                if (remove_file(testpath) <= 0) {
 
628
                    if (count == 0) count = -1;
 
629
                    will_clear = FALSE;
 
630
                    break;
 
631
                }
 
632
                ++count;
 
633
                FREE(testpath);
 
634
            }
 
635
        }
 
636
    }
 
637
    FREE(testpath);
 
638
    FREE(tmpbuf);
 
639
    if (will_clear)
 
640
        clear_tags();
 
641
    return count;
 
642
}
 
643
 
 
644
/*
 
645
 *  Move all tagged files and directories to a new location.
 
646
 *  Input is current directory.
 
647
 *  The tests in this function can, at best, prevent some user mistakes -
 
648
 *   anybody who relies on them for security is seriously misguided.
 
649
 *  If a user has enough permissions to move a file somewhere, the same
 
650
 *   uid with Lynx & dired can do the same thing.
 
651
 */
 
652
PRIVATE int modify_tagged ARGS1(
 
653
        char *,         testpath)
 
654
{
 
655
    char *cp;
 
656
    dev_t dev;
 
657
    ino_t inode;
 
658
    int owner;
 
659
    char tmpbuf[1024];
 
660
    char *savepath;
 
661
    char *srcpath = NULL;
 
662
    struct stat dir_info;
 
663
    int count = 0;
 
664
    HTList *tag;
 
665
 
 
666
    if (HTList_isEmpty(tagged))  /* should never happen */
 
667
        return 0;
 
668
 
 
669
    _statusline(gettext("Enter new location for tagged items: "));
 
670
 
 
671
    tmpbuf[0] = '\0';
 
672
    LYgetstr(tmpbuf, VISIBLE, sizeof(tmpbuf), NORECALL);
 
673
    if (strlen(tmpbuf)) {
 
674
    /*
 
675
     *  Determine the ownership of the current location.
 
676
     */
 
677
        /*
 
678
         *  This test used to always fail from the dired menu...
 
679
         *  changed to something that hopefully makes more sense - KW
 
680
         */
 
681
        if (testpath && *testpath && 0!=strcmp(testpath,"/")) {
 
682
            /*
 
683
             *  testpath passed in and is not empty and not a single "/"
 
684
             *  (which would probably be bogus) - use it.
 
685
             */
 
686
            cp = testpath;
 
687
        } else {
 
688
            /*
 
689
             *  Prepare to get directory path from one of the tagged files.
 
690
             */
 
691
            cp = HTList_lastObject(tagged);
 
692
            testpath = NULL;    /* Won't be needed any more in this function,
 
693
                                   set to NULL as a flag. */
 
694
        }
 
695
 
 
696
        if (testpath == NULL) {
 
697
            /*
 
698
             *  Get the directory containing the file or subdir.
 
699
             */
 
700
            if (cp) {
 
701
                cp = strip_trailing_slash(cp);
 
702
                cp = HTParse(".", cp, PARSE_PATH+PARSE_PUNCTUATION);
 
703
                savepath = HTURLPath_toFile(cp, TRUE, FALSE);
 
704
                FREE(cp);
 
705
            } else {    /* Last resort, should never happen. */
 
706
                savepath = HTURLPath_toFile(".", TRUE, FALSE);
 
707
            }
 
708
        } else {
 
709
            if (!strncmp(cp, "file://localhost", 16)) {
 
710
                cp += 16;
 
711
            } else if (isFILE_URL(cp)) {
 
712
                cp += LEN_FILE_URL;
 
713
            }
 
714
            savepath = HTURLPath_toFile(cp, TRUE, FALSE);
 
715
        }
 
716
 
 
717
        if (!ok_stat(savepath, &dir_info)) {
 
718
            FREE(savepath);
 
719
            return 0;
 
720
        }
 
721
 
 
722
        /*
 
723
         *  Save the owner of the current location for later use.
 
724
         *  Also save the device and inode for location checking/
 
725
         */
 
726
        dev = dir_info.st_dev;
 
727
        inode = dir_info.st_ino;
 
728
        owner = dir_info.st_uid;
 
729
 
 
730
        /*
 
731
         *  Replace ~/ references to the home directory.
 
732
         */
 
733
        if (!strncmp(tmpbuf, "~/", 2)) {
 
734
            char *cp1 = NULL;
 
735
            StrAllocCopy(cp1, Home_Dir());
 
736
            StrAllocCat(cp1, (tmpbuf + 1));
 
737
            if (strlen(cp1) > (sizeof(tmpbuf) - 1)) {
 
738
                HTAlert(gettext("Path too long"));
 
739
                FREE(savepath);
 
740
                FREE(cp1);
 
741
                return 0;
 
742
            }
 
743
            LYstrncpy(tmpbuf, cp1, sizeof(tmpbuf)-1);
 
744
            FREE(cp1);
 
745
        }
 
746
 
 
747
        /*
 
748
         *  If path is relative, prefix it with current location.
 
749
         */
 
750
        if (!LYIsPathSep(tmpbuf[0])) {
 
751
            LYAddPathSep(&savepath);
 
752
            StrAllocCat(savepath,tmpbuf);
 
753
        } else {
 
754
            StrAllocCopy(savepath,tmpbuf);
 
755
        }
 
756
 
 
757
        /*
 
758
         *  stat() the target location to determine type and ownership.
 
759
         */
 
760
        if (!ok_stat(savepath, &dir_info)) {
 
761
            FREE(savepath);
 
762
            return 0;
 
763
        }
 
764
 
 
765
        /*
 
766
         *  Make sure the source and target locations are not the same place.
 
767
         */
 
768
        if (dev == dir_info.st_dev && inode == dir_info.st_ino) {
 
769
            HTAlert(gettext("Source and destination are the same location - request ignored!"));
 
770
            FREE(savepath);
 
771
            return 0;
 
772
        }
 
773
 
 
774
        /*
 
775
         *  Make sure the target location is a directory which is owned
 
776
         *  by the same uid as the owner of the current location.
 
777
         */
 
778
        if (dir_has_same_owner(&dir_info, owner)) {
 
779
            count = 0;
 
780
            tag = tagged;
 
781
 
 
782
            /*
 
783
             *  Move all tagged items to the target location.
 
784
             */
 
785
            while ((cp = (char *)HTList_nextObject(tag)) != NULL) {
 
786
                srcpath = HTfullURL_toFile(cp);
 
787
 
 
788
                if (move_file(srcpath, savepath) < 0) {
 
789
                    if (count == 0)
 
790
                        count = -1;
 
791
                    break;
 
792
                }
 
793
                FREE(srcpath);
 
794
                ++count;
 
795
            }
 
796
            clear_tags();
 
797
            FREE(srcpath);
 
798
        }
 
799
        FREE(savepath);
 
800
        return count;
 
801
    }
 
802
    return 0;
 
803
}
 
804
 
 
805
/*
 
806
 *  Modify the name of the specified item.
 
807
 */
 
808
PRIVATE int modify_name ARGS1(
 
809
        char *,         testpath)
 
810
{
 
811
    char *cp;
 
812
    char tmpbuf[DIRED_MAXBUF];
 
813
    char *newpath = NULL;
 
814
    struct stat dir_info;
 
815
    int code = 0;
 
816
 
 
817
    /*
 
818
     *  Determine the status of the selected item.
 
819
     */
 
820
    testpath = strip_trailing_slash(testpath);
 
821
 
 
822
    if (ok_stat(testpath, &dir_info)) {
 
823
        /*
 
824
         *  Change the name of the file or directory.
 
825
         */
 
826
        if (S_ISDIR(dir_info.st_mode)) {
 
827
             cp = gettext("Enter new name for directory: ");
 
828
        } else if (S_ISREG(dir_info.st_mode)) {
 
829
             cp = gettext("Enter new name for file: ");
 
830
        } else {
 
831
             return ok_file_or_dir(&dir_info);
 
832
        }
 
833
        LYstrncpy(tmpbuf, LYPathLeaf(testpath), sizeof(tmpbuf)-1);
 
834
        if (get_filename(cp, tmpbuf, sizeof(tmpbuf)) == NULL)
 
835
            return 0;
 
836
 
 
837
        /*
 
838
         *  Do not allow the user to also change the location at this time.
 
839
         */
 
840
        if (LYLastPathSep(tmpbuf) != 0) {
 
841
            HTAlert(gettext("Illegal character (path-separator) found! Request ignored."));
 
842
        } else if (strlen(tmpbuf)) {
 
843
            if ((cp = LYLastPathSep(testpath)) != NULL)
 
844
                HTSprintf0(&newpath, "%.*s%s", (cp - testpath + 1), testpath, tmpbuf);
 
845
            else
 
846
                StrAllocCopy(newpath, tmpbuf);
 
847
 
 
848
            /*
 
849
             *  Make sure the destination does not already exist.
 
850
             */
 
851
            if (not_already_exists(newpath)) {
 
852
                code = move_file(testpath, newpath);
 
853
            }
 
854
            FREE(newpath);
 
855
 
 
856
        }
 
857
    }
 
858
    return code;
 
859
}
 
860
 
 
861
/*
 
862
 *  Change the location of a file or directory.
 
863
 */
 
864
PRIVATE int modify_location ARGS1(
 
865
        char *,         testpath)
 
866
{
 
867
    char *cp;
 
868
    dev_t dev;
 
869
    ino_t inode;
 
870
    int owner;
 
871
    char tmpbuf[1024];
 
872
    char *newpath = NULL;
 
873
    char *savepath = NULL;
 
874
    struct stat dir_info;
 
875
    int code = 0;
 
876
 
 
877
    /*
 
878
     *  Determine the status of the selected item.
 
879
     */
 
880
    testpath = strip_trailing_slash(testpath);
 
881
    if (!ok_stat(testpath, &dir_info)) {
 
882
        return 0;
 
883
    }
 
884
 
 
885
    /*
 
886
     *  Change the location of the file or directory.
 
887
     */
 
888
    if (S_ISDIR(dir_info.st_mode)) {
 
889
        if (HTGetProgramPath(ppMV) != NULL) {
 
890
            cp = gettext("Enter new location for directory: ");
 
891
        } else {
 
892
            HTAlert(COULD_NOT_ACCESS_DIR);
 
893
            return 0;
 
894
        }
 
895
    } else if (S_ISREG(dir_info.st_mode)) {
 
896
        cp = gettext("Enter new location for file: ");
 
897
    } else {
 
898
        return ok_file_or_dir(&dir_info);
 
899
    }
 
900
    LYstrncpy(tmpbuf, testpath, sizeof(tmpbuf)-1);
 
901
    *LYPathLeaf(tmpbuf) = '\0';
 
902
    if (get_filename(cp, tmpbuf, sizeof(tmpbuf)) == NULL)
 
903
        return 0;
 
904
    if (strlen(tmpbuf)) {
 
905
        StrAllocCopy(savepath, testpath);
 
906
        StrAllocCopy(newpath, testpath);
 
907
 
 
908
        /*
 
909
         *  Allow ~/ references to the home directory.
 
910
         */
 
911
        if (!strncmp(tmpbuf, "~/", 2)
 
912
         || !strcmp(tmpbuf,"~")) {
 
913
            StrAllocCopy(newpath, Home_Dir());
 
914
            StrAllocCat(newpath, (tmpbuf + 1));
 
915
            LYstrncpy(tmpbuf, newpath, sizeof(tmpbuf)-1);
 
916
        }
 
917
        if (LYisAbsPath(tmpbuf)) {
 
918
            StrAllocCopy(newpath, tmpbuf);
 
919
        } else if ((cp = LYLastPathSep(newpath)) != NULL) {
 
920
            *++cp = '\0';
 
921
            StrAllocCat(newpath, tmpbuf);
 
922
        } else {
 
923
            HTAlert(gettext("Unexpected failure - unable to find trailing path separator"));
 
924
            FREE(newpath);
 
925
            FREE(savepath);
 
926
            return 0;
 
927
        }
 
928
 
 
929
        /*
 
930
         *  Make sure the source and target have the same owner (uid).
 
931
         */
 
932
        dev = dir_info.st_dev;
 
933
        inode = dir_info.st_ino;
 
934
        owner = dir_info.st_uid;
 
935
        if (!ok_stat(newpath, &dir_info)) {
 
936
            code = 0;
 
937
        }
 
938
#ifdef UNIX
 
939
        /*
 
940
         *  Make sure the source and target are not the same location.
 
941
         */
 
942
        else if (dev == dir_info.st_dev && inode == dir_info.st_ino) {
 
943
            HTAlert(gettext("Source and destination are the same location!  Request ignored!"));
 
944
            code = 0;
 
945
        }
 
946
#endif
 
947
        else if (dir_has_same_owner(&dir_info, owner)) {
 
948
            code = move_file(savepath,newpath);
 
949
        }
 
950
        FREE(newpath);
 
951
        FREE(savepath);
 
952
    }
 
953
    return code;
 
954
}
 
955
 
 
956
/*
 
957
 *  Modify name or location of a file or directory on localhost.
 
958
 */
 
959
PUBLIC int local_modify ARGS2(
 
960
        DocInfo *,      doc,
 
961
        char **,        newpath)
 
962
{
 
963
    int ans;
 
964
    char *cp;
 
965
    char testpath[DIRED_MAXBUF]; /* a bit ridiculous */
 
966
    int count;
 
967
 
 
968
    if (!HTList_isEmpty(tagged)) {
 
969
        cp = HTpartURL_toFile(doc->address);
 
970
 
 
971
        count = modify_tagged(cp);
 
972
        FREE(cp);
 
973
 
 
974
        if (doc->link > (nlinks-count - 1))
 
975
            doc->link = (nlinks-count - 1);
 
976
        doc->link = (doc->link < 0) ?
 
977
                                  0 : doc->link;
 
978
 
 
979
        return count;
 
980
    } else if (doc->link < 0 || doc->link > nlinks) {
 
981
        /*
 
982
         *  Added protection.
 
983
         */
 
984
        return 0;
 
985
    }
 
986
 
 
987
    /*
 
988
     *  Do not allow simultaneous change of name and location as in Unix.
 
989
     *  This reduces functionality but reduces difficulty for the novice.
 
990
     */
 
991
#ifdef OK_PERMIT
 
992
    _statusline(gettext("Modify name, location, or permission (n, l, or p): "));
 
993
#else
 
994
    _statusline(gettext("Modify name or location (n or l): "));
 
995
#endif /* OK_PERMIT */
 
996
    ans = LYgetch_single();
 
997
 
 
998
    if (strchr("NLP", ans) != NULL) {
 
999
        cp = HTfullURL_toFile(links[doc->link].lname);
 
1000
        if (strlen(cp) >= DIRED_MAXBUF) {
 
1001
            FREE(cp);
 
1002
            return 0;
 
1003
        }
 
1004
        LYstrncpy(testpath, cp, sizeof(testpath)-1);
 
1005
        FREE(cp);
 
1006
 
 
1007
        if (ans == 'N') {
 
1008
            return(modify_name(testpath));
 
1009
        } else if (ans == 'L') {
 
1010
            if (modify_location(testpath)) {
 
1011
                if (doc->link == (nlinks-1))
 
1012
                    --doc->link;
 
1013
                return 1;
 
1014
            }
 
1015
#ifdef OK_PERMIT
 
1016
        } else if (ans == 'P') {
 
1017
            return(permit_location(NULL, testpath, newpath));
 
1018
#endif /* OK_PERMIT */
 
1019
        } else {
 
1020
            /*
 
1021
             *  Code for changing ownership needed here.
 
1022
             */
 
1023
            HTAlert(gettext("This feature not yet implemented!"));
 
1024
        }
 
1025
    }
 
1026
    return 0;
 
1027
}
 
1028
 
 
1029
/*
 
1030
 *  Create a new empty file in the current directory.
 
1031
 */
 
1032
PRIVATE int create_file ARGS1(
 
1033
        char *,         current_location)
 
1034
{
 
1035
    int code = FALSE;
 
1036
    char tmpbuf[DIRED_MAXBUF];
 
1037
    char *testpath = NULL;
 
1038
    char *bad_chars = ".~/";
 
1039
 
 
1040
    tmpbuf[0] = '\0';
 
1041
    if (get_filename(gettext("Enter name of file to create: "),
 
1042
                     tmpbuf, sizeof(tmpbuf)) != NULL) {
 
1043
 
 
1044
        if (!no_dotfiles && show_dotfiles) {
 
1045
            bad_chars = "~/";
 
1046
        }
 
1047
 
 
1048
        if (strstr(tmpbuf, "//") != NULL) {
 
1049
            HTAlert(gettext("Illegal redirection \"//\" found! Request ignored."));
 
1050
        } else if (strlen(tmpbuf) && strchr(bad_chars, tmpbuf[0]) == NULL) {
 
1051
            StrAllocCopy(testpath, current_location);
 
1052
            LYAddPathSep(&testpath);
 
1053
 
 
1054
            /*
 
1055
             *  Append the target filename to the current location.
 
1056
             */
 
1057
            StrAllocCat(testpath, tmpbuf);
 
1058
 
 
1059
            /*
 
1060
             *  Make sure the target does not already exist
 
1061
             */
 
1062
            if (not_already_exists(testpath)) {
 
1063
                code = touch_file(testpath);
 
1064
            }
 
1065
            FREE(testpath);
 
1066
        }
 
1067
    }
 
1068
    return code;
 
1069
}
 
1070
 
 
1071
/*
 
1072
 *  Create a new directory in the current directory.
 
1073
 */
 
1074
PRIVATE int create_directory ARGS1(
 
1075
        char *,         current_location)
 
1076
{
 
1077
    int code = FALSE;
 
1078
    char tmpbuf[DIRED_MAXBUF];
 
1079
    char *testpath = NULL;
 
1080
    char *bad_chars = ".~/";
 
1081
 
 
1082
    tmpbuf[0] = '\0';
 
1083
    if (get_filename(gettext("Enter name for new directory: "),
 
1084
                     tmpbuf, sizeof(tmpbuf)) != NULL) {
 
1085
 
 
1086
        if (!no_dotfiles && show_dotfiles) {
 
1087
            bad_chars = "~/";
 
1088
        }
 
1089
 
 
1090
        if (strstr(tmpbuf, "//") != NULL) {
 
1091
            HTAlert(gettext("Illegal redirection \"//\" found! Request ignored."));
 
1092
        } else if (strlen(tmpbuf) && strchr(bad_chars, tmpbuf[0]) == NULL) {
 
1093
            StrAllocCopy(testpath, current_location);
 
1094
            LYAddPathSep(&testpath);
 
1095
 
 
1096
            StrAllocCat(testpath, tmpbuf);
 
1097
 
 
1098
            /*
 
1099
             *  Make sure the target does not already exist.
 
1100
             */
 
1101
            if (not_already_exists(testpath)) {
 
1102
                code = make_directory(testpath);
 
1103
            }
 
1104
            FREE(testpath);
 
1105
        }
 
1106
    }
 
1107
    return code;
 
1108
}
 
1109
 
 
1110
/*
 
1111
 *  Create a file or a directory at the current location.
 
1112
 */
 
1113
PUBLIC int local_create ARGS1(
 
1114
        DocInfo *,      doc)
 
1115
{
 
1116
    int ans;
 
1117
    char *cp;
 
1118
    char testpath[DIRED_MAXBUF];
 
1119
 
 
1120
    cp = HTfullURL_toFile(doc->address);
 
1121
    if (strlen(cp) >= DIRED_MAXBUF) {
 
1122
        FREE(cp);
 
1123
        return 0;
 
1124
    }
 
1125
    strcpy(testpath,cp);
 
1126
    FREE(cp);
 
1127
 
 
1128
    _statusline(gettext("Create file or directory (f or d): "));
 
1129
    ans = LYgetch_single();
 
1130
 
 
1131
    if (ans == 'F') {
 
1132
        return(create_file(testpath));
 
1133
    } else if (ans == 'D') {
 
1134
        return(create_directory(testpath));
 
1135
    } else {
 
1136
        return 0;
 
1137
    }
 
1138
}
 
1139
 
 
1140
/*
 
1141
 *  Remove a single file or directory.
 
1142
 */
 
1143
PRIVATE int remove_single ARGS1(
 
1144
        char *,         testpath)
 
1145
{
 
1146
    int code = 0;
 
1147
    char *cp;
 
1148
    char *tmpbuf = 0;
 
1149
    struct stat dir_info;
 
1150
    BOOL is_directory = FALSE;
 
1151
 
 
1152
    if (!ok_lstat(testpath, &dir_info)) {
 
1153
        return 0;
 
1154
    }
 
1155
 
 
1156
    /*
 
1157
     *  Locate the filename portion of the path.
 
1158
     */
 
1159
    if ((cp = LYLastPathSep(testpath)) != NULL) {
 
1160
        ++cp;
 
1161
    } else {
 
1162
        cp = testpath;
 
1163
    }
 
1164
    if (S_ISDIR(dir_info.st_mode)) {
 
1165
        /*** This strlen stuff will probably screw up intl translations /jes ***/
 
1166
        /*** Course, it's probably broken for screen sizes other 80, too     ***/
 
1167
        if (strlen(cp) < 37) {
 
1168
            HTSprintf0(&tmpbuf,
 
1169
                       gettext("Remove directory '%s'?"), cp);
 
1170
        } else {
 
1171
            HTSprintf0(&tmpbuf,
 
1172
                       gettext("Remove directory?"));
 
1173
        }
 
1174
        is_directory = TRUE;
 
1175
    } else if (S_ISREG(dir_info.st_mode)) {
 
1176
        if (strlen(cp) < 60) {
 
1177
            HTSprintf0(&tmpbuf, gettext("Remove file '%s'?"), cp);
 
1178
        } else {
 
1179
            HTSprintf0(&tmpbuf, gettext("Remove file?"));
 
1180
        }
 
1181
#ifdef S_IFLNK
 
1182
    } else if (S_ISLNK(dir_info.st_mode)) {
 
1183
        if (strlen(cp) < 50) {
 
1184
            HTSprintf0(&tmpbuf, gettext("Remove symbolic link '%s'?"), cp);
 
1185
        } else {
 
1186
            HTSprintf0(&tmpbuf, gettext("Remove symbolic link?"));
 
1187
        }
 
1188
#endif
 
1189
    } else {
 
1190
        cannot_stat(testpath);
 
1191
        FREE(tmpbuf);
 
1192
        return 0;
 
1193
    }
 
1194
 
 
1195
    if (HTConfirm(tmpbuf) == YES) {
 
1196
        code = is_directory
 
1197
             ? remove_directory(testpath)
 
1198
             : remove_file(testpath);
 
1199
    }
 
1200
    FREE(tmpbuf);
 
1201
    return code;
 
1202
}
 
1203
 
 
1204
/*
 
1205
 *  Remove a file or a directory.
 
1206
 */
 
1207
PUBLIC int local_remove ARGS1(
 
1208
        DocInfo *,      doc)
 
1209
{
 
1210
    char *cp, *tp;
 
1211
    char testpath[DIRED_MAXBUF];
 
1212
    int count, i;
 
1213
 
 
1214
    if (!HTList_isEmpty(tagged)) {
 
1215
        count = remove_tagged();
 
1216
        if (doc->link > (nlinks-count - 1))
 
1217
            doc->link = (nlinks-count - 1);
 
1218
        doc->link = (doc->link < 0) ?
 
1219
                                  0 : doc->link;
 
1220
        return count;
 
1221
    } else if (doc->link < 0 || doc->link > nlinks) {
 
1222
        return 0;
 
1223
    }
 
1224
    cp = links[doc->link].lname;
 
1225
    if (is_url(cp) == FILE_URL_TYPE) {
 
1226
        tp = HTfullURL_toFile(cp);
 
1227
        if (strlen(tp) >= DIRED_MAXBUF) {
 
1228
            FREE(tp);
 
1229
            return 0;
 
1230
        }
 
1231
        strcpy(testpath, tp);
 
1232
        FREE(tp);
 
1233
 
 
1234
        if ((i = strlen(testpath)) && testpath[i - 1] == '/')
 
1235
            testpath[(i - 1)] = '\0';
 
1236
 
 
1237
        if (remove_single(testpath)) {
 
1238
            if (doc->link == (nlinks - 1))
 
1239
                --doc->link;
 
1240
            return 1;
 
1241
        }
 
1242
    }
 
1243
    return 0;
 
1244
}
 
1245
 
 
1246
#ifdef OK_PERMIT
 
1247
 
 
1248
PRIVATE char LYValidPermitFile[LY_MAXPATH] = "\0";
 
1249
 
 
1250
PRIVATE long permit_bits ARGS1(char *, string_mode)
 
1251
{
 
1252
    if (!strcmp(string_mode, "IRUSR")) return S_IRUSR;
 
1253
    if (!strcmp(string_mode, "IWUSR")) return S_IWUSR;
 
1254
    if (!strcmp(string_mode, "IXUSR")) return S_IXUSR;
 
1255
    if (!strcmp(string_mode, "IRGRP")) return S_IRGRP;
 
1256
    if (!strcmp(string_mode, "IWGRP")) return S_IWGRP;
 
1257
    if (!strcmp(string_mode, "IXGRP")) return S_IXGRP;
 
1258
    if (!strcmp(string_mode, "IROTH")) return S_IROTH;
 
1259
    if (!strcmp(string_mode, "IWOTH")) return S_IWOTH;
 
1260
    if (!strcmp(string_mode, "IXOTH")) return S_IXOTH;
 
1261
    /* Don't include setuid and friends; use shell access for that. */
 
1262
    return 0;
 
1263
}
 
1264
 
 
1265
/*
 
1266
 *  Handle DIRED permissions.
 
1267
 */
 
1268
PRIVATE int permit_location ARGS3(
 
1269
        char *,         destpath,
 
1270
        char *,         srcpath,
 
1271
        char **,        newpath)
 
1272
{
 
1273
#ifndef UNIX
 
1274
    HTAlert(gettext("Sorry, don't know how to permit non-UNIX files yet."));
 
1275
    return(0);
 
1276
#else
 
1277
    static char tempfile[LY_MAXPATH] = "\0";
 
1278
    char *cp;
 
1279
    char tmpdst[LY_MAXPATH];
 
1280
    struct stat dir_info;
 
1281
    CONST char *program;
 
1282
 
 
1283
    if (srcpath) {
 
1284
        /*
 
1285
         *  Create form.
 
1286
         */
 
1287
        FILE *fp0;
 
1288
        char * user_filename;
 
1289
        char * group_name;
 
1290
 
 
1291
        srcpath = strip_trailing_slash(srcpath);
 
1292
 
 
1293
        /*
 
1294
         *  A couple of sanity tests.
 
1295
         */
 
1296
        if (!ok_lstat(srcpath, &dir_info)
 
1297
         || !ok_file_or_dir(&dir_info))
 
1298
            return 0;
 
1299
 
 
1300
        user_filename = LYPathLeaf(srcpath);
 
1301
 
 
1302
        LYRemoveTemp(tempfile);
 
1303
        if ((fp0 = LYOpenTemp(tempfile, HTML_SUFFIX, "w")) == NULL) {
 
1304
            HTAlert(gettext("Unable to open permit options file"));
 
1305
            return(0);
 
1306
        }
 
1307
 
 
1308
        /*
 
1309
         * Make the tempfile a URL.
 
1310
         */
 
1311
        LYLocalFileToURL(newpath, tempfile);
 
1312
        LYRegisterUIPage(*newpath, UIP_PERMIT_OPTIONS);
 
1313
 
 
1314
        group_name = HTAA_GidToName (dir_info.st_gid);
 
1315
        LYstrncpy(LYValidPermitFile,
 
1316
                  srcpath,
 
1317
                  (sizeof(LYValidPermitFile) - 1));
 
1318
 
 
1319
        fprintf(fp0, "<Html><Head>\n<Title>%s</Title>\n</Head>\n<Body>\n",
 
1320
                PERMIT_OPTIONS_TITLE);
 
1321
      fprintf(fp0,"<H1>%s%s</H1>\n", PERMISSIONS_SEGMENT, user_filename);
 
1322
        {   /*
 
1323
             *  Prevent filenames which include '#' or '?' from messing it up.
 
1324
             */
 
1325
            char * srcpath_url = HTEscape(srcpath, URL_PATH);
 
1326
            fprintf(fp0, "<Form Action=\"%s//PERMIT_LOCATION%s\">\n",
 
1327
                    STR_LYNXDIRED, srcpath_url);
 
1328
            FREE(srcpath_url);
 
1329
        }
 
1330
 
 
1331
        fprintf(fp0, "<Ol><Li>%s<Br><Br>\n", gettext("Specify permissions below:"));
 
1332
        fprintf(fp0, "%s:<Br>\n", gettext("Owner:"));
 
1333
        fprintf(fp0,
 
1334
     "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IRUSR\" %s> Read<Br>\n",
 
1335
                (dir_info.st_mode & S_IRUSR) ? "checked" : "");
 
1336
        fprintf(fp0,
 
1337
    "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IWUSR\" %s> Write<Br>\n",
 
1338
                (dir_info.st_mode & S_IWUSR) ? "checked" : "");
 
1339
        /*
 
1340
         *  If restricted, only change eXecute permissions on directories.
 
1341
         */
 
1342
        if (!no_change_exec_perms || S_ISDIR(dir_info.st_mode))
 
1343
            fprintf(fp0,
 
1344
       "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IXUSR\" %s> %s<Br>\n",
 
1345
                (dir_info.st_mode & S_IXUSR) ? "checked" : "",
 
1346
                S_ISDIR(dir_info.st_mode) ? "Search" : "Execute");
 
1347
 
 
1348
        fprintf(fp0, "%s %s:<Br>\n", gettext("Group"), group_name);
 
1349
        fprintf(fp0,
 
1350
     "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IRGRP\" %s> Read<Br>\n",
 
1351
                (dir_info.st_mode & S_IRGRP) ? "checked" : "");
 
1352
        fprintf(fp0,
 
1353
    "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IWGRP\" %s> Write<Br>\n",
 
1354
                (dir_info.st_mode & S_IWGRP) ? "checked" : "");
 
1355
        /*
 
1356
         *  If restricted, only change eXecute permissions on directories.
 
1357
         */
 
1358
        if (!no_change_exec_perms || S_ISDIR(dir_info.st_mode))
 
1359
            fprintf(fp0,
 
1360
       "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IXGRP\" %s> %s<Br>\n",
 
1361
                (dir_info.st_mode & S_IXGRP) ? "checked" : "",
 
1362
                S_ISDIR(dir_info.st_mode) ? "Search" : "Execute");
 
1363
 
 
1364
        fprintf(fp0, "%s<Br>\n", gettext("Others:"));
 
1365
        fprintf(fp0,
 
1366
     "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IROTH\" %s> Read<Br>\n",
 
1367
                (dir_info.st_mode & S_IROTH) ? "checked" : "");
 
1368
        fprintf(fp0,
 
1369
    "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IWOTH\" %s> Write<Br>\n",
 
1370
                (dir_info.st_mode & S_IWOTH) ? "checked" : "");
 
1371
        /*
 
1372
         *  If restricted, only change eXecute permissions on directories.
 
1373
         */
 
1374
        if (!no_change_exec_perms || S_ISDIR(dir_info.st_mode))
 
1375
            fprintf(fp0,
 
1376
       "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IXOTH\" %s> %s<Br>\n",
 
1377
                (dir_info.st_mode & S_IXOTH) ? "checked" : "",
 
1378
                S_ISDIR(dir_info.st_mode) ? "Search" : "Execute");
 
1379
 
 
1380
      fprintf(fp0,
 
1381
"<Br>\n<Li><Input Type=\"submit\" Value=\"Submit\">  %s %s %s.\n</Ol>\n</Form>\n",
 
1382
                gettext("form to permit"),
 
1383
                S_ISDIR(dir_info.st_mode) ? "directory" : "file",
 
1384
                user_filename);
 
1385
        fprintf(fp0, "</Body></Html>");
 
1386
        LYCloseTempFP(fp0);
 
1387
 
 
1388
        LYforce_no_cache = TRUE;
 
1389
        return(PERMIT_FORM_RESULT);      /* Special flag for LYMainLoop */
 
1390
 
 
1391
    } else {                             /* The form being activated. */
 
1392
        mode_t new_mode = 0;
 
1393
 
 
1394
        /*
 
1395
         *  Make sure we have a valid set-permission
 
1396
         *  file comparison string loaded via a previous
 
1397
         *  call with srcpath != NULL. - KW
 
1398
         */
 
1399
        if (LYValidPermitFile[0] == '\0') {
 
1400
            if (LYCursesON)
 
1401
                HTAlert(INVALID_PERMIT_URL);
 
1402
            else
 
1403
                fprintf(stderr, "%s\n", INVALID_PERMIT_URL);
 
1404
            CTRACE((tfp, "permit_location: called for <%s>.\n",
 
1405
                        (destpath ?
 
1406
                         destpath : "NULL URL pointer")));
 
1407
            return 0;
 
1408
        }
 
1409
        cp = destpath;
 
1410
        while (*cp != '\0' && *cp != '?') { /* Find filename */
 
1411
            cp++;
 
1412
        }
 
1413
        if (*cp == '\0') {
 
1414
            return(0);  /* Nothing to permit. */
 
1415
        }
 
1416
        *cp++ = '\0';   /* Null terminate file name and
 
1417
                           start working on the masks. */
 
1418
 
 
1419
        /* Will now operate only on filename part. */
 
1420
        if ((destpath = HTURLPath_toFile(destpath, TRUE, FALSE)) == 0)
 
1421
                return(0);
 
1422
        if (strlen(destpath) >= LY_MAXPATH) {
 
1423
            FREE(destpath);
 
1424
            return(0);
 
1425
        }
 
1426
        strcpy(tmpdst, destpath);
 
1427
        FREE(destpath);
 
1428
        destpath = tmpdst;
 
1429
 
 
1430
        /*
 
1431
         *  Make sure that the file string is the one from
 
1432
         *  the last displayed File Permissions menu. - KW
 
1433
         */
 
1434
        if (strcmp(destpath, LYValidPermitFile)) {
 
1435
            if (LYCursesON)
 
1436
                HTAlert(INVALID_PERMIT_URL);
 
1437
            else
 
1438
                fprintf(stderr, "%s\n", INVALID_PERMIT_URL);
 
1439
            CTRACE((tfp, "permit_location: called for file '%s'.\n",
 
1440
                        destpath));
 
1441
            return 0;
 
1442
        }
 
1443
 
 
1444
        /*
 
1445
         *  A couple of sanity tests.
 
1446
         */
 
1447
        destpath = strip_trailing_slash(destpath);
 
1448
        if (!ok_stat(destpath, &dir_info)
 
1449
         || !ok_file_or_dir(&dir_info)) {
 
1450
            return 0;
 
1451
        }
 
1452
 
 
1453
        /*
 
1454
         *  Cycle over permission strings.
 
1455
         */
 
1456
        while(*cp != '\0') {
 
1457
            char *cr = cp;
 
1458
 
 
1459
            while(*cr != '\0' && *cr != '&') { /* GET data split by '&'. */
 
1460
                cr++;
 
1461
            }
 
1462
            if (*cr != '\0') {
 
1463
                *cr++ = '\0';
 
1464
            }
 
1465
            if (strncmp(cp, "mode=", 5) == 0) { /* Magic string. */
 
1466
                long mask = permit_bits(cp + 5);
 
1467
 
 
1468
                if (mask != 0) {
 
1469
                    /*
 
1470
                     *  If restricted, only change eXecute
 
1471
                     *  permissions on directories.
 
1472
                     */
 
1473
                    if (!no_change_exec_perms
 
1474
                     || strchr(cp+5, 'X') == NULL
 
1475
                     || S_ISDIR(dir_info.st_mode))
 
1476
                        new_mode |= mask;
 
1477
                } else {
 
1478
                    HTAlert(gettext("Invalid mode format."));
 
1479
                    return 0;
 
1480
                }
 
1481
            } else {
 
1482
                HTAlert(gettext("Invalid syntax format."));
 
1483
                return 0;
 
1484
            }
 
1485
 
 
1486
            cp = cr;
 
1487
        }
 
1488
 
 
1489
        /*
 
1490
         *  Call chmod().
 
1491
         */
 
1492
        if ((program = HTGetProgramPath(ppCHMOD)) != NULL) {
 
1493
            char *args[5];
 
1494
            char amode[10];
 
1495
            char *tmpbuf = NULL;
 
1496
 
 
1497
            HTSprintf0(&tmpbuf, "chmod %.4o %s", (unsigned int)new_mode, destpath);
 
1498
            sprintf(amode, "%.4o", (unsigned int)new_mode);
 
1499
            args[0] = "chmod";
 
1500
            args[1] = amode;
 
1501
            args[2] = destpath;
 
1502
            args[3] = (char *) 0;
 
1503
            if (LYExecv(program, args, tmpbuf) <= 0) {
 
1504
                FREE(tmpbuf);
 
1505
                return (-1);
 
1506
            }
 
1507
            FREE(tmpbuf);
 
1508
        } else {
 
1509
            if (chmod(destpath, new_mode) < 0)
 
1510
                return (-1);
 
1511
        }
 
1512
        LYforce_no_cache = TRUE;        /* Force update of dired listing. */
 
1513
        return 1;
 
1514
    }
 
1515
#endif /* !UNIX */
 
1516
}
 
1517
#endif /* OK_PERMIT */
 
1518
 
 
1519
/*
 
1520
 *  Display or remove a tag from a given link.
 
1521
 */
 
1522
PUBLIC void tagflag ARGS2(
 
1523
        int,            flag,
 
1524
        int,            cur)
 
1525
{
 
1526
    if (nlinks > 0) {
 
1527
        LYmove(links[cur].ly, 2);
 
1528
        lynx_stop_reverse();
 
1529
        if (flag == ON) {
 
1530
            LYaddch('+');
 
1531
        } else {
 
1532
            LYaddch(' ');
 
1533
        }
 
1534
 
 
1535
#if defined(FANCY_CURSES) || defined(USE_SLANG)
 
1536
        if (!LYShowCursor)
 
1537
            LYHideCursor(); /* get cursor out of the way */
 
1538
        else
 
1539
#endif /* FANCY CURSES || USE_SLANG */
 
1540
            /*
 
1541
             *  Never hide the cursor if there's no FANCY CURSES.
 
1542
             */
 
1543
            LYmove(links[cur].ly, links[cur].lx);
 
1544
 
 
1545
        LYrefresh();
 
1546
    }
 
1547
}
 
1548
 
 
1549
/*
 
1550
 *  Handle DIRED tags.
 
1551
 */
 
1552
PUBLIC void showtags ARGS1(
 
1553
        HTList *,       t)
 
1554
{
 
1555
    int i;
 
1556
    HTList *s;
 
1557
    char *name;
 
1558
 
 
1559
    for (i = 0; i < nlinks; i++) {
 
1560
        s = t;
 
1561
        while ((name = HTList_nextObject(s)) != NULL) {
 
1562
            if (!strcmp(links[i].lname, name)) {
 
1563
                tagflag(ON, i);
 
1564
                break;
 
1565
            }
 
1566
        }
 
1567
    }
 
1568
}
 
1569
 
 
1570
PRIVATE char * DirectoryOf ARGS1(
 
1571
        char *,         pathname)
 
1572
{
 
1573
    char *result = 0;
 
1574
    char *leaf;
 
1575
 
 
1576
    StrAllocCopy(result, pathname);
 
1577
    leaf = LYPathLeaf(result);
 
1578
 
 
1579
    if (leaf != result) {
 
1580
        CONST char *result1 = 0;
 
1581
 
 
1582
        *leaf = '\0';
 
1583
        if (!LYisRootPath(result))
 
1584
            LYTrimPathSep(result);
 
1585
        result1 = wwwName(result);
 
1586
        StrAllocCopy (result, result1);
 
1587
    }
 
1588
    return result;
 
1589
}
 
1590
 
 
1591
#ifdef __DJGPP__
 
1592
/*
 
1593
 * Convert filenames to acceptable 8+3 names when necessary.  Make a copy of
 
1594
 * the parameter if we must modify it.
 
1595
 */
 
1596
PRIVATE char * LYonedot ARGS1(
 
1597
        char *,         line)
 
1598
{
 
1599
    char *dot;
 
1600
    static char line1[LY_MAXPATH];
 
1601
 
 
1602
    if (pathconf (line, _PC_NAME_MAX) <= 12) {
 
1603
        LYstrncpy(line1, line, sizeof(line1)-1);
 
1604
        for (;;) {
 
1605
            if ((dot = strrchr(line1, '.')) == 0
 
1606
             || LYLastPathSep(dot) != 0) {
 
1607
                break;
 
1608
            } else if (strlen(dot) == 1) {
 
1609
                *dot = 0;
 
1610
            } else {
 
1611
                *dot = '_';
 
1612
            }
 
1613
        }
 
1614
        return(line1);
 
1615
    }
 
1616
    return(line);
 
1617
}
 
1618
#else
 
1619
#define LYonedot(path) path
 
1620
#endif /*  __DJGPP__ */
 
1621
 
 
1622
PRIVATE char * match_op ARGS2(
 
1623
        CONST char *,   prefix,
 
1624
        char *,         data)
 
1625
{
 
1626
    int len = strlen(prefix);
 
1627
 
 
1628
    if (!strncmp("LYNXDIRED://", data, 12)
 
1629
     && !strncmp(prefix, data + 12, (unsigned)len)) {
 
1630
        len += 12;
 
1631
#if defined(USE_DOS_DRIVES)
 
1632
        if (data[len] == '/') { /* this is normal */
 
1633
            len++;
 
1634
        }
 
1635
#endif
 
1636
        return data + len;
 
1637
    }
 
1638
    return 0;
 
1639
}
 
1640
 
 
1641
/*
 
1642
 *  Construct the appropriate system command taking care to
 
1643
 *  escape all path references to avoid spoofing the shell.
 
1644
 */
 
1645
PRIVATE char *build_command ARGS3(
 
1646
        char *,         line,
 
1647
        char *,         dirname,
 
1648
        char *,         arg)
 
1649
{
 
1650
    char *buffer = NULL;
 
1651
    CONST char *program;
 
1652
    CONST char *tar_path = HTGetProgramPath(ppTAR);
 
1653
 
 
1654
    if ((arg = match_op("DECOMPRESS", line)) != 0) {
 
1655
#define FMT_UNCOMPRESS "%s %s"
 
1656
        if ((program = HTGetProgramPath(ppUNCOMPRESS)) != NULL) {
 
1657
            HTAddParam(&buffer, FMT_UNCOMPRESS, 1, program);
 
1658
            HTAddParam(&buffer, FMT_UNCOMPRESS, 2, arg);
 
1659
            HTEndParam(&buffer, FMT_UNCOMPRESS, 2);
 
1660
        }
 
1661
        return buffer;
 
1662
    }
 
1663
 
 
1664
#if defined(OK_UUDECODE) && !defined(ARCHIVE_ONLY)
 
1665
    if ((arg = match_op("UUDECODE", line)) != 0) {
 
1666
#define FMT_UUDECODE "%s %s"
 
1667
        if ((program = HTGetProgramPath(ppUUDECODE)) != NULL) {
 
1668
            HTAddParam(&buffer, FMT_UUDECODE, 1, program);
 
1669
            HTAddParam(&buffer, FMT_UUDECODE, 2, arg);
 
1670
            HTEndParam(&buffer, FMT_UUDECODE, 2);
 
1671
            HTAlert(gettext("Warning!  UUDecoded file will exist in the directory you started Lynx."));
 
1672
        }
 
1673
        return buffer;
 
1674
    }
 
1675
#endif /* OK_UUDECODE && !ARCHIVE_ONLY */
 
1676
 
 
1677
#ifdef OK_TAR
 
1678
    if (tar_path != NULL) {
 
1679
# ifndef ARCHIVE_ONLY
 
1680
#  ifdef OK_GZIP
 
1681
        if ((arg = match_op("UNTAR_GZ", line)) != 0) {
 
1682
#define FMT_UNTAR_GZ "cd %s; %s -qdc %s |  %s %s %s"
 
1683
            if ((program = HTGetProgramPath(ppGZIP)) != NULL) {
 
1684
                dirname = DirectoryOf(arg);
 
1685
                HTAddParam(&buffer, FMT_UNTAR_GZ, 1, dirname);
 
1686
                HTAddParam(&buffer, FMT_UNTAR_GZ, 2, program);
 
1687
                HTAddParam(&buffer, FMT_UNTAR_GZ, 3, arg);
 
1688
                HTAddParam(&buffer, FMT_UNTAR_GZ, 4, tar_path);
 
1689
                HTAddToCmd(&buffer, FMT_UNTAR_GZ, 5, TAR_DOWN_OPTIONS);
 
1690
                HTAddToCmd(&buffer, FMT_UNTAR_GZ, 6, TAR_PIPE_OPTIONS);
 
1691
                HTEndParam(&buffer, FMT_UNTAR_GZ, 6);
 
1692
            }
 
1693
            return buffer;
 
1694
        }
 
1695
#  endif /* OK_GZIP */
 
1696
        if ((arg = match_op("UNTAR_Z", line)) != 0) {
 
1697
#define FMT_UNTAR_Z "cd %s; %s %s |  %s %s %s"
 
1698
            if ((program = HTGetProgramPath(ppZCAT)) != NULL) {
 
1699
                dirname = DirectoryOf(arg);
 
1700
                HTAddParam(&buffer, FMT_UNTAR_Z, 1, dirname);
 
1701
                HTAddParam(&buffer, FMT_UNTAR_Z, 2, program);
 
1702
                HTAddParam(&buffer, FMT_UNTAR_Z, 3, arg);
 
1703
                HTAddParam(&buffer, FMT_UNTAR_Z, 4, tar_path);
 
1704
                HTAddToCmd(&buffer, FMT_UNTAR_Z, 5, TAR_DOWN_OPTIONS);
 
1705
                HTAddToCmd(&buffer, FMT_UNTAR_Z, 6, TAR_PIPE_OPTIONS);
 
1706
                HTEndParam(&buffer, FMT_UNTAR_Z, 6);
 
1707
            }
 
1708
            return buffer;
 
1709
        }
 
1710
        if ((arg = match_op("UNTAR", line)) != 0) {
 
1711
#define FMT_UNTAR "cd %s; %s %s %s"
 
1712
            dirname = DirectoryOf(arg);
 
1713
            HTAddParam(&buffer, FMT_UNTAR, 1, dirname);
 
1714
            HTAddParam(&buffer, FMT_UNTAR, 2, tar_path);
 
1715
            HTAddToCmd(&buffer, FMT_UNTAR, 3, TAR_DOWN_OPTIONS);
 
1716
            HTAddParam(&buffer, FMT_UNTAR, 4, arg);
 
1717
            HTEndParam(&buffer, FMT_UNTAR, 4);
 
1718
            return buffer;
 
1719
        }
 
1720
# endif /* !ARCHIVE_ONLY */
 
1721
 
 
1722
# ifdef OK_GZIP
 
1723
        if ((arg = match_op("TAR_GZ", line)) != 0) {
 
1724
#define FMT_TAR_GZ "cd %s; %s %s %s %s | %s -qc >%s%s"
 
1725
            if ((program = HTGetProgramPath(ppGZIP)) != NULL) {
 
1726
                dirname = DirectoryOf(arg);
 
1727
                HTAddParam(&buffer, FMT_TAR_GZ, 1, dirname);
 
1728
                HTAddParam(&buffer, FMT_TAR_GZ, 2, tar_path);
 
1729
                HTAddToCmd(&buffer, FMT_TAR_GZ, 3, TAR_UP_OPTIONS);
 
1730
                HTAddToCmd(&buffer, FMT_TAR_GZ, 4, TAR_PIPE_OPTIONS);
 
1731
                HTAddParam(&buffer, FMT_TAR_GZ, 5, LYPathLeaf(arg));
 
1732
                HTAddParam(&buffer, FMT_TAR_GZ, 6, program);
 
1733
                HTAddParam(&buffer, FMT_TAR_GZ, 7, LYonedot(LYPathLeaf(arg)));
 
1734
                HTAddParam(&buffer, FMT_TAR_GZ, 8, EXT_TAR_GZ);
 
1735
                HTEndParam(&buffer, FMT_TAR_GZ, 8);
 
1736
            }
 
1737
            return buffer;
 
1738
        }
 
1739
# endif /* OK_GZIP */
 
1740
 
 
1741
        if ((arg = match_op("TAR_Z", line)) != 0) {
 
1742
#define FMT_TAR_Z "cd %s; %s %s %s %s | %s >%s%s"
 
1743
            if ((program = HTGetProgramPath(ppCOMPRESS)) != NULL) {
 
1744
                dirname = DirectoryOf(arg);
 
1745
                HTAddParam(&buffer, FMT_TAR_Z, 1, dirname);
 
1746
                HTAddParam(&buffer, FMT_TAR_Z, 2, tar_path);
 
1747
                HTAddToCmd(&buffer, FMT_TAR_Z, 3, TAR_UP_OPTIONS);
 
1748
                HTAddToCmd(&buffer, FMT_TAR_Z, 4, TAR_PIPE_OPTIONS);
 
1749
                HTAddParam(&buffer, FMT_TAR_Z, 5, LYPathLeaf(arg));
 
1750
                HTAddParam(&buffer, FMT_TAR_Z, 6, program);
 
1751
                HTAddParam(&buffer, FMT_TAR_Z, 7, LYonedot(LYPathLeaf(arg)));
 
1752
                HTAddParam(&buffer, FMT_TAR_Z, 8, EXT_TAR_Z);
 
1753
                HTEndParam(&buffer, FMT_TAR_Z, 8);
 
1754
            }
 
1755
            return buffer;
 
1756
        }
 
1757
 
 
1758
        if ((arg = match_op("TAR", line)) != 0) {
 
1759
#define FMT_TAR "cd %s; %s %s %s %s.tar %s"
 
1760
            dirname = DirectoryOf(arg);
 
1761
            HTAddParam(&buffer, FMT_TAR, 1, dirname);
 
1762
            HTAddParam(&buffer, FMT_TAR, 2, tar_path);
 
1763
            HTAddToCmd(&buffer, FMT_TAR, 3, TAR_UP_OPTIONS);
 
1764
            HTAddToCmd(&buffer, FMT_TAR, 4, TAR_FILE_OPTIONS);
 
1765
            HTAddParam(&buffer, FMT_TAR, 5, LYonedot(LYPathLeaf(arg)));
 
1766
            HTAddParam(&buffer, FMT_TAR, 6, LYPathLeaf(arg));
 
1767
            HTEndParam(&buffer, FMT_TAR, 6);
 
1768
            return buffer;
 
1769
        }
 
1770
    }
 
1771
#endif /* OK_TAR */
 
1772
 
 
1773
#ifdef OK_GZIP
 
1774
    if ((arg = match_op("GZIP", line)) != 0) {
 
1775
#define FMT_GZIP "%s -q %s"
 
1776
        if ((program = HTGetProgramPath(ppGZIP)) != NULL) {
 
1777
            HTAddParam(&buffer, FMT_GZIP, 1, program);
 
1778
            HTAddParam(&buffer, FMT_GZIP, 2, arg);
 
1779
            HTEndParam(&buffer, FMT_GZIP, 2);
 
1780
        }
 
1781
        return buffer;
 
1782
    }
 
1783
#ifndef ARCHIVE_ONLY
 
1784
    if ((arg = match_op("UNGZIP", line)) != 0) {
 
1785
#define FMT_UNGZIP "%s -d %s"
 
1786
        if ((program = HTGetProgramPath(ppGZIP)) != NULL) {
 
1787
            HTAddParam(&buffer, FMT_UNGZIP, 1, program);
 
1788
            HTAddParam(&buffer, FMT_UNGZIP, 2, arg);
 
1789
            HTEndParam(&buffer, FMT_UNGZIP, 2);
 
1790
        }
 
1791
        return buffer;
 
1792
    }
 
1793
#endif /* !ARCHIVE_ONLY */
 
1794
#endif /* OK_GZIP */
 
1795
 
 
1796
#ifdef OK_ZIP
 
1797
    if ((arg = match_op("ZIP", line)) != 0) {
 
1798
#define FMT_ZIP "cd %s; %s -rq %s.zip %s"
 
1799
        if ((program = HTGetProgramPath(ppZIP)) != NULL) {
 
1800
            dirname = DirectoryOf(arg);
 
1801
            HTAddParam(&buffer, FMT_ZIP, 1, dirname);
 
1802
            HTAddParam(&buffer, FMT_ZIP, 2, program);
 
1803
            HTAddParam(&buffer, FMT_ZIP, 3, LYonedot(LYPathLeaf(arg)));
 
1804
            HTAddParam(&buffer, FMT_ZIP, 4, LYPathLeaf(arg));
 
1805
            HTEndParam(&buffer, FMT_ZIP, 4);
 
1806
        }
 
1807
        return buffer;
 
1808
    }
 
1809
#if !defined(ARCHIVE_ONLY)
 
1810
    if ((arg = match_op("UNZIP", line)) != 0) {
 
1811
#define FMT_UNZIP "cd %s; %s -q %s"
 
1812
        if ((program = HTGetProgramPath(ppUNZIP)) != NULL) {
 
1813
            dirname = DirectoryOf(arg);
 
1814
            HTAddParam(&buffer, FMT_UNZIP, 1, dirname);
 
1815
            HTAddParam(&buffer, FMT_UNZIP, 2, program);
 
1816
            HTAddParam(&buffer, FMT_UNZIP, 3, arg);
 
1817
            HTEndParam(&buffer, FMT_UNZIP, 3);
 
1818
        }
 
1819
        return buffer;
 
1820
    }
 
1821
# endif /* !ARCHIVE_ONLY */
 
1822
#endif /* OK_ZIP */
 
1823
 
 
1824
    if ((arg = match_op("COMPRESS", line)) != 0) {
 
1825
#define FMT_COMPRESS "%s %s"
 
1826
        if ((program = HTGetProgramPath(ppCOMPRESS)) != NULL) {
 
1827
            HTAddParam(&buffer, FMT_COMPRESS, 1, program);
 
1828
            HTAddParam(&buffer, FMT_COMPRESS, 2, arg);
 
1829
            HTEndParam(&buffer, FMT_COMPRESS, 2);
 
1830
        }
 
1831
        return buffer;
 
1832
    }
 
1833
 
 
1834
    return NULL;
 
1835
}
 
1836
 
 
1837
/*
 
1838
 *  Perform file management operations for LYNXDIRED URL's.
 
1839
 *  Attempt to be consistent.  These are (pseudo) URLs - i.e., they should
 
1840
 *  be in URL syntax: some bytes will be URL-escaped with '%'.  This is
 
1841
 *  necessary because these (pseudo) URLs will go through some of the same
 
1842
 *  kinds of interpretations and mutilations as real ones: HTParse, stripping
 
1843
 *  off #fragments etc.  (Some access schemes currently have special rules
 
1844
 *  about not escaping parsing '#' "the URL way" built into HTParse, but that
 
1845
 *  doesn't look like a clean way.)
 
1846
 */
 
1847
PUBLIC int local_dired ARGS1(
 
1848
        DocInfo *,      doc)
 
1849
{
 
1850
    char *line_url;    /* will point to doc's address, which is a URL */
 
1851
    char *line = NULL; /* same as line_url, but HTUnEscaped, will be alloced */
 
1852
    char *arg = NULL; /* ...will point into line[] */
 
1853
    char *tp = NULL;
 
1854
    char *tmpbuf = NULL;
 
1855
    char *buffer = NULL;
 
1856
    char *dirname = NULL;
 
1857
    BOOL do_pop_doc = TRUE;
 
1858
 
 
1859
    line_url = doc->address;
 
1860
    CTRACE((tfp, "local_dired: called for <%s>.\n",
 
1861
                (line_url ?
 
1862
                 line_url : gettext("NULL URL pointer"))));
 
1863
    HTUnEscapeSome(line_url, "/");      /* don't mess too much with *doc */
 
1864
 
 
1865
    StrAllocCopy(line, line_url);
 
1866
    HTUnEscape(line);   /* _file_ (not URL) syntax, for those functions
 
1867
                           that need it.  Don't forget to FREE it. */
 
1868
    if ((arg = match_op("CHDIR", line)) != 0) {
 
1869
#ifdef SUPPORT_CHDIR
 
1870
        handle_LYK_CHDIR();
 
1871
        do_pop_doc = FALSE;
 
1872
#endif
 
1873
        arg = "blah";   /* do something to avoid cc's complaints */
 
1874
    } else if ((arg = match_op("NEW_FILE", line)) != 0) {
 
1875
        if (create_file(arg) > 0)
 
1876
            LYforce_no_cache = TRUE;
 
1877
    } else if ((arg = match_op("NEW_FOLDER", line)) != 0) {
 
1878
        if (create_directory(arg) > 0)
 
1879
            LYforce_no_cache = TRUE;
 
1880
#ifdef OK_INSTALL
 
1881
    } else if ((arg = match_op("INSTALL_SRC", line)) != 0) {
 
1882
        local_install(NULL, arg, &tp);
 
1883
        if (tp) {
 
1884
            FREE(doc->address);
 
1885
            doc->address = tp;
 
1886
        }
 
1887
        FREE(line);
 
1888
        return 0;
 
1889
    } else if ((arg = match_op("INSTALL_DEST", line)) != 0) {
 
1890
        local_install(arg, NULL, &tp);
 
1891
        LYpop(doc);
 
1892
#endif /* OK_INSTALL */
 
1893
    } else if ((arg = match_op("MODIFY_NAME", line)) != 0) {
 
1894
        if (modify_name(arg) > 0)
 
1895
            LYforce_no_cache = TRUE;
 
1896
    } else if ((arg = match_op("MODIFY_LOCATION", line)) != 0) {
 
1897
        if (modify_location(arg) > 0)
 
1898
            LYforce_no_cache = TRUE;
 
1899
    } else if ((arg = match_op("MOVE_TAGGED", line_url)) != 0) {
 
1900
        if (modify_tagged(arg) > 0)
 
1901
            LYforce_no_cache = TRUE;
 
1902
#ifdef OK_PERMIT
 
1903
    } else if ((arg = match_op("PERMIT_SRC", line)) != 0) {
 
1904
        permit_location(NULL, arg, &tp);
 
1905
        if (tp) {
 
1906
            /*
 
1907
             *  One of the checks may have failed.
 
1908
             */
 
1909
            FREE(doc->address);
 
1910
            doc->address = tp;
 
1911
        }
 
1912
        FREE(line);
 
1913
        return 0;
 
1914
    } else if ((arg = match_op("PERMIT_LOCATION", line_url)) != 0) {
 
1915
        permit_location(arg, NULL, &tp);
 
1916
#endif /* OK_PERMIT */
 
1917
    } else if ((arg = match_op("REMOVE_SINGLE", line)) != 0) {
 
1918
        if (remove_single(arg) > 0)
 
1919
            LYforce_no_cache = TRUE;
 
1920
    } else if ((arg = match_op("REMOVE_TAGGED", line)) != 0) {
 
1921
        if (remove_tagged())
 
1922
            LYforce_no_cache = TRUE;
 
1923
    } else if ((arg = match_op("CLEAR_TAGGED", line)) != 0) {
 
1924
        clear_tags();
 
1925
    } else if ((arg = match_op("UPLOAD", line)) != 0) {
 
1926
        /*
 
1927
         *  They're written by LYUpload_options() HTUnEscaped;
 
1928
         *  don't want to change that for now... so pass through
 
1929
         *  without more unescaping.  Directory names containing
 
1930
         *  '#' will probably fail.
 
1931
         */
 
1932
        if (LYUpload(line_url))
 
1933
            LYforce_no_cache = TRUE;
 
1934
    } else {
 
1935
        LYTrimPathSep(line);
 
1936
        if (LYLastPathSep(line) == NULL) {
 
1937
            FREE(line);
 
1938
            return 0;
 
1939
        }
 
1940
 
 
1941
        buffer = build_command(line, dirname, arg);
 
1942
 
 
1943
        if (buffer != 0) {
 
1944
            if ((int) strlen(buffer) < LYcols - 15) {
 
1945
                HTSprintf0(&tmpbuf, gettext("Executing %s "), buffer);
 
1946
            } else {
 
1947
                HTSprintf0(&tmpbuf,
 
1948
                           gettext("Executing system command. This might take a while."));
 
1949
            }
 
1950
            _statusline(tmpbuf);
 
1951
            stop_curses();
 
1952
            printf("%s\r\n", tmpbuf);
 
1953
            LYSystem(buffer);
 
1954
#ifdef VMS
 
1955
            HadVMSInterrupt = FALSE;
 
1956
#endif /* VMS */
 
1957
            start_curses();
 
1958
            LYforce_no_cache = TRUE;
 
1959
        }
 
1960
    }
 
1961
 
 
1962
    FREE(dirname);
 
1963
    FREE(tmpbuf);
 
1964
    FREE(buffer);
 
1965
    FREE(line);
 
1966
    FREE(tp);
 
1967
    if (do_pop_doc)
 
1968
        LYpop(doc);
 
1969
    return 0;
 
1970
}
 
1971
 
 
1972
/*
 
1973
 *  Provide a menu of file management options.
 
1974
 */
 
1975
PUBLIC int dired_options ARGS2(
 
1976
        DocInfo *,      doc,
 
1977
        char **,        newfile)
 
1978
{
 
1979
    static char tempfile[LY_MAXPATH];
 
1980
    char *path;
 
1981
    char *dir;
 
1982
    lynx_list_item_type *nxt;
 
1983
    struct stat dir_info;
 
1984
    FILE *fp0;
 
1985
    char *dir_url;
 
1986
    char *path_url;
 
1987
    BOOLEAN nothing_tagged;
 
1988
    int count;
 
1989
    struct dired_menu *mp;
 
1990
    char buf[2048];
 
1991
 
 
1992
    if ((fp0 = InternalPageFP(tempfile, FALSE)) == 0)
 
1993
        return(0);
 
1994
 
 
1995
    /*
 
1996
     *  Make the tempfile a URL.
 
1997
     */
 
1998
    LYLocalFileToURL(newfile, tempfile);
 
1999
    LYRegisterUIPage(*newfile, UIP_DIRED_MENU);
 
2000
 
 
2001
    if (doc->link > -1 && doc->link < (nlinks+1)) {
 
2002
        path = HTfullURL_toFile(links[doc->link].lname);
 
2003
        LYTrimPathSep(path);
 
2004
 
 
2005
        if (!ok_lstat(path, &dir_info)) {
 
2006
            LYCloseTempFP(fp0);
 
2007
            FREE(path);
 
2008
            return 0;
 
2009
        }
 
2010
 
 
2011
    } else {
 
2012
        StrAllocCopy(path, "");
 
2013
    }
 
2014
 
 
2015
    dir = HTfullURL_toFile(doc->address);
 
2016
    LYTrimPathSep(dir);
 
2017
 
 
2018
    nothing_tagged = (BOOL) (HTList_isEmpty(tagged));
 
2019
 
 
2020
    BeginInternalPage(fp0, DIRED_MENU_TITLE, DIRED_MENU_HELP);
 
2021
 
 
2022
    fprintf(fp0, "<em>%s</em> %s<br>\n", gettext("Current directory:"), dir);
 
2023
 
 
2024
    if (nothing_tagged) {
 
2025
        fprintf(fp0, "<em>%s</em> ", gettext("Current selection:"));
 
2026
        if (strlen(path)) {
 
2027
            fprintf(fp0, "%s<p>\n", path);
 
2028
        } else {
 
2029
            fprintf(fp0, "%s.<p>\n", gettext("Nothing currently selected."));
 
2030
        }
 
2031
    } else {
 
2032
        /*
 
2033
         *  Write out number of tagged items, and names of first
 
2034
         *  few of them relative to current (in the DIRED sense)
 
2035
         *  directory.
 
2036
         */
 
2037
        int n = HTList_count(tagged);
 
2038
        char *cp1 = NULL;
 
2039
        char *cd = NULL;
 
2040
        int i, m;
 
2041
#define NUM_TAGS_TO_WRITE 10
 
2042
        fprintf(fp0, "<em>%s</em> %d %s",
 
2043
                gettext("Current selection:"),
 
2044
                n, ((n == 1) ? gettext("tagged item:") : gettext("tagged items:")));
 
2045
        StrAllocCopy(cd, doc->address);
 
2046
        HTUnEscapeSome(cd, "/");
 
2047
        LYAddHtmlSep(&cd);
 
2048
        m = (n < NUM_TAGS_TO_WRITE) ? n : NUM_TAGS_TO_WRITE;
 
2049
        for (i = 1; i <= m; i++) {
 
2050
            cp1 = HTRelative(HTList_objectAt(tagged, i-1),
 
2051
                             (*cd ? cd : "file://localhost"));
 
2052
            HTUnEscape(cp1);
 
2053
            LYEntify(&cp1, TRUE); /* _should_ do this everywhere... */
 
2054
            fprintf(fp0, "%s<br>\n&nbsp;&nbsp;&nbsp;%s",
 
2055
                         (i == 1 ? "" : " ,"), cp1);
 
2056
            FREE(cp1);
 
2057
        }
 
2058
        if (n > m) {
 
2059
            fprintf(fp0," , ...");
 
2060
        }
 
2061
        fprintf(fp0, "<p>\n");
 
2062
        FREE(cd);
 
2063
    }
 
2064
 
 
2065
    /*
 
2066
     *  If menu_head is NULL then use defaults and link them together now.
 
2067
     */
 
2068
    if (menu_head == NULL) {
 
2069
        for (mp = defmenu; mp->href != NULL; mp++)
 
2070
            mp->next = (mp + 1);
 
2071
        (--mp)->next = NULL;
 
2072
        menu_head = defmenu;
 
2073
    }
 
2074
 
 
2075
    for (mp = menu_head; mp != NULL; mp = mp->next) {
 
2076
        if (mp->cond != DE_TAG && !nothing_tagged)
 
2077
            continue;
 
2078
        if (mp->cond == DE_TAG && nothing_tagged)
 
2079
            continue;
 
2080
        if (mp->cond == DE_DIR &&
 
2081
            (!*path || !S_ISDIR(dir_info.st_mode)))
 
2082
            continue;
 
2083
        if (mp->cond == DE_FILE &&
 
2084
            (!*path || !S_ISREG(dir_info.st_mode)))
 
2085
            continue;
 
2086
#ifdef S_IFLNK
 
2087
        if (mp->cond == DE_SYMLINK &&
 
2088
            (!*path || !S_ISLNK(dir_info.st_mode)))
 
2089
            continue;
 
2090
#endif
 
2091
        if (*mp->sfx &&
 
2092
            (strlen(path) < strlen(mp->sfx) ||
 
2093
             strcmp(mp->sfx, &path[(strlen(path) - strlen(mp->sfx))]) != 0))
 
2094
            continue;
 
2095
        dir_url  = HTEscape(dir, URL_PATH);
 
2096
        path_url = HTEscape(path, URL_PATH);
 
2097
        fprintf(fp0, "<a href=\"%s",
 
2098
                render_item(mp->href, path_url, dir_url, buf,sizeof(buf), YES));
 
2099
        fprintf(fp0, "\">%s</a> ",
 
2100
                render_item(mp->link, path, dir, buf,sizeof(buf), NO));
 
2101
        fprintf(fp0, "%s<br>\n",
 
2102
                render_item(mp->rest, path, dir, buf,sizeof(buf), NO));
 
2103
        FREE(dir_url);
 
2104
        FREE(path_url);
 
2105
    }
 
2106
    FREE(path);
 
2107
 
 
2108
    if (uploaders != NULL) {
 
2109
        fprintf(fp0, "<p>Upload to current directory:<p>\n");
 
2110
        for (count = 0, nxt = uploaders;
 
2111
             nxt != NULL;
 
2112
             nxt = nxt->next, count++) {
 
2113
            fprintf(fp0,
 
2114
                "<a href=\"LYNXDIRED://UPLOAD=%d/TO=%s\"> %s </a><br>\n",
 
2115
                    count, dir, nxt->name);
 
2116
        }
 
2117
    }
 
2118
    FREE(dir);
 
2119
 
 
2120
    EndInternalPage(fp0);
 
2121
    LYCloseTempFP(fp0);
 
2122
 
 
2123
    LYforce_no_cache = TRUE;
 
2124
 
 
2125
    return(0);
 
2126
}
 
2127
 
 
2128
/*
 
2129
 *  Check DIRED filename.
 
2130
 */
 
2131
PRIVATE char *get_filename ARGS3(
 
2132
        char *,         prompt,
 
2133
        char *,         buf,
 
2134
        size_t,         bufsize)
 
2135
{
 
2136
    char *cp;
 
2137
 
 
2138
    _statusline(prompt);
 
2139
 
 
2140
    LYgetstr(buf, VISIBLE, bufsize, NORECALL);
 
2141
    if (strstr(buf, "../") != NULL) {
 
2142
        HTAlert(gettext("Illegal filename; request ignored."));
 
2143
        return NULL;
 
2144
    }
 
2145
 
 
2146
    if (no_dotfiles || !show_dotfiles) {
 
2147
        cp = LYLastPathSep(buf); /* find last slash */
 
2148
        if (cp)
 
2149
            cp += 1;
 
2150
        else
 
2151
            cp = buf;
 
2152
        if (*cp == '.') {
 
2153
            HTAlert(gettext("Illegal filename; request ignored."));
 
2154
            return NULL;
 
2155
        }
 
2156
    }
 
2157
    return buf;
 
2158
}
 
2159
 
 
2160
#ifdef OK_INSTALL
 
2161
 
 
2162
#define LYEXECV_MAX_ARGC 15
 
2163
/* these are quasi-constant once they have been allocated: */
 
2164
static char ** install_argp = NULL;     /* args for execv install */
 
2165
static char * install_path = NULL;      /* auxiliary */
 
2166
#ifdef LY_FIND_LEAKS
 
2167
PRIVATE void clear_install_path NOARGS
 
2168
{
 
2169
    FREE(install_argp);
 
2170
    FREE(install_path);
 
2171
}
 
2172
#endif /* LY_FIND_LEAKS */
 
2173
 
 
2174
/*
 
2175
 *  Fill in args array for execv (or execvp etc.) call, after first
 
2176
 *  allocating it if necessary.  No fancy parsing, cmd_args is just
 
2177
 *  split at spaces.  Leave room for reserve additional args to be
 
2178
 *  added by caller.
 
2179
 *  On success *argvp points to new args vector, *pathp is auxiliary.
 
2180
 *  On success returns index of next argument, else -1.
 
2181
 *  This is generic enough that it could be used for other calls than
 
2182
 *  install, except the atexit call.  Go through this trouble for install
 
2183
 *  because INSTALL_ARGS may be significant, and someone may configure it
 
2184
 *  with more than one significant flags. - kw
 
2185
 */
 
2186
PRIVATE int fill_argv_for_execv ARGS5(
 
2187
    char ***,           argvp,
 
2188
    char **,            pathp,
 
2189
    char *,             cmd_path,
 
2190
    CONST char *,       cmd_args,
 
2191
    int,                reserve)
 
2192
{
 
2193
    int n = 0;
 
2194
 
 
2195
    char **args;
 
2196
    char *cp;
 
2197
    if (*argvp == NULL) {
 
2198
        *argvp = typecallocn(char *, LYEXECV_MAX_ARGC+1);
 
2199
        if (!*argvp)
 
2200
            return(-1);
 
2201
#ifdef LY_FIND_LEAKS
 
2202
        atexit(clear_install_path);
 
2203
#endif
 
2204
    }
 
2205
    args = *argvp;
 
2206
    args[n++] = cmd_path;
 
2207
    if (cmd_args) {
 
2208
        StrAllocCopy(*pathp, cmd_args);
 
2209
        cp = strtok(*pathp, " ");
 
2210
        if (cp) {
 
2211
            while (cp && (n < LYEXECV_MAX_ARGC - reserve)) {
 
2212
                args[n++] = cp;
 
2213
                cp = strtok(NULL, " ");
 
2214
            }
 
2215
            if (cp && (n >= LYEXECV_MAX_ARGC - reserve)) {
 
2216
                CTRACE((tfp, "Too many args for '%s' in '%s'!\n",
 
2217
                       NONNULL(cmd_path), cmd_args));
 
2218
                return(-1);
 
2219
            }
 
2220
        } else {
 
2221
            args[n++] = *pathp;
 
2222
        }
 
2223
    }
 
2224
    args[n] = (char *)0;
 
2225
    return(n);
 
2226
}
 
2227
 
 
2228
/*
 
2229
 *  Install the specified file or directory.
 
2230
 */
 
2231
PUBLIC BOOLEAN local_install ARGS3(
 
2232
        char *,         destpath,
 
2233
        char *,         srcpath,
 
2234
        char **,        newpath)
 
2235
{
 
2236
    char *tmpbuf = NULL;
 
2237
    static char savepath[DIRED_MAXBUF]; /* This will be the link that
 
2238
                                           is to be installed. */
 
2239
    struct stat dir_info;
 
2240
    char **args;
 
2241
    HTList *tag;
 
2242
    char *cp = NULL;
 
2243
    char *tmpdest = NULL;
 
2244
    int count = 0;
 
2245
    int n = 0;          /* indices into 'args[]' */
 
2246
    static int src = -1;
 
2247
    CONST char *program;
 
2248
 
 
2249
    if ((program = HTGetProgramPath(ppINSTALL)) == NULL) {
 
2250
        HTAlert(gettext("Install in the selected directory not permitted."));
 
2251
        return 0;
 
2252
    }
 
2253
 
 
2254
    /*
 
2255
     *  Determine the status of the selected item.
 
2256
     */
 
2257
    if (srcpath) {
 
2258
        srcpath = strip_trailing_slash(srcpath);
 
2259
        if (is_url(srcpath)) {
 
2260
            char *local_src = HTfullURL_toFile(srcpath);
 
2261
            if (!ok_localname(savepath, local_src)) {
 
2262
                FREE(local_src);
 
2263
                return 0;
 
2264
            }
 
2265
            FREE(local_src);
 
2266
        } else if (!HTList_isEmpty(tagged) &&
 
2267
                   srcpath[0] == '\0') {
 
2268
            savepath[0] = '\0'; /* will always use tagged list - kw */
 
2269
        } else if (!ok_localname(savepath, srcpath)) {
 
2270
            return 0;
 
2271
        }
 
2272
        LYforce_no_cache = TRUE;
 
2273
        LYLocalFileToURL(newpath, Home_Dir());
 
2274
        LYAddHtmlSep(newpath);
 
2275
        StrAllocCat(*newpath, INSTALLDIRS_FILE);
 
2276
        LYRegisterUIPage(*newpath, UIP_INSTALL);
 
2277
        return 0;
 
2278
    }
 
2279
 
 
2280
    /* deal with ~/ or /~/ at the beginning - kw */
 
2281
    if (destpath[0] == '~' &&
 
2282
        (destpath[1] == '/' || destpath[1] == '\0')) {
 
2283
        cp = &destpath[1];
 
2284
    } else if (destpath[0] == '/' && destpath[1] == '~' &&
 
2285
               (destpath[2] == '/' || destpath[2] == '\0')) {
 
2286
        cp = &destpath[2];
 
2287
    }
 
2288
    if (cp) {
 
2289
        /* If found, allocate new string, make destpath point to it - kw */
 
2290
        StrAllocCopy(tmpdest, Home_Dir());
 
2291
        if (cp[0] && cp[1]) {
 
2292
            LYAddPathSep(&tmpdest);
 
2293
            StrAllocCat(tmpdest, cp + 1);
 
2294
        }
 
2295
        destpath = tmpdest;
 
2296
    }
 
2297
 
 
2298
    destpath = strip_trailing_slash(destpath);
 
2299
 
 
2300
    if (!ok_stat(destpath, &dir_info)) {
 
2301
        FREE(tmpdest);
 
2302
        return 0;
 
2303
    } else if (!S_ISDIR(dir_info.st_mode)) {
 
2304
        HTAlert(gettext("The selected item is not a directory!  Request ignored."));
 
2305
        FREE(tmpdest);
 
2306
        return 0;
 
2307
    } else if (0 /*directory not writable*/) {
 
2308
        HTAlert(gettext("Install in the selected directory not permitted."));
 
2309
        FREE(tmpdest);
 
2310
        return 0;
 
2311
    }
 
2312
 
 
2313
    statusline(gettext("Just a moment, ..."));
 
2314
 
 
2315
    /* fill in the fixed args, if not already done - kw */
 
2316
    if (src > 0 && install_argp) {
 
2317
        n = src;
 
2318
        n++;
 
2319
    } else {
 
2320
        n = fill_argv_for_execv(&install_argp, &install_path,
 
2321
                                "install",
 
2322
#ifdef INSTALL_ARGS
 
2323
                                INSTALL_ARGS,
 
2324
#else
 
2325
                                NULL,
 
2326
#endif /* INSTALL_ARGS */
 
2327
                                2);
 
2328
        if (n <= 0) {
 
2329
            src = 0;
 
2330
            HTAlert(gettext("Error buiding install args"));
 
2331
            FREE(tmpdest);
 
2332
            return 0;
 
2333
        }
 
2334
        src = n++;
 
2335
    }
 
2336
    args = install_argp;
 
2337
 
 
2338
    args[n++] = destpath;
 
2339
    args[n] = (char *)0;
 
2340
    tag = tagged;
 
2341
 
 
2342
    if (HTList_isEmpty(tagged)) {
 
2343
        /* simplistic detection of identical src and dest - kw */
 
2344
        if (!strcmp(savepath, destpath)) {
 
2345
            HTUserMsg2(gettext("Source and target are the same: %s"),
 
2346
                       savepath);
 
2347
            FREE(tmpdest);
 
2348
            return(-1);         /* don't do it */
 
2349
        } else if (!strncmp(savepath, destpath, strlen(destpath)) &&
 
2350
                   LYIsPathSep(savepath[strlen(destpath)]) &&
 
2351
                   LYLastPathSep(savepath + strlen(destpath) + 1) == 0) {
 
2352
            HTUserMsg2(gettext("Already in target directory: %s"),
 
2353
                       savepath);
 
2354
            FREE(tmpdest);
 
2355
            return 0;           /* don't do it */
 
2356
        }
 
2357
        args[src] = savepath;
 
2358
        HTSprintf0(&tmpbuf, "install %s in %s", savepath, destpath);
 
2359
        if (LYExecv(program, args, tmpbuf) <= 0) {
 
2360
            FREE(tmpbuf);
 
2361
            FREE(tmpdest);
 
2362
            return (-1);
 
2363
        }
 
2364
        count++;
 
2365
    } else {
 
2366
        char *name;
 
2367
        HTSprintf0(&tmpbuf, "install in %s", destpath);
 
2368
        while ((name = (char *)HTList_nextObject(tag))) {
 
2369
            int err;
 
2370
            args[src] = HTfullURL_toFile(name);
 
2371
 
 
2372
            /* simplistic detection of identical src and dest - kw */
 
2373
            if (!strcmp(args[src], destpath)) {
 
2374
                HTUserMsg2(gettext("Source and target are the same: %s"),
 
2375
                           args[src]);
 
2376
                FREE(args[src]);
 
2377
                continue;       /* skip this source file */
 
2378
            } else if (!strncmp(args[src], destpath, strlen(destpath)) &&
 
2379
                       LYIsPathSep(args[src][strlen(destpath)]) &&
 
2380
                       LYLastPathSep(args[src] + strlen(destpath) + 1) == 0) {
 
2381
                HTUserMsg2(gettext("Already in target directory: %s"),
 
2382
                           args[src]);
 
2383
                FREE(args[src]);
 
2384
                continue;       /* skip this source file */
 
2385
            }
 
2386
            err = (LYExecv(program, args, tmpbuf) <= 0);
 
2387
            FREE(args[src]);
 
2388
            if (err) {
 
2389
                FREE(tmpbuf);
 
2390
                FREE(tmpdest);
 
2391
                return ((count == 0) ? -1 : count);
 
2392
            }
 
2393
            count++;
 
2394
        }
 
2395
        clear_tags();
 
2396
    }
 
2397
    FREE(tmpbuf);
 
2398
    FREE(tmpdest);
 
2399
    HTInfoMsg(gettext("Installation complete"));
 
2400
    return count;
 
2401
}
 
2402
#endif /* OK_INSTALL */
 
2403
 
 
2404
/*
 
2405
 *  Clear DIRED tags.
 
2406
 */
 
2407
PUBLIC void clear_tags NOARGS
 
2408
{
 
2409
    char *cp = NULL;
 
2410
 
 
2411
    while ((cp = HTList_removeLastObject(tagged)) != NULL) {
 
2412
        FREE(cp);
 
2413
    }
 
2414
    if (HTList_isEmpty(tagged))
 
2415
        FREE(tagged);
 
2416
}
 
2417
 
 
2418
/*
 
2419
 *  Handle DIRED menu item.
 
2420
 */
 
2421
PUBLIC void add_menu_item ARGS1(
 
2422
        char *,         str)
 
2423
{
 
2424
    struct dired_menu *new, *mp;
 
2425
    char *cp;
 
2426
 
 
2427
    /*
 
2428
     *  First custom menu definition causes entire default menu to be
 
2429
     *  discarded.
 
2430
     */
 
2431
    if (menu_head == defmenu)
 
2432
        menu_head = NULL;
 
2433
 
 
2434
    new = typecalloc(struct dired_menu);
 
2435
    if (new == NULL)
 
2436
        outofmem(__FILE__, "add_menu_item");
 
2437
 
 
2438
    /*
 
2439
     *  Conditional on tagged != NULL ?
 
2440
     */
 
2441
    cp = strchr(str, ':');
 
2442
    *cp++ = '\0';
 
2443
    if (strcasecomp(str, "tag") == 0) {
 
2444
        new->cond = DE_TAG;
 
2445
    } else if (strcasecomp(str, "dir") == 0) {
 
2446
        new->cond = DE_DIR;
 
2447
    } else if (strcasecomp(str, "file") == 0) {
 
2448
        new->cond = DE_FILE;
 
2449
#ifdef S_IFLNK
 
2450
    } else if (strcasecomp(str, "link") == 0) {
 
2451
        new->cond = DE_SYMLINK;
 
2452
#endif /* S_IFLNK */
 
2453
    }
 
2454
 
 
2455
    /*
 
2456
     *  Conditional on matching suffix.
 
2457
     */
 
2458
    str = cp;
 
2459
    cp = strchr(str, ':');
 
2460
    *cp++ = '\0';
 
2461
    StrAllocCopy(new->sfx, str);
 
2462
 
 
2463
    str = cp;
 
2464
    cp = strchr(str, ':');
 
2465
    *cp++ = '\0';
 
2466
    StrAllocCopy(new->link, str);
 
2467
 
 
2468
    str = cp;
 
2469
    cp = strchr(str, ':');
 
2470
    *cp++ = '\0';
 
2471
    StrAllocCopy(new->rest, str);
 
2472
 
 
2473
    StrAllocCopy(new->href, cp);
 
2474
 
 
2475
    if (menu_head) {
 
2476
        for (mp = menu_head; mp && mp->next != NULL; mp = mp->next)
 
2477
            ;
 
2478
        mp->next = new;
 
2479
    } else
 
2480
        menu_head = new;
 
2481
}
 
2482
 
 
2483
PUBLIC void reset_dired_menu NOARGS
 
2484
{
 
2485
    if (menu_head != defmenu) {
 
2486
        struct dired_menu *mp, *mp_next = NULL;
 
2487
        for (mp = menu_head; mp != NULL; mp = mp_next) {
 
2488
            FREE(mp->sfx);
 
2489
            FREE(mp->link);
 
2490
            FREE(mp->rest);
 
2491
            FREE(mp->href);
 
2492
            mp_next = mp_next;
 
2493
            FREE(mp);
 
2494
        }
 
2495
        menu_head = NULL;
 
2496
    }
 
2497
}
 
2498
 
 
2499
/*
 
2500
 *  Create URL for DIRED HREF value.
 
2501
 */
 
2502
PRIVATE char * render_item ARGS6(
 
2503
        CONST char *,   s,
 
2504
        CONST char *,   path,
 
2505
        CONST char *,   dir,
 
2506
        char *,         buf,
 
2507
        int,            bufsize,
 
2508
        BOOLEAN,        url_syntax)
 
2509
{
 
2510
    CONST char *cp;
 
2511
    char *bp;
 
2512
    char overrun = '\0';
 
2513
    char *taglist = NULL;
 
2514
#define BP_INC (bp>buf+bufsize-2 ?  &overrun : bp++)
 
2515
                                /* Buffer overrun could happen for very long
 
2516
                                   tag list, if %l or %t are used */
 
2517
    bp = buf;
 
2518
    while (*s && !overrun) {
 
2519
        if (*s == '%') {
 
2520
            s++;
 
2521
            switch (*s) {
 
2522
                case '%':
 
2523
                    *BP_INC = '%';
 
2524
                    break;
 
2525
                case 'p':
 
2526
                    cp = path;
 
2527
                    if (!LYIsHtmlSep(*cp))
 
2528
                        *BP_INC = '/';
 
2529
                    while (*cp)
 
2530
                        *BP_INC = *cp++;
 
2531
                    break;
 
2532
                case 'd':
 
2533
                    cp = dir;
 
2534
                    if (!LYIsHtmlSep(*cp))
 
2535
                        *BP_INC = '/';
 
2536
                    while (*cp)
 
2537
                        *BP_INC = *cp++;
 
2538
                    break;
 
2539
                case 'f':
 
2540
                    cp = LYLastPathSep(path);
 
2541
                    if (cp)
 
2542
                        cp++;
 
2543
                    else
 
2544
                        cp = path;
 
2545
                    while (*cp)
 
2546
                        *BP_INC = *cp++;
 
2547
                    break;
 
2548
                case 'l':
 
2549
                case 't':
 
2550
                    if (!HTList_isEmpty(tagged)) {
 
2551
                        HTList *cur = tagged;
 
2552
                        char *name;
 
2553
 
 
2554
                        while (!overrun &&
 
2555
                               (name = (char *)HTList_nextObject(cur))!=NULL) {
 
2556
                            if (*s == 'l' && (cp = strrchr(name, '/')))
 
2557
                                cp++;
 
2558
                            else
 
2559
                                cp = name;
 
2560
                            StrAllocCat(taglist, cp);
 
2561
                            StrAllocCat(taglist, " "); /* should this be %20?*/
 
2562
                        }
 
2563
                    }
 
2564
                    if (taglist) {
 
2565
                        /* could HTUnescape here... */
 
2566
                        cp = taglist;
 
2567
                        while (*cp)
 
2568
                            *BP_INC = *cp++;
 
2569
                        FREE(taglist);
 
2570
                    }
 
2571
                    break;
 
2572
                default:
 
2573
                    *BP_INC = '%';
 
2574
                    *BP_INC = *s;
 
2575
                    break;
 
2576
            }
 
2577
        } else {
 
2578
            /*
 
2579
             *  Other chars come from the lynx.cfg or
 
2580
             *  the default.  Let's assume there isn't
 
2581
             *  anything weird there that needs escaping.
 
2582
             */
 
2583
            *BP_INC =*s;
 
2584
        }
 
2585
        s++;
 
2586
    }
 
2587
    if (overrun & url_syntax) {
 
2588
        HTAlert(gettext("Temporary URL or list would be too long."));
 
2589
        bp = buf;       /* set to start, will return empty string as URL */
 
2590
    }
 
2591
    *bp = '\0';
 
2592
    return buf;
 
2593
}
 
2594
 
 
2595
#endif /* DIRED_SUPPORT */