		/*********************************
		 *                               *
		 *   Visual Shell v1.17  10/92   *
		 *                               *
		 *     by Torsten Jürgeleit      *
		 *                               *
		 *           dos part 2          *
		 *                               *
		 *********************************/

	/* Includes */

#include "includes.h"
#include "imports.h"
#include "protos.h"

	/* Make new directory */

   VOID
action_make_dir(VOID)
{
   struct FileRequest  *freq1 = &file_req[active_freq],
		       *freq2 = &file_req[(active_freq ? 0 : 1)];
   struct FileNode     *fnode;
   BYTE  *dir_name;
   BPTR  lock, plock, cd_lock;
   BYTE  old_name[MAX_FILE_NAME_LEN + 1];
   ULONG old_pos;
   SHORT old_cursor_line = freq1->fr_CursorLine, error = VSH_STATUS_NORMAL;

   if (freq1->fr_Mode == FREQ_MODE_NORMAL || freq1->fr_Mode ==
							   FREQ_MODE_FIND) {
      hcomp_freq_cursor(freq1);
      print_info_line(INFO_LINE_MODE_EMPTY);
      print_fkey_text(FKEY_MODE_NONE);

      /* Save name and pos of old cursor line node */
      if (old_cursor_line != -1) {
	 fnode = get_file_node_under_cursor(freq1);
	 strncpy(&old_name[0], &fnode->fn_Text[0], (size_t)
							 fnode->fn_NameLen);
	 old_name[fnode->fn_NameLen] = '\0';
	 old_pos                     = fnode->fn_Pos;
      }
      if (dir_name = get_input(INPUT_MODE_MAKE_DIR, NULL)) {

	 /* Create new directory and check if it goes to current directory */
	 print_status(VSH_STATUS_MAKE_DIR);
	 cd_lock = (BPTR)CurrentDir(freq1->fr_DirLock);
	 if ((error = make_dir(dir_name)) == VSH_STATUS_NORMAL) {
	    if (!(lock = quiet_lock(dir_name, (LONG)SHARED_LOCK))) {
	       error = VSH_ERROR_LOCK_FAILED;
	    } else {
	       if (!(plock = ParentDir(lock))) {
		  error = VSH_ERROR_LOCK_FAILED;
	       } else {
		  if (CompareLock(plock, freq1->fr_DirLock) == LCK_EQUAL) {

		     /* Place cursor over new directory */
		     strcpy(&old_name[0], BaseName(dir_name));
		     if (old_cursor_line == -1) {
			old_cursor_line = 0;
		     }
		  }
		  UnLock(plock);
	       }
	       UnLock(lock);
	    }
	 }
	 CurrentDir(cd_lock);
	 check_date_stamp(freq1, READ_SAME_DIR_MODE_NO_CURSOR);
	 check_date_stamp(freq2, READ_SAME_DIR_MODE_NO_OUTPUT);
	 change_fkey_text();
      }
      restore_old_cursor_line(freq1, &old_name[0], old_pos, old_cursor_line);
      print_info_line(INFO_LINE_MODE_NORMAL);
   }
   print_status(error);
}
	/* Create new directory */

   SHORT
make_dir(BYTE *dir_name)
{
   BPTR  dir_lock;
   SHORT error = VSH_STATUS_NORMAL;

   /* Entry with given name already exists ? */
   if (dir_lock = quiet_lock(dir_name, (LONG)SHARED_LOCK)) {
      if (Examine(dir_lock, fib) == DOSFALSE) {
	 error = VSH_ERROR_EXAMINE_FAILED;
      } else {

	 /* Dir or file ? */
	 if (fib->fib_EntryType > 0) {
	    error = VSH_ERROR_OBJECT_ALREADY_EXISTS;
	 } else {
	    error = VSH_ERROR_DIRNAME_ALREADY_USED;
	 }
      }
      UnLock(dir_lock);
   }
   if (error == VSH_STATUS_NORMAL) {
      if (!(dir_lock = (BPTR)CreateDir(dir_name))) {
	 error = get_dos_error(VSH_ERROR_CREATEDIR_FAILED);
      } else {
	 UnLock(dir_lock);
      }
   }
   return(error);
}
	/* Delete selected entries */

   VOID
action_delete(VOID)
{
   struct FileRequest  *freq1 = &file_req[active_freq],
		       *freq2 = &file_req[(active_freq ? 0 : 1)];
   struct FileNode     *fnode;
   BYTE  old_name[MAX_FILE_NAME_LEN + 1];
   ULONG old_pos;
   SHORT old_cursor_line = freq1->fr_CursorLine, error = VSH_STATUS_NORMAL;

   if ((freq1->fr_Mode == FREQ_MODE_NORMAL || freq1->fr_Mode ==
				 FREQ_MODE_FIND) && old_cursor_line != -1) {
      hcomp_freq_cursor(freq1);
      print_fkey_text(FKEY_MODE_NONE);

      /* Save name and pos of old cursor line node */
      fnode = get_file_node_under_cursor(freq1);
      strncpy(&old_name[0], &fnode->fn_Text[0], (size_t)fnode->fn_NameLen);
      old_name[fnode->fn_NameLen] = '\0';
      old_pos                     = fnode->fn_Pos;
      if (get_answer(ANSWER_MODE_DELETE_START, (BYTE *)
	     freq1->fr_MarkedEntries, ANSWER_TYPE_YES) == ANSWER_TYPE_YES) {

	 last1_answer = ANSWER_TYPE_YES;
	 enable_abort = 1;
	 if (!freq1->fr_MarkedEntries) {

	    /* Delete entry under cursor only */
	    if ((error = delete_file(freq1, fnode)) != VSH_STATUS_NORMAL) {
	       if (error == VSH_ERROR_SKIPPED) {
		  error = VSH_STATUS_NORMAL;
	       }
	    } else {
	       remove_file_node(freq1, fnode);
	    }
	 } else {

	    /* Delete marked entries only */
	    fnode = (struct FileNode *)freq1->fr_Display.d_List->mlh_Head;
	    do {
	       if (fnode->fn_Marked) {
		  move_freq_cursor(freq1, fnode, MOVE_MODE_NO_CURSOR);
		  if ((error = delete_file(freq1, fnode)) ==
			  VSH_STATUS_NORMAL || error == VSH_ERROR_SKIPPED) {

		     /* Remove deleted entry and refresh info line */
		     freq1->fr_MarkedSize -= fnode->fn_Size;
		     freq1->fr_MarkedEntries--;
		     if (error == VSH_ERROR_SKIPPED) {

			/* Unmark skipped entry */
			fnode->fn_Marked = 0;
			print_freq_lines(freq1, (struct MinNode *)fnode,
				   (USHORT)freq1->fr_CursorLine, (USHORT)1);
			fnode = (struct FileNode *)fnode->fn_Node.mln_Succ;
			error = VSH_STATUS_NORMAL;
		     } else {
			fnode = remove_file_node(freq1, fnode);
		     }
		     print_info_line(INFO_LINE_MODE_MARKED);
		  }
	       } else {
		  fnode = (struct FileNode *)fnode->fn_Node.mln_Succ;
	       }
	    } while (error == VSH_STATUS_NORMAL && freq1->fr_MarkedEntries);
	 }

	 /* After disabling ESC clear any pending break signal */
	 enable_abort = 0;
	 SetSignal(0L, (LONG)SIGBREAKF_CTRL_C);

	 /* Change date stamp of source directory and check other one */
	 set_date_stamp(freq1);
	 refresh_dir_info(freq1);
	 check_date_stamp(freq2, READ_SAME_DIR_MODE_NO_OUTPUT);
      }
      restore_old_cursor_line(freq1, &old_name[0], old_pos, old_cursor_line);
      change_fkey_text();
   }
   print_status(error);
}
	/* Delete selected entry */

   SHORT
delete_file(struct FileRequest  *freq, struct FileNode  *fnode)
{
   struct AnchorPath     *ap;
   struct FileInfoBlock  *info;
   BPTR  lock, cd_lock;
   BYTE  *path, *last_path, *first_path = &path1_buffer[0],
	 *path_buffer = &path2_buffer[0];
   LONG  rc, last_protection;
   SHORT error = VSH_STATUS_NORMAL;

   /* Build full path name */
   build_path_name_from_file_node(first_path, freq, fnode);
   if (!(lock = quiet_lock(first_path, (LONG)SHARED_LOCK))) {
      error = VSH_ERROR_LOCK_FAILED;
   } else {
      if (!Examine(lock, fib)) {
	 error = VSH_ERROR_EXAMINE_FAILED;
      } else {

	 /* Check if directory */
	 if (fib->fib_DirEntryType >= 0) {

	    /* Delete contents of directory */
	    if (!(ap = AllocMem((LONG)(sizeof(struct AnchorPath) +
		 MAX_PATH_NAME_LEN + 1), (LONG)MEMF_PUBLIC | MEMF_CLEAR))) {
	       error = VSH_ERROR_OUT_OF_MEM;
	    } else {

	       /* Init anchor path */
	       ap->ap_BreakBits = SIGBREAKF_CTRL_C;
	       ap->ap_StrLen    = MAX_PATH_NAME_LEN;
	       ap->ap_Flags     = APF_DoWild;
	       info             = &ap->ap_Info;
	       path             = &ap->ap_Buf[0];
	       last_path        = NULL;

	       /* Find first entry in selected directory */
	       cd_lock = CurrentDir(lock);
	       if (!(rc = FindFirst(star, ap))) {

		  /* Traverse through ALL directories in current directory */
		  do {

		     /* Delete last entry */
		     if (last_path) {
			error = do_delete_file(last_path, last_protection);
		     }
		     if (error == VSH_STATUS_NORMAL ||
					       error == VSH_ERROR_SKIPPED) {
			/* Examine current entry */
			if (info->fib_DirEntryType < 0) {

			   /* File */
			   last_path       = path_buffer;
			   last_protection = info->fib_Protection;
			   error           = build_path_name_from_relative_path(last_path, path);
			} else {

			   /* Directory */
			   if (ap->ap_Flags & APF_DidDir) {
			      ap->ap_Flags   &= ~APF_DidDir;   /* don't enter dir again */
			      last_path       = path_buffer;
			      last_protection = info->fib_Protection;
			      error           = build_path_name_from_relative_path(last_path, path);
			   } else {
			      ap->ap_Flags |= APF_DoDir;   /* enter dir */
			      last_path     = NULL;
			   }
			}
		     }
		  } while ((error == VSH_STATUS_NORMAL ||
		       error == VSH_ERROR_SKIPPED) && !(rc = FindNext(ap)));
	       }
	       FreeAnchorChain(ap);
	       CurrentDir(cd_lock);
	       if (error == VSH_STATUS_NORMAL) {
		  switch (rc) {
		     case ERROR_NO_MORE_ENTRIES :

			/* Delete last entry */
			if (last_path) {
			   error = do_delete_file(last_path, last_protection);
			}
			break;
		     case ERROR_BREAK :
			error = VSH_ERROR_ABORTED;
			break;
		     default :
			error = VSH_ERROR_FINDFIRST_OR_FINDNEXT_FAILED;
			break;
		  }
	       }
	       FreeMem(ap, (LONG)(sizeof(struct AnchorPath) +
						    MAX_PATH_NAME_LEN + 1));
	    }
	 }

	 /* At last delete marked entry */
	 if (error == VSH_STATUS_NORMAL || error == VSH_ERROR_SKIPPED) {

	    /* But first unlock it */
	    UnLock(lock);
	    lock  = NULL;
	    error = do_delete_file(first_path, fib->fib_Protection);
	 }
      }
      if (lock) {
	 UnLock(lock);
      }
   }
   return(error);
}
	/* Call DOS function DeleteFile() */

   SHORT
do_delete_file(BYTE *path, LONG protection)
{
   SHORT error = VSH_STATUS_NORMAL;

   if (CheckAbort(NULL)) {
      error = VSH_ERROR_ABORTED;
   } else {

      /* Check delete protection flag */
      if (protection & FIBF_DELETE) {
	 if (last1_answer != ANSWER_TYPE_ALL) {
	    switch (last1_answer = get_answer(ANSWER_MODE_DELETE_NO_DELETE,
						      path, last1_answer)) {
	       case ANSWER_TYPE_YES :
	       case ANSWER_TYPE_ALL :
		  break;
	       case ANSWER_TYPE_NO :
		  error = VSH_ERROR_SKIPPED;
		  break;
	       case ANSWER_TYPE_ESC :
		  error = VSH_ERROR_ABORTED;
		  break;
	    }
	 }
	 if (last1_answer == ANSWER_TYPE_YES ||
					  last1_answer == ANSWER_TYPE_ALL) {
	    /* Clear delete protection flag */
	    if (SetProtection(path, (LONG)(protection & ~FIBF_DELETE)) ==
								 DOSFALSE) {
	       error = VSH_ERROR_SETPROTECTION_FAILED;
	    }
	 }
      }

      /* If no error then delete file now */
      if (error != VSH_STATUS_NORMAL) {
	 if (error == VSH_ERROR_SKIPPED) {
	    print_dos_status(DOS_MODE_SKIP, path, NULL);
	 }
      } else {
	 print_dos_status(DOS_MODE_DELETE, path, NULL);
	 if (DeleteFile(path) == DOSFALSE) {
	    error = get_dos_error(VSH_ERROR_DELETEFILE_FAILED);
	 }
      }
   }
   return(error);
}
	/* Get AmigaDOS error using IoErr() */

   SHORT
get_dos_error(SHORT error)
{
   if (error != VSH_STATUS_NORMAL && error != VSH_ERROR_ABORTED) {
      switch (IoErr()) {
	 case ERROR_FILE_NOT_OBJECT :
	    error = VSH_ERROR_NO_LOAD_FILE;
	    break;
	 case ERROR_OBJECT_IN_USE :
	    error = VSH_ERROR_OBJECT_IN_USE;
	    break;
	 case ERROR_OBJECT_EXISTS :
	    error = VSH_ERROR_OBJECT_ALREADY_EXISTS;
	    break;
	 case ERROR_OBJECT_NOT_FOUND :
	    error = VSH_ERROR_OBJECT_NOT_FOUND;
	    break;
	 case ERROR_OBJECT_WRONG_TYPE :
	    error = VSH_ERROR_OBJECT_WRONG_TYPE;
	    break;
	 case ERROR_DIRECTORY_NOT_EMPTY :
	    error = VSH_ERROR_DIRECTORY_NOT_EMPTY;
	    break;
	 case ERROR_NO_DISK :
	    error = VSH_ERROR_NO_DISK;
	    break;
	 case ERROR_NOT_A_DOS_DISK :
	    error = VSH_ERROR_NO_DOS_DISK;
	    break;
	 case ERROR_DISK_NOT_VALIDATED :
	    error = VSH_ERROR_DISK_NOT_VALIDATED;
	    break;
	 case ERROR_DISK_WRITE_PROTECTED :
	    error = VSH_ERROR_DISK_WRITE_PROTECTED;
	    break;
	 case ERROR_DISK_FULL :
	    error = VSH_ERROR_DISK_FULL;
	    break;
	 case ERROR_READ_PROTECTED :
	    error = VSH_ERROR_READ_PROTECTED;
	    break;
	 case ERROR_WRITE_PROTECTED :
	    error = VSH_ERROR_WRITE_PROTECTED;
	    break;
	 case ERROR_DELETE_PROTECTED :
	    error = VSH_ERROR_DELETE_PROTECTED;
	    break;
	 case ERROR_SEEK_ERROR :
	    error = VSH_ERROR_SEEK_FAILED;
	    break;
      }
   }
   return(error);
}
	/* Compare current dir from CLI with dir of active file req and get it if necessary */

   VOID
get_current_dir(VOID)
{
   struct CommandLineInterface  *cli  = BTOC(_parent_proc->pr_CLI);
   struct FileRequest           *freq = &file_req[active_freq];
   BPTR dir_lock;
   BYTE *path = &path1_buffer[0];
   BOOL dir_changed = FALSE;

   if (cli == save_cli && freq->fr_Mode == FREQ_MODE_NORMAL) {

      /* Any CD pending ? */
      if (delayed_cd == 1) {
	 change_current_dir();
      }

      /* CD performed ? */
      if (!delayed_cd) {

	 /* Boot device ? */
	 if (!(dir_lock = _parent_proc->pr_CurrentDir)) {
	    if (build_path_name_from_lock(path, dir_lock) ==
							VSH_STATUS_NORMAL) {
	       if (strcmp(path, &freq->fr_DirName[0])) {
		  dir_changed = TRUE;
	       }
	    }
	 } else {
	    if (CompareLock(dir_lock, freq->fr_DirLock) != LCK_EQUAL) {
	       Forbid();
	       BtoCStr(path, cli->cli_SetName, (LONG)MAX_PATH_NAME_LEN);
	       Permit();
	       if (dir_lock = quiet_lock(path, (LONG)SHARED_LOCK)) {
		  if (CompareLock(dir_lock, freq->fr_DirLock) != LCK_EQUAL) {
		     if (build_path_name_from_lock(path, dir_lock) ==
							VSH_STATUS_NORMAL) {
			dir_changed = TRUE;
		     }
		  }
		  UnLock(dir_lock);
	       }
	    }
	 }
      }
   }
   if (dir_changed == TRUE) {
      print_status(read_new_dir(freq, path, READ_DIR_MODE_NO_CD));
   }
}
	/* Compare current dir from CLI with dir of active file req and change it if necessary */

   SHORT
change_current_dir(VOID)
{
   struct CommandLineInterface *cli  = BTOC(_parent_proc->pr_CLI);
   struct FileRequest          *freq = &file_req[active_freq];
   BYTE  *cmd_name = BTOC(cli->cli_CommandName),
	 *dir_name = &freq->fr_DirName[0];
   BPTR  old_lock, new_lock, dir_lock = freq->fr_DirLock;
   SHORT error = VSH_STATUS_NORMAL;

   if (cli == save_cli && *dir_name != '\0') {

      /* Any command or script running in our CLI ? */
      if (*cmd_name || cli->cli_StandardInput != cli->cli_CurrentInput) {

	 /* Change current dir when command finished */
	 delayed_cd = 1;
      } else {

	 /* Change current dir now */
	 delayed_cd = 0;
	 Forbid();
	 old_lock = _parent_proc->pr_CurrentDir;
	 if (CompareLock(old_lock, dir_lock) != LCK_EQUAL) {
	    if (!(new_lock = DupLock(dir_lock))) {
	       error = VSH_ERROR_OUT_OF_MEM;
	    } else {
	       _parent_proc->pr_CurrentDir = new_lock;
	       CtoBStr(dir_name, cli->cli_SetName, (LONG)MAX_DIR_NAME_LEN);
	       if (old_lock) {
		  UnLock(old_lock);
	       }
	    }
	 }
	 Permit();
      }
   }
   return(error);
}
