/* ** Routines to manipulate the local filesystem. ** Written by: Rick Mallett, Carleton University ** Report problems to rmallett@ccs.carleton.ca ** Modified 18-Dec-95 David Trueman (david@cs.dal.ca): ** Added OK_PERMIT compilation option. ** Support replacement of compiled-in f)ull menu configuration via ** DIRED_MENU definitions in lynx.cfg, so that more than one menu ** can be driven by the same executable. ** Modified Oct-96 Klaus Weide (kweide@tezcat.com): ** Changed to use the library's HTList_* functions and macros for ** managing the list of tagged file URLs. ** Keep track of proper level of URL escaping, so that unusual filenames ** which contain #% etc. are handled properly (some HTUnEscapeSome()'s ** left in to be conservative, and to document where superfluous ** unescaping took place before). ** Dynamic memory instead of fixed length buffers in a few cases. ** Other minor changes to make things work as intended. ** Modified Jun-97 Klaus Weide (kweide@tezcat.com) & FM: ** Modified the code handling DIRED_MENU to do more careful ** checking of the selected file. In addition to "TAG", "FILE", and ** "DIR", DIRED_MENU definitions in lynx.cfg now also recognize LINK as ** a type. DIRED_MENU definitions with a type field of "LINK" are only ** used if the current selection is a symbolic link ("FILE" and "DIR" ** definitions are not used in that case). The default menu ** definitions have been updated to reflect this change, and to avoid ** the showing of menu items whose action would always fail - KW ** Cast all code into the Lynx programming style. - FM */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef VMS #ifndef _WINDOWS #ifdef HAVE_SYS_WAIT_H #include #endif #include #endif /*_WINDOWS */ #endif /* VMS */ #ifndef WEXITSTATUS # if HAVE_TYPE_UNIONWAIT # define WEXITSTATUS(status) (status.w_retcode) # else # define WEXITSTATUS(status) (((status) & 0xff00) >> 8) # endif #endif #ifndef WTERMSIG # if HAVE_TYPE_UNIONWAIT # define WTERMSIG(status) (status.w_termsig) # else # define WTERMSIG(status) ((status) & 0x7f) # endif #endif #include PRIVATE int LYExecv PARAMS(( char * path, char ** argv, char * msg)); #ifdef DIRED_SUPPORT PUBLIC char LYPermitFileURL[LY_MAXPATH] = "\0"; PUBLIC char LYDiredFileURL[LY_MAXPATH] = "\0"; PRIVATE char *filename PARAMS(( char * prompt, char * buf, size_t bufsize)); #ifdef OK_PERMIT PRIVATE BOOLEAN permit_location PARAMS(( char * destpath, char * srcpath, char ** newpath)); #endif /* OK_PERMIT */ PRIVATE char *render_item PARAMS(( CONST char * s, char * path, char * dir, char * buf, int bufsize, BOOLEAN url_syntax)); PRIVATE struct dired_menu *menu_head = NULL; struct dired_menu { int cond; #define DE_TAG 1 #define DE_DIR 2 #define DE_FILE 3 #define DE_SYMLINK 4 char *sfx; char *link; char *rest; char *href; struct dired_menu *next; } defmenu[] = { /* * The following initializations determine the contents of the f)ull menu * selection when in dired mode. If any menu entries are defined in the * configuration file via DIRED_MENU lines, then these default entries * are discarded entirely. */ { 0, "", "New File", "(in current directory)", "LYNXDIRED://NEW_FILE%d", NULL }, { 0, "", "New Directory", "(in current directory)", "LYNXDIRED://NEW_FOLDER%d", NULL }, { DE_FILE, "", "Install", "(of current selection)", "LYNXDIRED://INSTALL_SRC%p", NULL }, { DE_DIR, "", "Install", "(of current selection)", "LYNXDIRED://INSTALL_SRC%p", NULL }, { DE_FILE, "", "Modify File Name", "(of current selection)", "LYNXDIRED://MODIFY_NAME%p", NULL }, { DE_DIR, "", "Modify Directory Name", "(of current selection)", "LYNXDIRED://MODIFY_NAME%p", NULL }, { DE_SYMLINK, "", "Modify Name", "(of selected symbolic link)", "LYNXDIRED://MODIFY_NAME%p", NULL }, #ifdef OK_PERMIT { DE_FILE, "", "Modify File Permissions", "(of current selection)", "LYNXDIRED://PERMIT_SRC%p", NULL }, { DE_DIR, "", "Modify Directory Permissions", "(of current selection)", "LYNXDIRED://PERMIT_SRC%p", NULL }, #endif /* OK_PERMIT */ { DE_FILE, "", "Change Location", "(of selected file)" , "LYNXDIRED://MODIFY_LOCATION%p", NULL }, { DE_DIR, "", "Change Location", "(of selected directory)", "LYNXDIRED://MODIFY_LOCATION%p", NULL }, { DE_SYMLINK, "", "Change Location", "(of selected symbolic link)", "LYNXDIRED://MODIFY_LOCATION%p", NULL }, { DE_FILE, "", "Remove File", "(current selection)", "LYNXDIRED://REMOVE_SINGLE%p", NULL }, { DE_DIR, "", "Remove Directory", "(current selection)", "LYNXDIRED://REMOVE_SINGLE%p", NULL }, { DE_SYMLINK, "", "Remove Symbolic Link", "(current selection)", "LYNXDIRED://REMOVE_SINGLE%p", NULL }, #if defined(OK_UUDECODE) && !defined(ARCHIVE_ONLY) { DE_FILE, "", "UUDecode", "(current selection)", "LYNXDIRED://UUDECODE%p", NULL }, #endif /* OK_UUDECODE && !ARCHIVE_ONLY */ #if defined(OK_TAR) && !defined(ARCHIVE_ONLY) { DE_FILE, ".tar.Z", "Expand", "(current selection)", "LYNXDIRED://UNTAR_Z%p", NULL }, #endif /* OK_TAR && !ARCHIVE_ONLY */ #if defined(OK_TAR) && defined(OK_GZIP) && !defined(ARCHIVE_ONLY) { DE_FILE, ".tar.gz", "Expand", "(current selection)", "LYNXDIRED://UNTAR_GZ%p", NULL }, { DE_FILE, ".tgz", "Expand", "(current selection)", "LYNXDIRED://UNTAR_GZ%p", NULL }, #endif /* OK_TAR && OK_GZIP && !ARCHIVE_ONLY */ #ifndef ARCHIVE_ONLY { DE_FILE, ".Z", "Uncompress", "(current selection)", "LYNXDIRED://DECOMPRESS%p", NULL }, #endif /* ARCHIVE_ONLY */ #if defined(OK_GZIP) && !defined(ARCHIVE_ONLY) { DE_FILE, ".gz", "Uncompress", "(current selection)", "LYNXDIRED://UNGZIP%p", NULL }, #endif /* OK_GZIP && !ARCHIVE_ONLY */ #if defined(OK_ZIP) && !defined(ARCHIVE_ONLY) { DE_FILE, ".zip", "Uncompress", "(current selection)", "LYNXDIRED://UNZIP%p", NULL }, #endif /* OK_ZIP && !ARCHIVE_ONLY */ #if defined(OK_TAR) && !defined(ARCHIVE_ONLY) { DE_FILE, ".tar", "UnTar", "(current selection)", "LYNXDIRED://UNTAR%p", NULL }, #endif /* OK_TAR && !ARCHIVE_ONLY */ #ifdef OK_TAR { DE_DIR, "", "Tar", "(current selection)", "LYNXDIRED://TAR%p", NULL }, #endif /* OK_TAR */ #if defined(OK_TAR) && defined(OK_GZIP) { DE_DIR, "", "Tar and compress", "(using GNU gzip)", "LYNXDIRED://TAR_GZ%p", NULL }, #endif /* OK_TAR && OK_GZIP */ #ifdef OK_ZIP { DE_DIR, "", "Package and compress", "(using zip)", "LYNXDIRED://ZIP%p", NULL }, #endif /* OK_ZIP */ { DE_FILE, "", "Compress", "(using Unix compress)", "LYNXDIRED://COMPRESS%p", NULL }, #ifdef OK_GZIP { DE_FILE, "", "Compress", "(using gzip)", "LYNXDIRED://GZIP%p", NULL }, #endif /* OK_GZIP */ #ifdef OK_ZIP { DE_FILE, "", "Compress", "(using zip)", "LYNXDIRED://ZIP%p", NULL }, #endif /* OK_ZIP */ { DE_TAG, "", "Move all tagged items to another location.", "", "LYNXDIRED://MOVE_TAGGED%d", NULL }, { DE_TAG, "", "Remove all tagged files and directories.", "", "LYNXDIRED://REMOVE_TAGGED", NULL }, { DE_TAG, "", "Untag all tagged files and directories.", "", "LYNXDIRED://CLEAR_TAGGED", NULL }, { 0, NULL, NULL, NULL, NULL, NULL } }; PRIVATE BOOLEAN ok_stat ARGS2(char *, name, struct stat*, sb) { char tmpbuf[LY_MAXPATH+80]; CTRACE(tfp, "testing ok_stat(%s)\n", name); if (stat(name, sb) < 0) { sprintf(tmpbuf, "Unable to get status of '%s'.", name); HTAlert(tmpbuf); return FALSE; } return TRUE; } #ifdef HAVE_LSTAT PRIVATE BOOLEAN ok_lstat ARGS2(char *, name, struct stat*, sb) { char tmpbuf[LY_MAXPATH+80]; CTRACE(tfp, "testing ok_lstat(%s)\n", name); if (lstat(name, sb) < 0) { sprintf(tmpbuf, "Unable to get status of '%s'.", name); HTAlert(tmpbuf); return FALSE; } return TRUE; } #else #define ok_lstat(name,sb) ok_stat(name,sb) #endif PRIVATE BOOLEAN ok_file_or_dir ARGS1(struct stat*, sb) { if (!S_ISDIR(sb->st_mode) && !S_ISREG(sb->st_mode)) { HTAlert("The selected item is not a file or a directory! Request ignored."); return FALSE; } return TRUE; } PRIVATE BOOLEAN ok_localname ARGS2(char*, dst, char*, src) { char *s = HTfullURL_toFile(strip_trailing_slash(src)); struct stat dir_info; if (!ok_stat(s, &dir_info) || !ok_file_or_dir(&dir_info)) { free(s); return FALSE; } strcpy(dst, s); free(s); return TRUE; } /* * Remove all tagged files and directories. */ PRIVATE BOOLEAN remove_tagged NOARGS { int c, ans; char *cp, *tp; char tmpbuf[1024]; char *testpath = NULL; struct stat dir_info; int count; HTList *tag; char *args[5]; if (HTList_isEmpty(tagged)) /* should never happen */ return 0; _statusline("Remove all tagged files and directories (y or n): "); c = LYgetch(); ans = TOUPPER(c); count = 0; tag = tagged; while (ans == 'Y' && (cp = (char *)HTList_nextObject(tag)) != NULL) { if (is_url(cp) == FILE_URL_TYPE) { /* unnecessary check */ tp = HTfullURL_toFile(cp); StrAllocCopy(testpath, tp); free(tp); LYTrimPathSep(testpath); /* * Check the current status of the path to be deleted. */ if (!ok_stat(testpath, &dir_info)) { return count; } else { args[0] = "rm"; args[1] = "-rf"; args[2] = testpath; args[3] = (char *) 0; sprintf(tmpbuf, "remove %s", testpath); if (LYExecv(RM_PATH, args, tmpbuf) <= 0) { FREE(testpath); return ((count == 0) ? -1 : count); } ++count; } } } FREE(testpath); clear_tags(); return count; } /* * Move all tagged files and directories to a new location. * Input is current directory. * The tests in this function can, at best, prevent some user mistakes - * anybody who relies on them for security is seriously misguided. * If a user has enough permissions to move a file somewhere, the same * uid with Lynx & dired can do the same thing. */ PRIVATE BOOLEAN modify_tagged ARGS1( char *, testpath) { char *cp; dev_t dev; ino_t inode; uid_t owner; char tmpbuf[1024]; char *savepath = NULL; char *srcpath = NULL; struct stat dir_info; char *args[5]; int count = 0; HTList *tag; if (HTList_isEmpty(tagged)) /* should never happen */ return 0; _statusline("Enter new location for tagged items: "); tmpbuf[0] = '\0'; LYgetstr(tmpbuf, VISIBLE, sizeof(tmpbuf), NORECALL); if (strlen(tmpbuf)) { /* * Determine the ownership of the current location. */ /* * This test used to always fail from the dired menu... * changed to something that hopefully makes more sense - KW */ if (testpath && *testpath && 0!=strcmp(testpath,"/")) { /* * testpath passed in and is not empty and not a single "/" * (which would probably be bogus) - use it. */ cp = testpath; } else { /* * Prepare to get directory path from one of the tagged files. */ cp = HTList_lastObject(tagged); testpath = NULL; /* Won't be needed any more in this function, set to NULL as a flag. */ if (!cp) /* Last resort, should never happen. */ cp = "/"; } if (testpath == NULL) { /* * Get the directory containing the file or subdir. */ cp = HTfullURL_toFile(strip_trailing_slash(cp)); savepath = HTParse(".", cp, PARSE_PATH+PARSE_PUNCTUATION); } else { cp = HTfullURL_toFile(cp); StrAllocCopy(savepath, cp); } free(cp); if (!ok_stat(savepath, &dir_info)) { FREE(savepath); return 0; } /* * Save the owner of the current location for later use. * Also save the device and inode for location checking/ */ dev = dir_info.st_dev; inode = dir_info.st_ino; owner = dir_info.st_uid; /* * Replace ~/ references to the home directory. */ if (!strncmp(tmpbuf, "~/", 2)) { char *cp1 = NULL; StrAllocCopy(cp1, Home_Dir()); StrAllocCat(cp1, (tmpbuf + 1)); if (strlen(cp1) > (sizeof(tmpbuf) - 1)) { sprintf(tmpbuf, "%s", "Path too long"); HTAlert(tmpbuf); FREE(savepath); FREE(cp1); return 0; } strcpy(tmpbuf, cp1); FREE(cp1); } /* * If path is relative, prefix it with current location. */ if (!LYIsPathSep(tmpbuf[0])) { LYAddPathSep(&savepath); StrAllocCat(savepath,tmpbuf); } else { StrAllocCopy(savepath,tmpbuf); } /* * stat() the target location to determine type and ownership. */ if (!ok_stat(savepath, &dir_info)) { FREE(savepath); return 0; } /* * Make sure the source and target locations are not the same place. */ if (dev == dir_info.st_dev && inode == dir_info.st_ino) { HTAlert("Source and destination are the same location - request ignored!"); FREE(savepath); return 0; } /* * Make sure the target location is a directory which is owned * by the same uid as the owner of the current location. */ if (S_ISDIR(dir_info.st_mode)) { if (dir_info.st_uid == owner) { count = 0; tag = tagged; /* * Move all tagged items to the target location. */ while ((cp = (char *)HTList_nextObject(tag)) != NULL) { cp = HTfullURL_toFile(cp); StrAllocCopy(srcpath, cp); free(cp); sprintf(tmpbuf, "move %s to %s", srcpath, savepath); args[0] = "mv"; args[1] = srcpath; args[2] = savepath; args[3] = (char *) 0; if (LYExecv(MV_PATH, args, tmpbuf) <= 0) { if (count == 0) count = -1; break; } ++count; } FREE(srcpath); FREE(savepath); clear_tags(); return count; } else { HTAlert("Destination has different owner! Request denied."); FREE(srcpath); FREE(savepath); return 0; } } else { HTAlert("Destination is not a valid directory! Request denied."); FREE(savepath); return 0; } } return 0; } /* * Modify the name of the specified item. */ PRIVATE BOOLEAN modify_name ARGS1( char *, testpath) { char *cp; char tmpbuf[512]; char newpath[512]; char savepath[512]; struct stat dir_info; char *args[5]; /* * Determine the status of the selected item. */ testpath = strip_trailing_slash(testpath); if (ok_stat(testpath, &dir_info)) { /* * Change the name of the file or directory. */ if (S_ISDIR(dir_info.st_mode)) { cp = "Enter new name for directory: "; } else if (S_ISREG(dir_info.st_mode)) { cp = "Enter new name for file: "; } else { HTAlert("The selected item is not a file or a directory! Request ignored."); return 0; } if (filename(cp, tmpbuf, sizeof(tmpbuf)) == NULL) return 0; /* * Do not allow the user to also change the location at this time. */ if (strchr(tmpbuf, '/') != NULL) { HTAlert("Illegal character \"/\" found! Request ignored."); } else if (strlen(tmpbuf) && (cp = strrchr(testpath, '/')) != NULL) { strcpy(savepath,testpath); *(++cp) = '\0'; strcpy(newpath,testpath); strcat(newpath,tmpbuf); /* * Make sure the destination does not already exist. */ if (stat(newpath, &dir_info) == -1) { if (errno != ENOENT) { sprintf(tmpbuf, "Unable to determine status of '%s'.", newpath); HTAlert(tmpbuf); } else { sprintf(tmpbuf, "move %s to %s", savepath, newpath); args[0] = "mv"; args[1] = savepath; args[2] = newpath; args[3] = (char *) 0; if (LYExecv(MV_PATH, args, tmpbuf) <= 0) return (-1); return 1; } } else if (S_ISDIR(dir_info.st_mode)) { HTAlert("There is already a directory with that name! Request ignored."); } else if (S_ISREG(dir_info.st_mode)) { HTAlert("There is already a file with that name! Request ignored."); } else { HTAlert("The specified name is already in use! Request ignored."); } } } return 0; } /* * Change the location of a file or directory. */ PRIVATE BOOLEAN modify_location ARGS1( char *, testpath) { int mode; char *cp; dev_t dev; ino_t inode; uid_t owner; char tmpbuf[1024]; char newpath[512]; char savepath[512]; struct stat dir_info; char *args[5]; /* * Determine the status of the selected item. */ testpath = strip_trailing_slash(testpath); if (!ok_stat(testpath, &dir_info)) { return 0; } /* * Change the location of the file or directory. */ if (S_ISDIR(dir_info.st_mode)) { cp = "Enter new location for directory: "; } else if (S_ISREG(dir_info.st_mode)) { cp = "Enter new location for file: "; } else { HTAlert("The specified item is not a file or a directory - request ignored."); return 0; } if (filename(cp, tmpbuf, sizeof(tmpbuf)) == NULL) return 0; if (strlen(tmpbuf)) { strcpy(savepath, testpath); strcpy(newpath, testpath); /* * Allow ~/ references to the home directory. */ if (!strncmp(tmpbuf, "~/", 2) || !strcmp(tmpbuf,"~")) { strcpy(newpath, Home_Dir()); strcat(newpath, (tmpbuf + 1)); strcpy(tmpbuf, newpath); } if (!LYIsPathSep(tmpbuf[0])) { if ((cp = strrchr(newpath,'/')) != NULL) { *++cp = '\0'; strcat(newpath,tmpbuf); } else { HTAlert("Unexpected failure - unable to find trailing \"/\""); return 0; } } else { strcpy(newpath,tmpbuf); } /* * Make sure the source and target have the same owner (uid). */ dev = dir_info.st_dev; mode = dir_info.st_mode; inode = dir_info.st_ino; owner = dir_info.st_uid; if (!ok_stat(newpath, &dir_info)) { return 0; } if (!S_ISDIR(dir_info.st_mode)) { HTAlert("Destination is not a valid directory! Request denied."); return 0; } /* * Make sure the source and target are not the same location. */ if (dev == dir_info.st_dev && inode == dir_info.st_ino) { HTAlert("Source and destination are the same location! Request ignored!"); return 0; } if (dir_info.st_uid == owner) { sprintf(tmpbuf,"move %s to %s",savepath,newpath); args[0] = "mv"; args[1] = savepath; args[2] = newpath; args[3] = (char *) 0; if (LYExecv(MV_PATH, args, tmpbuf) <= 0) return (-1); return 1; } else { HTAlert("Destination has different owner! Request denied."); return 0; } } return 0; } /* * Modify name or location of a file or directory on localhost. */ PUBLIC BOOLEAN local_modify ARGS2( document *, doc, char **, newpath) { int c, ans; char *cp; char testpath[512]; /* a bit ridiculous */ int count; if (!HTList_isEmpty(tagged)) { cp = HTpartURL_toFile(doc->address); strcpy(testpath, cp); free(cp); count = modify_tagged(testpath); if (doc->link > (nlinks-count - 1)) doc->link = (nlinks-count - 1); doc->link = (doc->link < 0) ? 0 : doc->link; return count; } else if (doc->link < 0 || doc->link > nlinks) { /* * Added protection. */ return 0; } /* * Do not allow simultaneous change of name and location as in Unix. * This reduces functionality but reduces difficulty for the novice. */ #ifdef OK_PERMIT _statusline("Modify name, location, or permission (n, l, or p): "); #else _statusline("Modify name, or location (n or l): "); #endif /* OK_PERMIT */ c = LYgetch(); ans = TOUPPER(c); if (strchr("NLP", ans) != NULL) { cp = HTfullURL_toFile(links[doc->link].lname); strcpy(testpath, cp); free(cp); if (ans == 'N') { return(modify_name(testpath)); } else if (ans == 'L') { if (modify_location(testpath)) { if (doc->link == (nlinks-1)) --doc->link; return 1; } #ifdef OK_PERMIT } else if (ans == 'P') { return(permit_location(NULL, testpath, newpath)); #endif /* OK_PERMIT */ } else { /* * Code for changing ownership needed here. */ HTAlert("This feature not yet implemented!"); } } return 0; } /* * Create a new empty file in the current directory. */ PRIVATE BOOLEAN create_file ARGS1( char *, current_location) { char tmpbuf[512]; char testpath[512]; struct stat dir_info; char *args[5]; char *bad_chars = ".~/"; if (filename("Enter name of file to create: ", tmpbuf, sizeof(tmpbuf)) == NULL) { return 0; } if (!no_dotfiles && show_dotfiles) { bad_chars = "~/"; } if (strstr(tmpbuf, "//") != NULL) { HTAlert("Illegal redirection \"//\" found! Request ignored."); } else if (strlen(tmpbuf) && strchr(bad_chars, tmpbuf[0]) == NULL) { strcpy(testpath,current_location); LYAddPathSep0(testpath); /* * Append the target filename to the current location. */ strcat(testpath, tmpbuf); /* * Make sure the target does not already exist */ if (stat(testpath, &dir_info) == -1) { if (errno != ENOENT) { sprintf(tmpbuf, "Unable to determine status of '%s'.", testpath); HTAlert(tmpbuf); return 0; } sprintf(tmpbuf,"create %s",testpath); args[0] = "touch"; args[1] = testpath; args[2] = (char *) 0; if (LYExecv(TOUCH_PATH, args, tmpbuf) <= 0) return (-1); return 1; } else if (S_ISDIR(dir_info.st_mode)) { HTAlert("There is already a directory with that name! Request ignored."); } else if (S_ISREG(dir_info.st_mode)) { HTAlert("There is already a file with that name! Request ignored."); } else { HTAlert("The specified name is already in use! Request ignored."); } } return 0; } /* * Create a new directory in the current directory. */ PRIVATE BOOLEAN create_directory ARGS1( char *, current_location) { char tmpbuf[512]; char testpath[512]; struct stat dir_info; char *args[5]; char *bad_chars = ".~/"; if (filename("Enter name for new directory: ", tmpbuf, sizeof(tmpbuf)) == NULL) { return 0; } if (!no_dotfiles && show_dotfiles) { bad_chars = "~/"; } if (strstr(tmpbuf, "//") != NULL) { HTAlert("Illegal redirection \"//\" found! Request ignored."); } else if (strlen(tmpbuf) && strchr(bad_chars, tmpbuf[0]) == NULL) { strcpy(testpath,current_location); LYAddPathSep0(testpath); strcat(testpath, tmpbuf); /* * Make sure the target does not already exist. */ if (stat(testpath, &dir_info) == -1) { if (errno != ENOENT) { sprintf(tmpbuf, "Unable to determine status of '%s'.", testpath); HTAlert(tmpbuf); return 0; } sprintf(tmpbuf,"make directory %s",testpath); args[0] = "mkdir"; args[1] = testpath; args[2] = (char *) 0; if (LYExecv(MKDIR_PATH, args, tmpbuf) <= 0) return (-1); return 1; } else if (S_ISDIR(dir_info.st_mode)) { HTAlert("There is already a directory with that name! Request ignored."); } else if (S_ISREG(dir_info.st_mode)) { HTAlert("There is already a file with that name! Request ignored."); } else { HTAlert("The specified name is already in use! Request ignored."); } } return 0; } /* * Create a file or a directory at the current location. */ PUBLIC BOOLEAN local_create ARGS1( document *, doc) { int c, ans; char *cp; char testpath[512]; _statusline("Create file or directory (f or d): "); c = LYgetch(); ans = TOUPPER(c); cp = HTfullURL_toFile(doc->address); strcpy(testpath,cp); free(cp); if (ans == 'F') { return(create_file(testpath)); } else if (ans == 'D') { return(create_directory(testpath)); } else { return 0; } } /* * Remove a single file or directory. */ PRIVATE BOOLEAN remove_single ARGS1( char *, testpath) { int c; char *cp; char tmpbuf[1024]; struct stat dir_info; char *args[5]; if (!ok_lstat(testpath, &dir_info)) { return 0; } /* * Locate the filename portion of the path. */ if ((cp = strrchr(testpath, '/')) != NULL) { ++cp; } else { cp = testpath; } if (S_ISDIR(dir_info.st_mode)) { if (strlen(cp) < 37) { sprintf(tmpbuf, "Remove '%s' and all of its contents (y or n): ", cp); } else { sprintf(tmpbuf, "Remove directory and all of its contents (y or n): "); } } else if (S_ISREG(dir_info.st_mode)) { if (strlen(cp) < 60) { sprintf(tmpbuf, "Remove file '%s' (y or n): ", cp); } else { sprintf(tmpbuf, "Remove file (y or n): "); } #ifdef S_IFLNK } else if (S_ISLNK(dir_info.st_mode)) { if (strlen(cp) < 50) { sprintf(tmpbuf, "Remove symbolic link '%s' (y or n): ", cp); } else { sprintf(tmpbuf, "Remove symbolic link (y or n): "); } #endif } else { sprintf(tmpbuf, "Unable to determine status of '%s'.", testpath); HTAlert(tmpbuf); return 0; } _statusline(tmpbuf); c = LYgetch(); if (TOUPPER(c) == 'Y') { sprintf(tmpbuf,"remove %s",testpath); args[0] = "rm"; args[1] = "-rf"; args[2] = testpath; args[3] = (char *) 0; if (LYExecv(RM_PATH, args, tmpbuf) <= 0) return (-1); return 1; } return 0; } /* * Remove a file or a directory. */ PUBLIC BOOLEAN local_remove ARGS1( document *, doc) { char *cp, *tp; char testpath[512]; int count, i; if (!HTList_isEmpty(tagged)) { count = remove_tagged(); if (doc->link > (nlinks-count - 1)) doc->link = (nlinks-count - 1); doc->link = (doc->link < 0) ? 0 : doc->link; return count; } else if (doc->link < 0 || doc->link > nlinks) { return 0; } cp = links[doc->link].lname; if (is_url(cp) == FILE_URL_TYPE) { tp = HTfullURL_toFile(cp); strcpy(testpath, tp); free(tp); if ((i = strlen(testpath)) && testpath[i - 1] == '/') testpath[(i - 1)] = '\0'; if (remove_single(testpath)) { if (doc->link == (nlinks - 1)) --doc->link; return 1; } } return 0; } #ifdef OK_PERMIT /* * Table of permission strings and chmod values. * Makes the code a bit cleaner. */ static struct { CONST char *string_mode; /* Key for value below */ long permit_bits; /* Value for chmod/whatever */ } permissions[] = { {"IRUSR", S_IRUSR}, {"IWUSR", S_IWUSR}, {"IXUSR", S_IXUSR}, {"IRGRP", S_IRGRP}, {"IWGRP", S_IWGRP}, {"IXGRP", S_IXGRP}, {"IROTH", S_IROTH}, {"IWOTH", S_IWOTH}, {"IXOTH", S_IXOTH}, {NULL, 0} /* Don't include setuid and friends; use shell access for that. */ }; PRIVATE char LYValidPermitFile[LY_MAXPATH] = "\0"; /* * Handle DIRED permissions. */ PRIVATE BOOLEAN permit_location ARGS3( char *, destpath, char *, srcpath, char **, newpath) { #ifndef UNIX HTAlert("Sorry, don't know how to permit non-UNIX files yet."); return(0); #else static char tempfile[LY_MAXPATH] = "\0"; char *cp; char tmpbuf[LINESIZE]; char tmpdst[LY_MAXPATH]; struct stat dir_info; if (srcpath) { /* * Create form. */ FILE *fp0; char local_src[LY_MAXPATH]; char * user_filename; struct group * grp; char * group_name; cp = HTfullURL_toFile(strip_trailing_slash(srcpath)); strcpy(local_src, cp); free(cp); /* * A couple of sanity tests. */ if (!ok_lstat(local_src, &dir_info) || !ok_file_or_dir(&dir_info)) return 0; user_filename = LYPathLeaf(local_src); LYRemoveTemp(tempfile); if ((fp0 = LYOpenTemp(tempfile, HTML_SUFFIX, "w")) == NULL) { HTAlert("Unable to open permit options file"); return(0); } /* * Make the tempfile a URL. */ LYLocalFileToURL(newpath, tempfile); strcpy(LYPermitFileURL, *newpath); grp = getgrgid(dir_info.st_gid); if (grp == NULL) { group_name = ""; } else { group_name = grp->gr_name; } LYstrncpy(LYValidPermitFile, local_src, (sizeof(LYValidPermitFile) - 1)); fprintf(fp0, "\n%s\n\n\n", PERMIT_OPTIONS_TITLE); fprintf(fp0,"

Permissions for %s

\n", user_filename); { /* * Prevent filenames which include '#' or '?' from messing it up. */ char * srcpath_url = HTEscape(srcpath, URL_PATH); fprintf(fp0, "
\n", srcpath_url); FREE(srcpath_url); } fprintf(fp0, "
  1. Specify permissions below:

    \n"); fprintf(fp0, "Owner:
    \n"); fprintf(fp0, " Read
    \n", (dir_info.st_mode & S_IRUSR) ? "checked" : ""); fprintf(fp0, " Write
    \n", (dir_info.st_mode & S_IWUSR) ? "checked" : ""); /* * If restricted, only change eXecute permissions on directories. */ if (!no_change_exec_perms || S_ISDIR(dir_info.st_mode)) fprintf(fp0, " %s
    \n", (dir_info.st_mode & S_IXUSR) ? "checked" : "", S_ISDIR(dir_info.st_mode) ? "Search" : "Execute"); fprintf(fp0, "Group %s:
    \n", group_name); fprintf(fp0, " Read
    \n", (dir_info.st_mode & S_IRGRP) ? "checked" : ""); fprintf(fp0, " Write
    \n", (dir_info.st_mode & S_IWGRP) ? "checked" : ""); /* * If restricted, only change eXecute permissions on directories. */ if (!no_change_exec_perms || S_ISDIR(dir_info.st_mode)) fprintf(fp0, " %s
    \n", (dir_info.st_mode & S_IXGRP) ? "checked" : "", S_ISDIR(dir_info.st_mode) ? "Search" : "Execute"); fprintf(fp0, "Others:
    \n"); fprintf(fp0, " Read
    \n", (dir_info.st_mode & S_IROTH) ? "checked" : ""); fprintf(fp0, " Write
    \n", (dir_info.st_mode & S_IWOTH) ? "checked" : ""); /* * If restricted, only change eXecute permissions on directories. */ if (!no_change_exec_perms || S_ISDIR(dir_info.st_mode)) fprintf(fp0, " %s
    \n", (dir_info.st_mode & S_IXOTH) ? "checked" : "", S_ISDIR(dir_info.st_mode) ? "Search" : "Execute"); fprintf(fp0, "
    \n
  2. \ form to permit %s %s.\n
\n
\n", S_ISDIR(dir_info.st_mode) ? "directory" : "file", user_filename); fprintf(fp0, ""); LYCloseTempFP(fp0); LYforce_no_cache = TRUE; return(PERMIT_FORM_RESULT); /* Special flag for LYMainLoop */ } else { /* The form being activated. */ mode_t new_mode = 0; char *args[5]; char amode[10]; /* * Make sure we have a valid set-permission * file comparison string loaded via a previous * call with srcpath != NULL. - KW */ if (LYValidPermitFile[0] == '\0') { if (LYCursesON) HTAlert(INVALID_PERMIT_URL); else fprintf(stderr, "%s\n", INVALID_PERMIT_URL); CTRACE(tfp, "permit_location: called for <%s>.\n", (destpath ? destpath : "NULL URL pointer")); return 0; } cp = destpath; while (*cp != '\0' && *cp != '?') { /* Find filename */ cp++; } if (*cp == '\0') { return(0); /* Nothing to permit. */ } *cp++ = '\0'; /* Null terminate file name and start working on the masks. */ if ((destpath = HTfullURL_toFile(destpath)) == 0) return(0); strcpy(tmpdst, destpath); /* operate only on filename */ free(destpath); destpath = tmpdst; /* * Make sure that the file string is the one from * the last displayed File Permissions menu. - KW */ if (strcmp(destpath, LYValidPermitFile)) { if (LYCursesON) HTAlert(INVALID_PERMIT_URL); else fprintf(stderr, "%s\n", INVALID_PERMIT_URL); CTRACE(tfp, "permit_location: called for file '%s'.\n", destpath); return 0; } /* * A couple of sanity tests. */ destpath = strip_trailing_slash(destpath); if (!ok_stat(destpath, &dir_info) || !ok_file_or_dir(&dir_info)) { return 0; } /* * Cycle over permission strings. */ while(*cp != '\0') { char *cr = cp; while(*cr != '\0' && *cr != '&') { /* GET data split by '&'. */ cr++; } if (*cr != '\0') { *cr++ = '\0'; } if (strncmp(cp, "mode=", 5) == 0) { /* Magic string. */ int i; for(i = 0; permissions[i].string_mode != NULL; i++) { if (strcmp(permissions[i].string_mode, cp+5) == 0) { /* * If restricted, only change eXecute * permissions on directories. */ if (!no_change_exec_perms || strchr(cp+5,'X') == NULL || S_ISDIR(dir_info.st_mode)) new_mode |= permissions[i].permit_bits; break; } } if (permissions[i].string_mode == NULL) { HTAlert("Invalid mode format."); return 0; } } else { HTAlert("Invalid syntax format."); return 0; } cp = cr; } #ifdef UNIX /* * Call chmod(). */ sprintf(tmpbuf, "chmod %.4o %s", (unsigned int)new_mode, destpath); sprintf(amode, "%.4o", (unsigned int)new_mode); args[0] = "chmod"; args[1] = amode; args[2] = destpath; args[3] = (char *) 0; if (LYExecv(CHMOD_PATH, args, tmpbuf) <= 0) { return (-1); } #endif /* UNIX */ LYforce_no_cache = TRUE; /* Force update of dired listing. */ return 1; } #endif /* !UNIX */ } #endif /* OK_PERMIT */ /* * Display or remove a tag from a given link. */ PUBLIC void tagflag ARGS2( int, flag, int, cur) { if (nlinks > 0) { move(links[cur].ly, 2); stop_reverse(); if (flag == ON) { addch('+'); } else { addch(' '); } #if defined(FANCY_CURSES) || defined(USE_SLANG) if (!LYShowCursor) move((LYlines - 1), (LYcols - 1)); /* get cursor out of the way */ else #endif /* FANCY CURSES || USE_SLANG */ /* * Never hide the cursor if there's no FANCY CURSES. */ move(links[cur].ly, links[cur].lx); refresh(); } } /* * Handle DIRED tags. */ PUBLIC void showtags ARGS1( HTList *, t) { int i; HTList *s; char *name; for (i = 0; i < nlinks; i++) { s = t; while ((name = HTList_nextObject(s)) != NULL) { if (!strcmp(links[i].lname, name)) { tagflag(ON, i); break; } } } } /* * Perform file management operations for LYNXDIRED URL's. * Attempt to be consistent. These are (pseudo) URLs - i.e. they should * be in URL syntax: some bytes will be URL-escaped with '%'. This is * necessary because these (pseudo) URLs will go through some of the same * kinds of interpretations and mutilations as real ones: HTParse, stripping * off #fragments etc. (Some access schemes currently have special rules * about not escaping parsing '#' "the URL way" built into HTParse, but that * doesn't look like a clean way.) */ PUBLIC int local_dired ARGS1( document *, doc) { char *line_url; /* will point to doc's address, which is a URL */ char *line = NULL; /* same as line_url, but HTUnEscaped, will be alloced */ char *cp, *tp, *bp; char tmpbuf[256]; char buffer[512]; line_url = doc->address; CTRACE(tfp, "local_dired: called for <%s>.\n", (line_url ? line_url : "NULL URL pointer")); HTUnEscapeSome(line_url, "/"); /* don't mess too much with *doc */ StrAllocCopy(line, line_url); HTUnEscape(line); /* _file_ (not URL) syntax, for those functions that need it. Don't forget to FREE it. */ tp = NULL; if (!strncmp(line, "LYNXDIRED://NEW_FILE", 20)) { if (create_file(&line[20]) > 0) LYforce_no_cache = TRUE; } else if (!strncmp(line, "LYNXDIRED://NEW_FOLDER", 22)) { if (create_directory(&line[22]) > 0) LYforce_no_cache = TRUE; } else if (!strncmp(line, "LYNXDIRED://INSTALL_SRC", 23)) { local_install(NULL, &line[23], &tp); StrAllocCopy(doc->address, tp); FREE(line); return 0; } else if (!strncmp(line, "LYNXDIRED://INSTALL_DEST", 24)) { local_install(&line[24], NULL, &tp); LYpop(doc); } else if (!strncmp(line, "LYNXDIRED://MODIFY_NAME", 23)) { if (modify_name(&line[23]) > 0) LYforce_no_cache = TRUE; } else if (!strncmp(line, "LYNXDIRED://MODIFY_LOCATION", 27)) { if (modify_location(&line[27]) > 0) LYforce_no_cache = TRUE; } else if (!strncmp(line, "LYNXDIRED://MOVE_TAGGED", 23)) { if (modify_tagged(&line_url[23]) > 0) LYforce_no_cache = TRUE; #ifdef OK_PERMIT } else if (!strncmp(line, "LYNXDIRED://PERMIT_SRC", 22)) { permit_location(NULL, &line[22], &tp); if (tp) /* * One of the checks may have failed. */ StrAllocCopy(doc->address, tp); FREE(line); return 0; } else if (!strncmp(line, "LYNXDIRED://PERMIT_LOCATION", 27)) { permit_location(&line_url[27], NULL, &tp); #endif /* OK_PERMIT */ } else if (!strncmp(line, "LYNXDIRED://REMOVE_SINGLE", 25)) { if (remove_single(&line[25]) > 0) LYforce_no_cache = TRUE; } else if (!strncmp(line, "LYNXDIRED://REMOVE_TAGGED", 25)) { if (remove_tagged()) LYforce_no_cache = TRUE; } else if (!strncmp(line, "LYNXDIRED://CLEAR_TAGGED", 24)) { clear_tags(); } else if (!strncmp(line, "LYNXDIRED://UPLOAD", 18)) { /* * They're written by LYUpload_options() HTUnEscaped; * don't want to change that for now... so pass through * without more unescaping. Directory names containing * '#' will probably fail. */ if (LYUpload(line_url)) LYforce_no_cache = TRUE; } else { LYTrimPathSep(line); if ((cp = strrchr(line, '/')) == NULL) { FREE(line); return 0; } /* * Construct the appropriate system command taking care to * escape all path references to avoid spoofing the shell. */ *buffer = '\0'; if (!strncmp(line, "LYNXDIRED://DECOMPRESS", 22)) { tp = quote_pathname(line + 22); sprintf(buffer,"%s %s", UNCOMPRESS_PATH, tp); FREE(tp); #if defined(OK_UUDECODE) && !defined(ARCHIVE_ONLY) } else if (!strncmp(line, "LYNXDIRED://UUDECODE", 20)) { tp = quote_pathname(line + 20); sprintf(buffer,"%s %s", UUDECODE_PATH, tp); HTAlert("Warning! UUDecoded file will exist in the directory you started Lynx."); FREE(tp); #endif /* OK_UUDECODE && !ARCHIVE_ONLY */ #ifdef OK_TAR # ifndef ARCHIVE_ONLY # ifdef OK_GZIP } else if (!strncmp(line, "LYNXDIRED://UNTAR_GZ", 20)) { tp = quote_pathname(line+20); *cp++ = '\0'; cp = quote_pathname(line + 20); sprintf(buffer, "%s -qdc %s | (cd %s; %s -xf -)", GZIP_PATH, tp, cp, TAR_PATH); FREE(cp); FREE(tp); # endif /* OK_GZIP */ } else if (!strncmp(line, "LYNXDIRED://UNTAR_Z", 19)) { tp = quote_pathname(line + 19); *cp++ = '\0'; cp = quote_pathname(line + 19); sprintf(buffer, "%s %s | (cd %s; %s -xf -)", ZCAT_PATH, tp, cp, TAR_PATH); FREE(cp); FREE(tp); } else if (!strncmp(line, "LYNXDIRED://UNTAR", 17)) { tp = quote_pathname(line + 17); *cp++ = '\0'; cp = quote_pathname(line + 17); sprintf(buffer, "cd %s; %s -xf %s", cp, TAR_PATH, tp); FREE(cp); FREE(tp); # endif /* !ARCHIVE_ONLY */ # ifdef OK_GZIP } else if (!strncmp(line, "LYNXDIRED://TAR_GZ", 18)) { *cp++ = '\0'; cp = quote_pathname(cp); tp = quote_pathname(line + 18); sprintf(buffer, "(cd %s; %s -cf - %s) | %s -qc >%s/%s.tar.gz", tp, TAR_PATH, cp, GZIP_PATH, tp, cp); FREE(cp); FREE(tp); # endif /* OK_GZIP */ } else if (!strncmp(line, "LYNXDIRED://TAR_Z", 17)) { *cp++ = '\0'; cp = quote_pathname(cp); tp = quote_pathname(line + 17); sprintf(buffer, "(cd %s; %s -cf - %s) | %s >%s/%s.tar.Z", tp, TAR_PATH, cp, COMPRESS_PATH, tp, cp); FREE(cp); FREE(tp); } else if (!strncmp(line, "LYNXDIRED://TAR", 15)) { *cp++ = '\0'; cp = quote_pathname(cp); tp = quote_pathname(line + 15); sprintf(buffer, "(cd %s; %s -cf %s.tar %s)", tp, TAR_PATH, cp, cp); FREE(cp); FREE(tp); #endif /* OK_TAR */ #ifdef OK_GZIP } else if (!strncmp(line, "LYNXDIRED://GZIP", 16)) { tp = quote_pathname(line + 16); sprintf(buffer, "%s -q %s", GZIP_PATH, tp); FREE(tp); #ifndef ARCHIVE_ONLY } else if (!strncmp(line, "LYNXDIRED://UNGZIP", 18)) { tp = quote_pathname(line + 18); sprintf(buffer, "%s -d %s", GZIP_PATH, tp); FREE(tp); #endif /* !ARCHIVE_ONLY */ #endif /* OK_GZIP */ #ifdef OK_ZIP } else if (!strncmp(line, "LYNXDIRED://ZIP", 15)) { tp = quote_pathname(line + 15); *cp++ = '\0'; bp = quote_pathname(cp); cp = quote_pathname(line + 15); sprintf(buffer, "cd %s; %s -rq %s.zip %s", cp, ZIP_PATH, tp, bp); FREE(cp); FREE(bp); FREE(tp); #ifndef ARCHIVE_ONLY } else if (!strncmp(line, "LYNXDIRED://UNZIP", 17)) { tp = quote_pathname(line + 17); *cp = '\0'; cp = quote_pathname(line + 17); sprintf(buffer, "cd %s; %s -q %s", cp, UNZIP_PATH, tp); FREE(cp); FREE(tp); # endif /* !ARCHIVE_ONLY */ #endif /* OK_ZIP */ } else if (!strncmp(line, "LYNXDIRED://COMPRESS", 20)) { tp = quote_pathname(line + 20); sprintf(buffer, "%s %s", COMPRESS_PATH, tp); FREE(tp); } if (strlen(buffer)) { if (strlen(buffer) < 60) { sprintf(tmpbuf, "Executing %s ", buffer); } else { sprintf(tmpbuf, "Executing system command. This might take a while."); } _statusline(tmpbuf); stop_curses(); printf("%s\n", tmpbuf); LYSystem(buffer); #ifdef VMS extern BOOLEAN HadVMSInterrupt HadVMSInterrupt = FALSE; #endif /* VMS */ start_curses(); LYforce_no_cache = TRUE; } } FREE(line); LYpop(doc); return 0; } /* * Provide a menu of file management options. */ PUBLIC int dired_options ARGS2( document *, doc, char **, newfile) { static char tempfile[LY_MAXPATH]; char path[512], dir[512]; /* much too large */ lynx_html_item_type *nxt; struct stat dir_info; FILE *fp0; char *cp = NULL; char *dir_url; char *path_url; BOOLEAN nothing_tagged; int count; struct dired_menu *mp; char buf[2048]; LYRemoveTemp(tempfile); if ((fp0 = LYOpenTemp(tempfile, HTML_SUFFIX, "w")) == NULL) { HTAlert("Unable to open file management menu file."); return(0); } /* * Make the tempfile a URL. */ LYLocalFileToURL(newfile, tempfile); strcpy(LYDiredFileURL, *newfile); cp = HTpartURL_toFile(doc->address); strcpy(dir, cp); LYTrimPathSep(dir); if (doc->link > -1 && doc->link < (nlinks+1)) { cp = HTfullURL_toFile(links[doc->link].lname); strcpy(path, cp); LYTrimPathSep(path); free(cp); if (!ok_lstat(path, &dir_info)) { LYCloseTempFP(fp0); return 0; } } else { path[0] = '\0'; } nothing_tagged = (HTList_isEmpty(tagged)); BeginInternalPage(fp0, DIRED_MENU_TITLE, DIRED_MENU_HELP); fprintf(fp0, "Current directory: %s
\n", dir); if (nothing_tagged) { if (strlen(path)) { fprintf(fp0, "Current selection: %s

\n", path); } else { fprintf(fp0, "Current selection: Nothing currently selected.

\n"); } } else { /* * Write out number of tagged items, and names of first * few of them relative to current (in the DIRED sense) * directory. */ int n = HTList_count(tagged); char *cp1 = NULL; char *cd = NULL; int i, m; #define NUM_TAGS_TO_WRITE 10 fprintf(fp0, "Current selection: %d tagged item%s", n, ((n == 1) ? ":" : "s:")); StrAllocCopy(cd, doc->address); HTUnEscapeSome(cd, "/"); LYAddHtmlSep(&cd); m = (n < NUM_TAGS_TO_WRITE) ? n : NUM_TAGS_TO_WRITE; for (i = 1; i <= m; i++) { cp1 = HTRelative(HTList_objectAt(tagged, i-1), (*cd ? cd : "file://localhost")); HTUnEscape(cp1); LYEntify(&cp1, TRUE); /* _should_ do this everywhere... */ fprintf(fp0, "%s
\n   %s", (i == 1 ? "" : " ,"), cp1); FREE(cp1); } if (n > m) { fprintf(fp0," , ..."); } fprintf(fp0, "

\n"); FREE(cd); } /* * If menu_head is NULL then use defaults and link them together now. */ if (menu_head == NULL) { for (mp = defmenu; mp->href != NULL; mp++) mp->next = (mp + 1); (--mp)->next = NULL; menu_head = defmenu; } for (mp = menu_head; mp != NULL; mp = mp->next) { if (mp->cond != DE_TAG && !nothing_tagged) continue; if (mp->cond == DE_TAG && nothing_tagged) continue; if (mp->cond == DE_DIR && (!*path || !S_ISDIR(dir_info.st_mode))) continue; if (mp->cond == DE_FILE && (!*path || !S_ISREG(dir_info.st_mode))) continue; #ifdef S_IFLNK if (mp->cond == DE_SYMLINK && (!*path || !S_ISLNK(dir_info.st_mode))) continue; #endif if (*mp->sfx && (strlen(path) < strlen(mp->sfx) || strcmp(mp->sfx, &path[(strlen(path) - strlen(mp->sfx))]) != 0)) continue; dir_url = HTEscape(dir, URL_PATH); path_url = HTEscape(path, URL_PATH); fprintf(fp0, "href, path_url, dir_url, buf,sizeof(buf), YES)); fprintf(fp0, "\">%s ", render_item(mp->link, path, dir, buf,sizeof(buf), NO)); fprintf(fp0, "%s
\n", render_item(mp->rest, path, dir, buf,sizeof(buf), NO)); FREE(dir_url); FREE(path_url); } if (uploaders != NULL) { fprintf(fp0, "

Upload to current directory:

\n"); for (count = 0, nxt = uploaders; nxt != NULL; nxt = nxt->next, count++) { fprintf(fp0, " %s
\n", count, dir, nxt->name); } } EndInternalPage(fp0); LYCloseTempFP(fp0); LYforce_no_cache = TRUE; return(0); } /* * Check DIRED filename. */ PRIVATE char *filename ARGS3( char *, prompt, char *, buf, size_t, bufsize) { char *cp; _statusline(prompt); *buf = '\0'; LYgetstr(buf, VISIBLE, bufsize, NORECALL); if (strstr(buf, "../") != NULL) { HTAlert("Illegal filename; request ignored."); return NULL; } if (no_dotfiles || !show_dotfiles) { cp = strrchr(buf, '/'); /* find last slash */ if (cp) cp += 1; else cp = buf; if (*cp == '.') { HTAlert("Illegal filename; request ignored."); return NULL; } } return buf; } /* * Install the specified file or directory. */ PUBLIC BOOLEAN local_install ARGS3( char *, destpath, char *, srcpath, char **, newpath) { char tmpbuf[512]; static char savepath[512]; /* This will be the link that is to be installed. */ struct stat dir_info; char *args[6]; HTList *tag; int count = 0; int n = 0, src; /* indices into 'args[]' */ /* * Determine the status of the selected item. */ if (srcpath) { if (!ok_localname(savepath, srcpath)) return 0; LYforce_no_cache = TRUE; LYLocalFileToURL(newpath, Home_Dir()); StrAllocCat(*newpath, "/.installdirs.html"); return 0; } destpath = strip_trailing_slash(destpath); if (!ok_stat(destpath, &dir_info)) { return 0; } else if (!S_ISDIR(dir_info.st_mode)) { HTAlert("The selected item is not a directory! Request ignored."); return 0; } else if (0 /*directory not writable*/) { HTAlert("Install in the selected directory not permitted."); return 0; } statusline("Just a moment, ..."); args[n++] = "install"; #ifdef INSTALL_ARGS args[n++] = INSTALL_ARGS; #endif /* INSTALL_ARGS */ src = n++; args[n++] = destpath; args[n] = (char *)0; sprintf(tmpbuf, "install %s", destpath); tag = tagged; if (HTList_isEmpty(tagged)) { args[src] = savepath; if (LYExecv(INSTALL_PATH, args, tmpbuf) <= 0) return (-1); count++; } else { char *name; while ((name = (char *)HTList_nextObject(tag))) { int err; args[src] = HTfullURL_toFile(name); err = (LYExecv(INSTALL_PATH, args, tmpbuf) <= 0); free(args[src]); if (err) return ((count == 0) ? -1 : count); count++; } clear_tags(); } HTInfoMsg("Installation complete"); return count; } /* * Clear DIRED tags. */ PUBLIC void clear_tags NOARGS { char *cp = NULL; while ((cp = HTList_removeLastObject(tagged)) != NULL) { FREE(cp); } if (HTList_isEmpty(tagged)) FREE(tagged); } /* * Handle DIRED menu item. */ PUBLIC void add_menu_item ARGS1( char *, str) { struct dired_menu *new, *mp; char *cp; /* * First custom menu definition causes entire default menu to be * discarded. */ if (menu_head == defmenu) menu_head = NULL; new = (struct dired_menu *)calloc(1, sizeof(*new)); /* * Conditional on tagged != NULL ? */ cp = strchr(str, ':'); *cp++ = '\0'; if (strcasecomp(str, "tag") == 0) { new->cond = DE_TAG; } else if (strcasecomp(str, "dir") == 0) { new->cond = DE_DIR; } else if (strcasecomp(str, "file") == 0) { new->cond = DE_FILE; } else if (strcasecomp(str, "link") == 0) { new->cond = DE_SYMLINK; } /* * Conditional on matching suffix. */ str = cp; cp = strchr(str, ':'); *cp++ = '\0'; StrAllocCopy(new->sfx, str); str = cp; cp = strchr(str, ':'); *cp++ = '\0'; StrAllocCopy(new->link, str); str = cp; cp = strchr(str, ':'); *cp++ = '\0'; StrAllocCopy(new->rest, str); StrAllocCopy(new->href, cp); if (menu_head) { for (mp = menu_head; mp && mp->next != NULL; mp = mp->next) ; mp->next = new; } else menu_head = new; } /* * Create URL for DIRED HREF value. */ PRIVATE char * render_item ARGS6( CONST char *, s, char *, path, char *, dir, char *, buf, int, bufsize, BOOLEAN, url_syntax) { char *cp; char *bp; char overrun = '\0'; char *taglist = NULL; #define BP_INC (bp>buf+bufsize-2 ? &overrun : bp++) /* Buffer overrun could happen for very long tag list, if %l or %t are used */ bp = buf; while (*s && !overrun) { if (*s == '%') { s++; switch (*s) { case '%': *BP_INC = '%'; break; case 'p': cp = path; if (!LYIsHtmlSep(*cp)) *BP_INC = '/'; while (*cp) *BP_INC = *cp++; break; case 'd': cp = dir; if (!LYIsHtmlSep(*cp)) *BP_INC = '/'; while (*cp) *BP_INC = *cp++; break; case 'f': cp = strrchr(path, '/'); if (cp) cp++; else cp = path; while (*cp) *BP_INC = *cp++; break; case 'l': case 't': if (!HTList_isEmpty(tagged)) { HTList *cur = tagged; char *name; while (!overrun && (name = (char *)HTList_nextObject(cur))!=NULL) { if (*s == 'l' && (cp = strrchr(name, '/'))) cp++; else cp = name; StrAllocCat(taglist, cp); StrAllocCat(taglist, " "); /* should this be %20?*/ } } if (taglist) { /* could HTUnescape here... */ cp = taglist; while (*cp) *BP_INC = *cp++; FREE(taglist); } break; default: *BP_INC = '%'; *BP_INC =*s; break; } } else { /* * Other chars come from the lynx.cfg or * the default. Let's assume there isn't * anything weird there that needs escaping. */ *BP_INC =*s; } s++; } if (overrun & url_syntax) { sprintf(buf,"Temporary URL or list would be too long."); HTAlert(buf); bp = buf; /* set to start, will return empty string as URL */ } *bp = '\0'; return buf; } #endif /* DIRED_SUPPORT */ /* * Execute DIRED command. */ PRIVATE int LYExecv ARGS3( char *, path, char **, argv, char *, msg) { #if defined(VMS) || defined(_WINDOWS) CTRACE(tfp, "LYExecv: Called inappropriately!\n"); return(0); #else int rc; char tmpbuf[512]; pid_t pid; #if HAVE_TYPE_UNIONWAIT union wait wstatus; #else int wstatus; #endif if (TRACE) { int n; CTRACE(tfp, "LYExecv path='%s'\n", path); for (n = 0; argv[n] != 0; n++) CTRACE(tfp, "argv[%d] = '%s'\n", n, argv[n]); } rc = 1; /* It will work */ tmpbuf[0] = '\0'; /* empty buffer for alert messages */ stop_curses(); pid = fork(); /* fork and execute rm */ switch (pid) { case -1: sprintf(tmpbuf, "Unable to %s due to system error!", msg); rc = 0; break; /* don't fall thru! - KW */ case 0: /* child */ execv(path, argv); exit(-1); /* execv failed, give wait() something to look at */ default: /* parent */ #if !HAVE_WAITPID while (wait(&wstatus) != pid) ; /* do nothing */ #else while (-1 == waitpid(pid, &wstatus, 0)) { /* wait for child */ #ifdef EINTR if (errno == EINTR) continue; #endif /* EINTR */ #ifdef ERESTARTSYS if (errno == ERESTARTSYS) continue; #endif /* ERESTARTSYS */ break; } #endif /* !HAVE_WAITPID */ if (WEXITSTATUS(wstatus) != 0 || WTERMSIG(wstatus) > 0) { /* error return */ sprintf(tmpbuf, "Probable failure to %s due to system error!", msg); rc = 0; } } if (rc == 0) { /* * Screen may have message from the failed execv'd command. * Give user time to look at it before screen refresh. */ sleep(AlertSecs); } start_curses(); if (tmpbuf[0]) { HTAlert(tmpbuf); } return(rc); #endif /* VMS */ }