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
37
#include <LYGlobalDefs.h>
39
#include <LYStrings.h>
40
#include <LYCharUtils.h>
41
#include <LYStructs.h>
42
#include <LYHistory.h>
49
#include <LYMainLoop.h>
57
#define EXT_TAR_GZ ".tgz"
58
#define EXT_TAR_Z ".taz"
61
#define EXT_TAR_GZ ".tar.gz"
62
#define EXT_TAR_Z ".tar.Z"
67
#define DIRED_MAXBUF 512
74
#define INSTALLDIRS_FILE "instdirs.htm"
76
#define INSTALLDIRS_FILE ".installdirs.html"
77
#endif /* FNAMES_8_3 */
78
#endif /* OK_INSTALL */
80
PRIVATE char *get_filename PARAMS((
86
PRIVATE int permit_location PARAMS((
90
#endif /* OK_PERMIT */
92
PRIVATE char *render_item PARAMS((
100
PRIVATE struct dired_menu *menu_head = NULL;
111
struct dired_menu *next;
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.
121
{ 0, "", "Change directory",
122
"", "LYNXDIRED://CHDIR", NULL },
125
"(in current directory)", "LYNXDIRED://NEW_FILE%d", NULL },
127
{ 0, "", "New Directory",
128
"(in current directory)", "LYNXDIRED://NEW_FOLDER%d", NULL },
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
138
{ DE_DIR, "", "Install",
139
"selected directory to new location", "LYNXDIRED://INSTALL_SRC%p", NULL },
140
#endif /* OK_INSTALL */
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 },
147
{ DE_SYMLINK, "", "Modify Name",
148
"(of selected symbolic link)", "LYNXDIRED://MODIFY_NAME%p", NULL },
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 */
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 },
163
{ DE_SYMLINK, "", "Change Location",
164
"(of selected symbolic link)", "LYNXDIRED://MODIFY_LOCATION%p", NULL },
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 },
172
{ DE_SYMLINK, "", "Remove Symbolic Link",
173
"(current selection)", "LYNXDIRED://REMOVE_SINGLE%p", NULL },
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 */
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 */
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 },
190
{ DE_FILE, ".tgz", "Expand",
191
"(current selection)", "LYNXDIRED://UNTAR_GZ%p", NULL },
192
#endif /* OK_TAR && OK_GZIP && !ARCHIVE_ONLY */
195
{ DE_FILE, EXT_Z, "Uncompress",
196
"(current selection)", "LYNXDIRED://DECOMPRESS%p", NULL },
197
#endif /* ARCHIVE_ONLY */
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 */
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 */
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 */
216
"(current selection)", "LYNXDIRED://TAR%p", NULL },
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 */
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 */
230
{ DE_DIR, "", "Package and compress",
231
"(using zip)", "LYNXDIRED://ZIP%p", NULL },
234
{ DE_FILE, "", "Compress",
235
"(using Unix compress)", "LYNXDIRED://COMPRESS%p", NULL },
238
{ DE_FILE, "", "Compress",
239
"(using gzip)", "LYNXDIRED://GZIP%p", NULL },
243
{ DE_FILE, "", "Compress",
244
"(using zip)", "LYNXDIRED://ZIP%p", NULL },
247
{ DE_TAG, "", "Move all tagged items to another location.",
248
"", "LYNXDIRED://MOVE_TAGGED%d", NULL },
251
{ DE_TAG, "", "Install tagged files into another directory.",
252
"", "LYNXDIRED://INSTALL_SRC%00", NULL },
255
{ DE_TAG, "", "Remove all tagged files and directories.",
256
"", "LYNXDIRED://REMOVE_TAGGED", NULL },
258
{ DE_TAG, "", "Untag all tagged files and directories.",
259
"", "LYNXDIRED://CLEAR_TAGGED", NULL },
265
PRIVATE BOOLEAN cannot_stat ARGS1(CONST char *, name)
268
HTSprintf0(&tmpbuf, gettext("Unable to get status of '%s'."), name);
274
#define OK_STAT(name, sb) (stat(name, sb) == 0)
276
PRIVATE BOOLEAN ok_stat ARGS2(CONST char *, name, struct stat*, sb)
278
CTRACE((tfp, "testing ok_stat(%s)\n", name));
279
if (!OK_STAT(name, sb)) {
280
return cannot_stat(name);
286
PRIVATE BOOLEAN ok_lstat ARGS2(char *, name, struct stat*, sb)
288
CTRACE((tfp, "testing ok_lstat(%s)\n", name));
289
if (lstat(name, sb) < 0) {
290
return cannot_stat(name);
295
#define ok_lstat(name,sb) ok_stat(name,sb)
298
PRIVATE BOOLEAN ok_file_or_dir ARGS1(struct stat*, sb)
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."));
308
#ifdef OK_INSTALL /* currently only used in local_install */
309
PRIVATE BOOLEAN ok_localname ARGS2(char*, dst, CONST char*, src)
311
struct stat dir_info;
313
if (!ok_stat(src, &dir_info)
314
|| !ok_file_or_dir(&dir_info)) {
317
if (strlen(src) >= DIRED_MAXBUF) {
318
CTRACE((tfp, "filename too long in ok_localname!\n"));
324
#endif /* OK_INSTALL */
327
* Execute DIRED command, return -1 or 0 on failure, 1 success.
329
PRIVATE int LYExecv ARGS3(
335
#if defined(VMS) || defined(_WINDOWS)
336
CTRACE((tfp, "LYExecv: Called inappropriately! (path=%s)\n", path));
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;
349
#ifdef HAVE_TYPE_UNIONWAIT
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]));
361
rc = 1; /* It will work */
363
pid = fork(); /* fork and execute command */
367
HTSprintf0(&tmpbuf, gettext("Unable to %s due to system error!"), msg);
369
break; /* don't fall thru! - KW */
373
execvp(path, argv); /* this uses our $PATH */
377
exit(EXIT_FAILURE); /* execv failed, give wait() something to look at */
380
default: /* parent */
382
while (wait(&wstatus) != pid)
385
while (-1 == waitpid(pid, &wstatus, 0)) { /* wait for child */
391
if (errno == ERESTARTSYS)
393
#endif /* ERESTARTSYS */
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!"),
406
#endif /* __DJGPP__ */
410
* Screen may have message from the failed execv'd command.
411
* Give user time to look at it before screen refresh.
422
#endif /* VMS || _WINDOWS */
426
PRIVATE int make_directory ARGS1(char *, path)
431
if ((program = HTGetProgramPath(ppMKDIR)) != NULL) {
435
HTSprintf0(&msg,"make directory %s", path);
438
args[2] = (char *) 0;
439
code = (LYExecv(program, args, msg) <= 0) ? -1 : 1;
443
code = mkdir(path) ? -1 : 1;
445
code = mkdir(path, 0777) ? -1 : 1;
451
PRIVATE int remove_file ARGS1(char *, path)
456
if ((program = HTGetProgramPath(ppRM)) != NULL) {
463
args[3] = (char *) 0;
464
HTSprintf0(&tmpbuf, gettext("remove %s"), path);
465
code = LYExecv(program, args, tmpbuf);
468
code = remove(path) ? -1 : 1;
473
PRIVATE int remove_directory ARGS1(char *, path)
478
if ((program = HTGetProgramPath(ppRMDIR)) != NULL) {
484
args[2] = (char *) 0;
485
HTSprintf0(&tmpbuf, gettext("remove %s"), path);
486
code = LYExecv(program, args, tmpbuf);
489
code = rmdir(path) ? -1 : 1;
494
PRIVATE int touch_file ARGS1(char *, path)
499
if ((program = HTGetProgramPath(ppTOUCH)) != NULL) {
503
HTSprintf0(&msg, gettext("touch %s"), path);
506
args[2] = (char *) 0;
507
code = (LYExecv(program, args, msg) <= 0) ? -1 : 1;
511
if ((fp = fopen(path, "w")) != 0) {
521
PRIVATE int move_file ARGS2(char *, source, char *, target)
526
if ((program = HTGetProgramPath(ppMV)) != NULL) {
530
HTSprintf0(&msg, gettext("move %s to %s"), source, target);
534
args[3] = (char *) 0;
535
code = (LYExecv(program, args, msg) <= 0) ? -1 : 1;
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));
547
if ((code = rename(source, target)) != 0)
548
if ((code = LYCopyFile(source, target)) >= 0)
549
code = remove(source);
552
if (actual != target) {
559
PRIVATE BOOLEAN not_already_exists ARGS1(char *, name)
561
struct stat dir_info;
563
if (!OK_STAT(name, &dir_info)) {
564
if (errno != ENOENT) {
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."));
574
HTAlert(gettext("The specified name is already in use! Request ignored."));
579
PRIVATE BOOLEAN dir_has_same_owner ARGS2(struct stat *, info, int, owner)
581
if (S_ISDIR(info->st_mode)) {
582
if ((int) info->st_uid == owner) {
585
HTAlert(gettext("Destination has different owner! Request denied."));
588
HTAlert(gettext("Destination is not a valid directory! Request denied."));
594
* Remove all tagged files and directories.
596
PRIVATE int remove_tagged NOARGS
599
BOOL will_clear = TRUE;
602
char *testpath = NULL;
603
struct stat dir_info;
607
if (HTList_isEmpty(tagged)) /* should never happen */
610
ans = HTConfirm(gettext("Remove all tagged files and directories?"));
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);
621
* Check the current status of the path to be deleted.
623
if (!ok_stat(testpath, &dir_info)) {
627
if (remove_file(testpath) <= 0) {
628
if (count == 0) count = -1;
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.
652
PRIVATE int modify_tagged ARGS1(
661
char *srcpath = NULL;
662
struct stat dir_info;
666
if (HTList_isEmpty(tagged)) /* should never happen */
669
_statusline(gettext("Enter new location for tagged items: "));
672
LYgetstr(tmpbuf, VISIBLE, sizeof(tmpbuf), NORECALL);
673
if (strlen(tmpbuf)) {
675
* Determine the ownership of the current location.
678
* This test used to always fail from the dired menu...
679
* changed to something that hopefully makes more sense - KW
681
if (testpath && *testpath && 0!=strcmp(testpath,"/")) {
683
* testpath passed in and is not empty and not a single "/"
684
* (which would probably be bogus) - use it.
689
* Prepare to get directory path from one of the tagged files.
691
cp = HTList_lastObject(tagged);
692
testpath = NULL; /* Won't be needed any more in this function,
693
set to NULL as a flag. */
696
if (testpath == NULL) {
698
* Get the directory containing the file or subdir.
701
cp = strip_trailing_slash(cp);
702
cp = HTParse(".", cp, PARSE_PATH+PARSE_PUNCTUATION);
703
savepath = HTURLPath_toFile(cp, TRUE, FALSE);
705
} else { /* Last resort, should never happen. */
706
savepath = HTURLPath_toFile(".", TRUE, FALSE);
709
if (!strncmp(cp, "file://localhost", 16)) {
711
} else if (isFILE_URL(cp)) {
714
savepath = HTURLPath_toFile(cp, TRUE, FALSE);
717
if (!ok_stat(savepath, &dir_info)) {
723
* Save the owner of the current location for later use.
724
* Also save the device and inode for location checking/
726
dev = dir_info.st_dev;
727
inode = dir_info.st_ino;
728
owner = dir_info.st_uid;
731
* Replace ~/ references to the home directory.
733
if (!strncmp(tmpbuf, "~/", 2)) {
735
StrAllocCopy(cp1, Home_Dir());
736
StrAllocCat(cp1, (tmpbuf + 1));
737
if (strlen(cp1) > (sizeof(tmpbuf) - 1)) {
738
HTAlert(gettext("Path too long"));
743
LYstrncpy(tmpbuf, cp1, sizeof(tmpbuf)-1);
748
* If path is relative, prefix it with current location.
750
if (!LYIsPathSep(tmpbuf[0])) {
751
LYAddPathSep(&savepath);
752
StrAllocCat(savepath,tmpbuf);
754
StrAllocCopy(savepath,tmpbuf);
758
* stat() the target location to determine type and ownership.
760
if (!ok_stat(savepath, &dir_info)) {
766
* Make sure the source and target locations are not the same place.
768
if (dev == dir_info.st_dev && inode == dir_info.st_ino) {
769
HTAlert(gettext("Source and destination are the same location - request ignored!"));
775
* Make sure the target location is a directory which is owned
776
* by the same uid as the owner of the current location.
778
if (dir_has_same_owner(&dir_info, owner)) {
783
* Move all tagged items to the target location.
785
while ((cp = (char *)HTList_nextObject(tag)) != NULL) {
786
srcpath = HTfullURL_toFile(cp);
788
if (move_file(srcpath, savepath) < 0) {
806
* Modify the name of the specified item.
808
PRIVATE int modify_name ARGS1(
812
char tmpbuf[DIRED_MAXBUF];
813
char *newpath = NULL;
814
struct stat dir_info;
818
* Determine the status of the selected item.
820
testpath = strip_trailing_slash(testpath);
822
if (ok_stat(testpath, &dir_info)) {
824
* Change the name of the file or directory.
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: ");
831
return ok_file_or_dir(&dir_info);
833
LYstrncpy(tmpbuf, LYPathLeaf(testpath), sizeof(tmpbuf)-1);
834
if (get_filename(cp, tmpbuf, sizeof(tmpbuf)) == NULL)
838
* Do not allow the user to also change the location at this time.
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);
846
StrAllocCopy(newpath, tmpbuf);
849
* Make sure the destination does not already exist.
851
if (not_already_exists(newpath)) {
852
code = move_file(testpath, newpath);
862
* Change the location of a file or directory.
864
PRIVATE int modify_location ARGS1(
872
char *newpath = NULL;
873
char *savepath = NULL;
874
struct stat dir_info;
878
* Determine the status of the selected item.
880
testpath = strip_trailing_slash(testpath);
881
if (!ok_stat(testpath, &dir_info)) {
886
* Change the location of the file or directory.
888
if (S_ISDIR(dir_info.st_mode)) {
889
if (HTGetProgramPath(ppMV) != NULL) {
890
cp = gettext("Enter new location for directory: ");
892
HTAlert(COULD_NOT_ACCESS_DIR);
895
} else if (S_ISREG(dir_info.st_mode)) {
896
cp = gettext("Enter new location for file: ");
898
return ok_file_or_dir(&dir_info);
900
LYstrncpy(tmpbuf, testpath, sizeof(tmpbuf)-1);
901
*LYPathLeaf(tmpbuf) = '\0';
902
if (get_filename(cp, tmpbuf, sizeof(tmpbuf)) == NULL)
904
if (strlen(tmpbuf)) {
905
StrAllocCopy(savepath, testpath);
906
StrAllocCopy(newpath, testpath);
909
* Allow ~/ references to the home directory.
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);
917
if (LYisAbsPath(tmpbuf)) {
918
StrAllocCopy(newpath, tmpbuf);
919
} else if ((cp = LYLastPathSep(newpath)) != NULL) {
921
StrAllocCat(newpath, tmpbuf);
923
HTAlert(gettext("Unexpected failure - unable to find trailing path separator"));
930
* Make sure the source and target have the same owner (uid).
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)) {
940
* Make sure the source and target are not the same location.
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!"));
947
else if (dir_has_same_owner(&dir_info, owner)) {
948
code = move_file(savepath,newpath);
957
* Modify name or location of a file or directory on localhost.
959
PUBLIC int local_modify ARGS2(
965
char testpath[DIRED_MAXBUF]; /* a bit ridiculous */
968
if (!HTList_isEmpty(tagged)) {
969
cp = HTpartURL_toFile(doc->address);
971
count = modify_tagged(cp);
974
if (doc->link > (nlinks-count - 1))
975
doc->link = (nlinks-count - 1);
976
doc->link = (doc->link < 0) ?
980
} else if (doc->link < 0 || doc->link > nlinks) {
988
* Do not allow simultaneous change of name and location as in Unix.
989
* This reduces functionality but reduces difficulty for the novice.
992
_statusline(gettext("Modify name, location, or permission (n, l, or p): "));
994
_statusline(gettext("Modify name or location (n or l): "));
995
#endif /* OK_PERMIT */
996
ans = LYgetch_single();
998
if (strchr("NLP", ans) != NULL) {
999
cp = HTfullURL_toFile(links[doc->link].lname);
1000
if (strlen(cp) >= DIRED_MAXBUF) {
1004
LYstrncpy(testpath, cp, sizeof(testpath)-1);
1008
return(modify_name(testpath));
1009
} else if (ans == 'L') {
1010
if (modify_location(testpath)) {
1011
if (doc->link == (nlinks-1))
1016
} else if (ans == 'P') {
1017
return(permit_location(NULL, testpath, newpath));
1018
#endif /* OK_PERMIT */
1021
* Code for changing ownership needed here.
1023
HTAlert(gettext("This feature not yet implemented!"));
1030
* Create a new empty file in the current directory.
1032
PRIVATE int create_file ARGS1(
1033
char *, current_location)
1036
char tmpbuf[DIRED_MAXBUF];
1037
char *testpath = NULL;
1038
char *bad_chars = ".~/";
1041
if (get_filename(gettext("Enter name of file to create: "),
1042
tmpbuf, sizeof(tmpbuf)) != NULL) {
1044
if (!no_dotfiles && show_dotfiles) {
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);
1055
* Append the target filename to the current location.
1057
StrAllocCat(testpath, tmpbuf);
1060
* Make sure the target does not already exist
1062
if (not_already_exists(testpath)) {
1063
code = touch_file(testpath);
1072
* Create a new directory in the current directory.
1074
PRIVATE int create_directory ARGS1(
1075
char *, current_location)
1078
char tmpbuf[DIRED_MAXBUF];
1079
char *testpath = NULL;
1080
char *bad_chars = ".~/";
1083
if (get_filename(gettext("Enter name for new directory: "),
1084
tmpbuf, sizeof(tmpbuf)) != NULL) {
1086
if (!no_dotfiles && show_dotfiles) {
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);
1096
StrAllocCat(testpath, tmpbuf);
1099
* Make sure the target does not already exist.
1101
if (not_already_exists(testpath)) {
1102
code = make_directory(testpath);
1111
* Create a file or a directory at the current location.
1113
PUBLIC int local_create ARGS1(
1118
char testpath[DIRED_MAXBUF];
1120
cp = HTfullURL_toFile(doc->address);
1121
if (strlen(cp) >= DIRED_MAXBUF) {
1125
strcpy(testpath,cp);
1128
_statusline(gettext("Create file or directory (f or d): "));
1129
ans = LYgetch_single();
1132
return(create_file(testpath));
1133
} else if (ans == 'D') {
1134
return(create_directory(testpath));
1141
* Remove a single file or directory.
1143
PRIVATE int remove_single ARGS1(
1149
struct stat dir_info;
1150
BOOL is_directory = FALSE;
1152
if (!ok_lstat(testpath, &dir_info)) {
1157
* Locate the filename portion of the path.
1159
if ((cp = LYLastPathSep(testpath)) != NULL) {
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) {
1169
gettext("Remove directory '%s'?"), cp);
1172
gettext("Remove directory?"));
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);
1179
HTSprintf0(&tmpbuf, gettext("Remove file?"));
1182
} else if (S_ISLNK(dir_info.st_mode)) {
1183
if (strlen(cp) < 50) {
1184
HTSprintf0(&tmpbuf, gettext("Remove symbolic link '%s'?"), cp);
1186
HTSprintf0(&tmpbuf, gettext("Remove symbolic link?"));
1190
cannot_stat(testpath);
1195
if (HTConfirm(tmpbuf) == YES) {
1197
? remove_directory(testpath)
1198
: remove_file(testpath);
1205
* Remove a file or a directory.
1207
PUBLIC int local_remove ARGS1(
1211
char testpath[DIRED_MAXBUF];
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) ?
1221
} else if (doc->link < 0 || doc->link > nlinks) {
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) {
1231
strcpy(testpath, tp);
1234
if ((i = strlen(testpath)) && testpath[i - 1] == '/')
1235
testpath[(i - 1)] = '\0';
1237
if (remove_single(testpath)) {
1238
if (doc->link == (nlinks - 1))
1248
PRIVATE char LYValidPermitFile[LY_MAXPATH] = "\0";
1250
PRIVATE long permit_bits ARGS1(char *, string_mode)
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. */
1266
* Handle DIRED permissions.
1268
PRIVATE int permit_location ARGS3(
1274
HTAlert(gettext("Sorry, don't know how to permit non-UNIX files yet."));
1277
static char tempfile[LY_MAXPATH] = "\0";
1279
char tmpdst[LY_MAXPATH];
1280
struct stat dir_info;
1281
CONST char *program;
1288
char * user_filename;
1291
srcpath = strip_trailing_slash(srcpath);
1294
* A couple of sanity tests.
1296
if (!ok_lstat(srcpath, &dir_info)
1297
|| !ok_file_or_dir(&dir_info))
1300
user_filename = LYPathLeaf(srcpath);
1302
LYRemoveTemp(tempfile);
1303
if ((fp0 = LYOpenTemp(tempfile, HTML_SUFFIX, "w")) == NULL) {
1304
HTAlert(gettext("Unable to open permit options file"));
1309
* Make the tempfile a URL.
1311
LYLocalFileToURL(newpath, tempfile);
1312
LYRegisterUIPage(*newpath, UIP_PERMIT_OPTIONS);
1314
group_name = HTAA_GidToName (dir_info.st_gid);
1315
LYstrncpy(LYValidPermitFile,
1317
(sizeof(LYValidPermitFile) - 1));
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);
1323
* Prevent filenames which include '#' or '?' from messing it up.
1325
char * srcpath_url = HTEscape(srcpath, URL_PATH);
1326
fprintf(fp0, "<Form Action=\"%s//PERMIT_LOCATION%s\">\n",
1327
STR_LYNXDIRED, srcpath_url);
1331
fprintf(fp0, "<Ol><Li>%s<Br><Br>\n", gettext("Specify permissions below:"));
1332
fprintf(fp0, "%s:<Br>\n", gettext("Owner:"));
1334
"<Input Type=\"checkbox\" Name=\"mode\" Value=\"IRUSR\" %s> Read<Br>\n",
1335
(dir_info.st_mode & S_IRUSR) ? "checked" : "");
1337
"<Input Type=\"checkbox\" Name=\"mode\" Value=\"IWUSR\" %s> Write<Br>\n",
1338
(dir_info.st_mode & S_IWUSR) ? "checked" : "");
1340
* If restricted, only change eXecute permissions on directories.
1342
if (!no_change_exec_perms || S_ISDIR(dir_info.st_mode))
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");
1348
fprintf(fp0, "%s %s:<Br>\n", gettext("Group"), group_name);
1350
"<Input Type=\"checkbox\" Name=\"mode\" Value=\"IRGRP\" %s> Read<Br>\n",
1351
(dir_info.st_mode & S_IRGRP) ? "checked" : "");
1353
"<Input Type=\"checkbox\" Name=\"mode\" Value=\"IWGRP\" %s> Write<Br>\n",
1354
(dir_info.st_mode & S_IWGRP) ? "checked" : "");
1356
* If restricted, only change eXecute permissions on directories.
1358
if (!no_change_exec_perms || S_ISDIR(dir_info.st_mode))
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");
1364
fprintf(fp0, "%s<Br>\n", gettext("Others:"));
1366
"<Input Type=\"checkbox\" Name=\"mode\" Value=\"IROTH\" %s> Read<Br>\n",
1367
(dir_info.st_mode & S_IROTH) ? "checked" : "");
1369
"<Input Type=\"checkbox\" Name=\"mode\" Value=\"IWOTH\" %s> Write<Br>\n",
1370
(dir_info.st_mode & S_IWOTH) ? "checked" : "");
1372
* If restricted, only change eXecute permissions on directories.
1374
if (!no_change_exec_perms || S_ISDIR(dir_info.st_mode))
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");
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",
1385
fprintf(fp0, "</Body></Html>");
1388
LYforce_no_cache = TRUE;
1389
return(PERMIT_FORM_RESULT); /* Special flag for LYMainLoop */
1391
} else { /* The form being activated. */
1392
mode_t new_mode = 0;
1395
* Make sure we have a valid set-permission
1396
* file comparison string loaded via a previous
1397
* call with srcpath != NULL. - KW
1399
if (LYValidPermitFile[0] == '\0') {
1401
HTAlert(INVALID_PERMIT_URL);
1403
fprintf(stderr, "%s\n", INVALID_PERMIT_URL);
1404
CTRACE((tfp, "permit_location: called for <%s>.\n",
1406
destpath : "NULL URL pointer")));
1410
while (*cp != '\0' && *cp != '?') { /* Find filename */
1414
return(0); /* Nothing to permit. */
1416
*cp++ = '\0'; /* Null terminate file name and
1417
start working on the masks. */
1419
/* Will now operate only on filename part. */
1420
if ((destpath = HTURLPath_toFile(destpath, TRUE, FALSE)) == 0)
1422
if (strlen(destpath) >= LY_MAXPATH) {
1426
strcpy(tmpdst, destpath);
1431
* Make sure that the file string is the one from
1432
* the last displayed File Permissions menu. - KW
1434
if (strcmp(destpath, LYValidPermitFile)) {
1436
HTAlert(INVALID_PERMIT_URL);
1438
fprintf(stderr, "%s\n", INVALID_PERMIT_URL);
1439
CTRACE((tfp, "permit_location: called for file '%s'.\n",
1445
* A couple of sanity tests.
1447
destpath = strip_trailing_slash(destpath);
1448
if (!ok_stat(destpath, &dir_info)
1449
|| !ok_file_or_dir(&dir_info)) {
1454
* Cycle over permission strings.
1456
while(*cp != '\0') {
1459
while(*cr != '\0' && *cr != '&') { /* GET data split by '&'. */
1465
if (strncmp(cp, "mode=", 5) == 0) { /* Magic string. */
1466
long mask = permit_bits(cp + 5);
1470
* If restricted, only change eXecute
1471
* permissions on directories.
1473
if (!no_change_exec_perms
1474
|| strchr(cp+5, 'X') == NULL
1475
|| S_ISDIR(dir_info.st_mode))
1478
HTAlert(gettext("Invalid mode format."));
1482
HTAlert(gettext("Invalid syntax format."));
1492
if ((program = HTGetProgramPath(ppCHMOD)) != NULL) {
1495
char *tmpbuf = NULL;
1497
HTSprintf0(&tmpbuf, "chmod %.4o %s", (unsigned int)new_mode, destpath);
1498
sprintf(amode, "%.4o", (unsigned int)new_mode);
1502
args[3] = (char *) 0;
1503
if (LYExecv(program, args, tmpbuf) <= 0) {
1509
if (chmod(destpath, new_mode) < 0)
1512
LYforce_no_cache = TRUE; /* Force update of dired listing. */
1517
#endif /* OK_PERMIT */
1520
* Display or remove a tag from a given link.
1522
PUBLIC void tagflag ARGS2(
1527
LYmove(links[cur].ly, 2);
1528
lynx_stop_reverse();
1535
#if defined(FANCY_CURSES) || defined(USE_SLANG)
1537
LYHideCursor(); /* get cursor out of the way */
1539
#endif /* FANCY CURSES || USE_SLANG */
1541
* Never hide the cursor if there's no FANCY CURSES.
1543
LYmove(links[cur].ly, links[cur].lx);
1550
* Handle DIRED tags.
1552
PUBLIC void showtags ARGS1(
1559
for (i = 0; i < nlinks; i++) {
1561
while ((name = HTList_nextObject(s)) != NULL) {
1562
if (!strcmp(links[i].lname, name)) {
1570
PRIVATE char * DirectoryOf ARGS1(
1576
StrAllocCopy(result, pathname);
1577
leaf = LYPathLeaf(result);
1579
if (leaf != result) {
1580
CONST char *result1 = 0;
1583
if (!LYisRootPath(result))
1584
LYTrimPathSep(result);
1585
result1 = wwwName(result);
1586
StrAllocCopy (result, result1);
1593
* Convert filenames to acceptable 8+3 names when necessary. Make a copy of
1594
* the parameter if we must modify it.
1596
PRIVATE char * LYonedot ARGS1(
1600
static char line1[LY_MAXPATH];
1602
if (pathconf (line, _PC_NAME_MAX) <= 12) {
1603
LYstrncpy(line1, line, sizeof(line1)-1);
1605
if ((dot = strrchr(line1, '.')) == 0
1606
|| LYLastPathSep(dot) != 0) {
1608
} else if (strlen(dot) == 1) {
1619
#define LYonedot(path) path
1620
#endif /* __DJGPP__ */
1622
PRIVATE char * match_op ARGS2(
1623
CONST char *, prefix,
1626
int len = strlen(prefix);
1628
if (!strncmp("LYNXDIRED://", data, 12)
1629
&& !strncmp(prefix, data + 12, (unsigned)len)) {
1631
#if defined(USE_DOS_DRIVES)
1632
if (data[len] == '/') { /* this is normal */
1642
* Construct the appropriate system command taking care to
1643
* escape all path references to avoid spoofing the shell.
1645
PRIVATE char *build_command ARGS3(
1650
char *buffer = NULL;
1651
CONST char *program;
1652
CONST char *tar_path = HTGetProgramPath(ppTAR);
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);
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."));
1675
#endif /* OK_UUDECODE && !ARCHIVE_ONLY */
1678
if (tar_path != NULL) {
1679
# ifndef ARCHIVE_ONLY
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);
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);
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);
1720
# endif /* !ARCHIVE_ONLY */
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);
1739
# endif /* OK_GZIP */
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);
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);
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);
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);
1793
#endif /* !ARCHIVE_ONLY */
1794
#endif /* OK_GZIP */
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);
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);
1821
# endif /* !ARCHIVE_ONLY */
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);
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.)
1847
PUBLIC int local_dired ARGS1(
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[] */
1854
char *tmpbuf = NULL;
1855
char *buffer = NULL;
1856
char *dirname = NULL;
1857
BOOL do_pop_doc = TRUE;
1859
line_url = doc->address;
1860
CTRACE((tfp, "local_dired: called for <%s>.\n",
1862
line_url : gettext("NULL URL pointer"))));
1863
HTUnEscapeSome(line_url, "/"); /* don't mess too much with *doc */
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
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;
1881
} else if ((arg = match_op("INSTALL_SRC", line)) != 0) {
1882
local_install(NULL, arg, &tp);
1889
} else if ((arg = match_op("INSTALL_DEST", line)) != 0) {
1890
local_install(arg, NULL, &tp);
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;
1903
} else if ((arg = match_op("PERMIT_SRC", line)) != 0) {
1904
permit_location(NULL, arg, &tp);
1907
* One of the checks may have failed.
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) {
1925
} else if ((arg = match_op("UPLOAD", line)) != 0) {
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.
1932
if (LYUpload(line_url))
1933
LYforce_no_cache = TRUE;
1935
LYTrimPathSep(line);
1936
if (LYLastPathSep(line) == NULL) {
1941
buffer = build_command(line, dirname, arg);
1944
if ((int) strlen(buffer) < LYcols - 15) {
1945
HTSprintf0(&tmpbuf, gettext("Executing %s "), buffer);
1948
gettext("Executing system command. This might take a while."));
1950
_statusline(tmpbuf);
1952
printf("%s\r\n", tmpbuf);
1955
HadVMSInterrupt = FALSE;
1958
LYforce_no_cache = TRUE;
1973
* Provide a menu of file management options.
1975
PUBLIC int dired_options ARGS2(
1979
static char tempfile[LY_MAXPATH];
1982
lynx_list_item_type *nxt;
1983
struct stat dir_info;
1987
BOOLEAN nothing_tagged;
1989
struct dired_menu *mp;
1992
if ((fp0 = InternalPageFP(tempfile, FALSE)) == 0)
1996
* Make the tempfile a URL.
1998
LYLocalFileToURL(newfile, tempfile);
1999
LYRegisterUIPage(*newfile, UIP_DIRED_MENU);
2001
if (doc->link > -1 && doc->link < (nlinks+1)) {
2002
path = HTfullURL_toFile(links[doc->link].lname);
2003
LYTrimPathSep(path);
2005
if (!ok_lstat(path, &dir_info)) {
2012
StrAllocCopy(path, "");
2015
dir = HTfullURL_toFile(doc->address);
2018
nothing_tagged = (BOOL) (HTList_isEmpty(tagged));
2020
BeginInternalPage(fp0, DIRED_MENU_TITLE, DIRED_MENU_HELP);
2022
fprintf(fp0, "<em>%s</em> %s<br>\n", gettext("Current directory:"), dir);
2024
if (nothing_tagged) {
2025
fprintf(fp0, "<em>%s</em> ", gettext("Current selection:"));
2027
fprintf(fp0, "%s<p>\n", path);
2029
fprintf(fp0, "%s.<p>\n", gettext("Nothing currently selected."));
2033
* Write out number of tagged items, and names of first
2034
* few of them relative to current (in the DIRED sense)
2037
int n = HTList_count(tagged);
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, "/");
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"));
2053
LYEntify(&cp1, TRUE); /* _should_ do this everywhere... */
2054
fprintf(fp0, "%s<br>\n %s",
2055
(i == 1 ? "" : " ,"), cp1);
2059
fprintf(fp0," , ...");
2061
fprintf(fp0, "<p>\n");
2066
* If menu_head is NULL then use defaults and link them together now.
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;
2075
for (mp = menu_head; mp != NULL; mp = mp->next) {
2076
if (mp->cond != DE_TAG && !nothing_tagged)
2078
if (mp->cond == DE_TAG && nothing_tagged)
2080
if (mp->cond == DE_DIR &&
2081
(!*path || !S_ISDIR(dir_info.st_mode)))
2083
if (mp->cond == DE_FILE &&
2084
(!*path || !S_ISREG(dir_info.st_mode)))
2087
if (mp->cond == DE_SYMLINK &&
2088
(!*path || !S_ISLNK(dir_info.st_mode)))
2092
(strlen(path) < strlen(mp->sfx) ||
2093
strcmp(mp->sfx, &path[(strlen(path) - strlen(mp->sfx))]) != 0))
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));
2108
if (uploaders != NULL) {
2109
fprintf(fp0, "<p>Upload to current directory:<p>\n");
2110
for (count = 0, nxt = uploaders;
2112
nxt = nxt->next, count++) {
2114
"<a href=\"LYNXDIRED://UPLOAD=%d/TO=%s\"> %s </a><br>\n",
2115
count, dir, nxt->name);
2120
EndInternalPage(fp0);
2123
LYforce_no_cache = TRUE;
2129
* Check DIRED filename.
2131
PRIVATE char *get_filename ARGS3(
2138
_statusline(prompt);
2140
LYgetstr(buf, VISIBLE, bufsize, NORECALL);
2141
if (strstr(buf, "../") != NULL) {
2142
HTAlert(gettext("Illegal filename; request ignored."));
2146
if (no_dotfiles || !show_dotfiles) {
2147
cp = LYLastPathSep(buf); /* find last slash */
2153
HTAlert(gettext("Illegal filename; request ignored."));
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
2172
#endif /* LY_FIND_LEAKS */
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
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
2186
PRIVATE int fill_argv_for_execv ARGS5(
2190
CONST char *, cmd_args,
2197
if (*argvp == NULL) {
2198
*argvp = typecallocn(char *, LYEXECV_MAX_ARGC+1);
2201
#ifdef LY_FIND_LEAKS
2202
atexit(clear_install_path);
2206
args[n++] = cmd_path;
2208
StrAllocCopy(*pathp, cmd_args);
2209
cp = strtok(*pathp, " ");
2211
while (cp && (n < LYEXECV_MAX_ARGC - reserve)) {
2213
cp = strtok(NULL, " ");
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));
2224
args[n] = (char *)0;
2229
* Install the specified file or directory.
2231
PUBLIC BOOLEAN local_install ARGS3(
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;
2243
char *tmpdest = NULL;
2245
int n = 0; /* indices into 'args[]' */
2246
static int src = -1;
2247
CONST char *program;
2249
if ((program = HTGetProgramPath(ppINSTALL)) == NULL) {
2250
HTAlert(gettext("Install in the selected directory not permitted."));
2255
* Determine the status of the selected item.
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)) {
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)) {
2272
LYforce_no_cache = TRUE;
2273
LYLocalFileToURL(newpath, Home_Dir());
2274
LYAddHtmlSep(newpath);
2275
StrAllocCat(*newpath, INSTALLDIRS_FILE);
2276
LYRegisterUIPage(*newpath, UIP_INSTALL);
2280
/* deal with ~/ or /~/ at the beginning - kw */
2281
if (destpath[0] == '~' &&
2282
(destpath[1] == '/' || destpath[1] == '\0')) {
2284
} else if (destpath[0] == '/' && destpath[1] == '~' &&
2285
(destpath[2] == '/' || destpath[2] == '\0')) {
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);
2298
destpath = strip_trailing_slash(destpath);
2300
if (!ok_stat(destpath, &dir_info)) {
2303
} else if (!S_ISDIR(dir_info.st_mode)) {
2304
HTAlert(gettext("The selected item is not a directory! Request ignored."));
2307
} else if (0 /*directory not writable*/) {
2308
HTAlert(gettext("Install in the selected directory not permitted."));
2313
statusline(gettext("Just a moment, ..."));
2315
/* fill in the fixed args, if not already done - kw */
2316
if (src > 0 && install_argp) {
2320
n = fill_argv_for_execv(&install_argp, &install_path,
2326
#endif /* INSTALL_ARGS */
2330
HTAlert(gettext("Error buiding install args"));
2336
args = install_argp;
2338
args[n++] = destpath;
2339
args[n] = (char *)0;
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"),
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"),
2355
return 0; /* don't do it */
2357
args[src] = savepath;
2358
HTSprintf0(&tmpbuf, "install %s in %s", savepath, destpath);
2359
if (LYExecv(program, args, tmpbuf) <= 0) {
2367
HTSprintf0(&tmpbuf, "install in %s", destpath);
2368
while ((name = (char *)HTList_nextObject(tag))) {
2370
args[src] = HTfullURL_toFile(name);
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"),
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"),
2384
continue; /* skip this source file */
2386
err = (LYExecv(program, args, tmpbuf) <= 0);
2391
return ((count == 0) ? -1 : count);
2399
HTInfoMsg(gettext("Installation complete"));
2402
#endif /* OK_INSTALL */
2407
PUBLIC void clear_tags NOARGS
2411
while ((cp = HTList_removeLastObject(tagged)) != NULL) {
2414
if (HTList_isEmpty(tagged))
2419
* Handle DIRED menu item.
2421
PUBLIC void add_menu_item ARGS1(
2424
struct dired_menu *new, *mp;
2428
* First custom menu definition causes entire default menu to be
2431
if (menu_head == defmenu)
2434
new = typecalloc(struct dired_menu);
2436
outofmem(__FILE__, "add_menu_item");
2439
* Conditional on tagged != NULL ?
2441
cp = strchr(str, ':');
2443
if (strcasecomp(str, "tag") == 0) {
2445
} else if (strcasecomp(str, "dir") == 0) {
2447
} else if (strcasecomp(str, "file") == 0) {
2448
new->cond = DE_FILE;
2450
} else if (strcasecomp(str, "link") == 0) {
2451
new->cond = DE_SYMLINK;
2452
#endif /* S_IFLNK */
2456
* Conditional on matching suffix.
2459
cp = strchr(str, ':');
2461
StrAllocCopy(new->sfx, str);
2464
cp = strchr(str, ':');
2466
StrAllocCopy(new->link, str);
2469
cp = strchr(str, ':');
2471
StrAllocCopy(new->rest, str);
2473
StrAllocCopy(new->href, cp);
2476
for (mp = menu_head; mp && mp->next != NULL; mp = mp->next)
2483
PUBLIC void reset_dired_menu NOARGS
2485
if (menu_head != defmenu) {
2486
struct dired_menu *mp, *mp_next = NULL;
2487
for (mp = menu_head; mp != NULL; mp = mp_next) {
2500
* Create URL for DIRED HREF value.
2502
PRIVATE char * render_item ARGS6(
2508
BOOLEAN, url_syntax)
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 */
2518
while (*s && !overrun) {
2527
if (!LYIsHtmlSep(*cp))
2534
if (!LYIsHtmlSep(*cp))
2540
cp = LYLastPathSep(path);
2550
if (!HTList_isEmpty(tagged)) {
2551
HTList *cur = tagged;
2555
(name = (char *)HTList_nextObject(cur))!=NULL) {
2556
if (*s == 'l' && (cp = strrchr(name, '/')))
2560
StrAllocCat(taglist, cp);
2561
StrAllocCat(taglist, " "); /* should this be %20?*/
2565
/* could HTUnescape here... */
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.
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 */
2595
#endif /* DIRED_SUPPORT */