#include <stdio.h>
#include <errno.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <ss/ss.h>
#include <com_err.h>
#include "q.h"

static char q_rcs_revision[]= "$Revision: 1.1 $";

int sci_idx;
extern ss_request_table qtest_cmds;
extern int getuid ();
static char dot[] = ".";
static char *whoami = "qtest";

void
qtest_get_homedir (home)
     char *home;
{
  char *envhome;
  struct passwd *entry;

  envhome = (char *) getenv ("HOME");

  if (envhome)
    {
      strcpy (home, envhome);
      return;
    }
  else 
    {
      entry = getpwuid (getuid ());
      if (entry == NULL)
	{
	  ss_perror (sci_idx, errno, "while getting home directory");
	  exit (1);
	}
      strcpy (home, entry->pw_dir);
    }
}

void
qtest_noop ()
{
  /* Do nothing */
}

void 
qtest_pwd ()
{
  char dir[MAXPATHLEN];

  if (!getwd (dir))
    {
      ss_perror (sci_idx, errno, dir);
      exit (1);
    }
 
  printf ("Current directory is %s\n", dir);
}

void 
qtest_chdir (argc, argv)
     int argc;
     char **argv;
{
  char *dir;

  dir = (char *) malloc (MAXPATHLEN * sizeof (char));

  if (argc == 1)
    qtest_get_homedir (dir);
  else
    strcpy (dir, argv[1]);
    
  if (chdir (dir) < 0)
    {
      ss_perror (sci_idx, errno, "while changing working directory");
      return;
    }

  free (dir);
  qtest_pwd ();
}

void
qtest_list (argc, argv)
     int argc; 
     char **argv;
{
  static char lscmd[]= "ls -FClg ";
  char *command;
  char *filename;

  filename = (argc > 1 ? argv[1] : dot);
  
  command = (char *) malloc (strlen (filename) + strlen (lscmd) + 1);
  sprintf (command, "%s %s", lscmd, filename);
  system (command);
  free (command);
}

void
qtest_stat (argc, argv)
     int argc;
     char **argv;
{
  struct stat finfo;
  char *arg;
  
  arg = (argc > 1 ? argv[1] : dot);

  if (stat (arg, &finfo) == -1)
    {
      ss_perror (sci_idx, errno, "while performing stat");
      return;
    }

  printf ("Statistics for `%s':\n", arg);

  printf ("%s has %d link%s, and is %d bytes in length.\n", arg,
          finfo.st_nlink, (finfo.st_nlink == 1) ? "" : "s",  finfo.st_size);
  printf ("      Created on: %s", ctime (&finfo.st_ctime));
  printf ("  Last access at: %s", ctime (&finfo.st_atime));
  printf ("Last modified at: %s", ctime (&finfo.st_mtime));
}

void qtest_change_access (argc, argv)
     int argc;
     char **argv;
{
  char *dir;
  AFS_acl_entry *acl_ent;
  int negative;
  long code;

  if (strcasecmp(argv[argc-1],"-negative") == 0)
    negative = 1;
  else
    negative = 0;

  if ((argc - negative) != 4)
    printf("usage: ca <dir> <who> <permissions> [-negative]\n");
  else
    {
      dir = (char *) Q_malloc (MAXPATHLEN * sizeof(char));
      acl_ent = (AFS_acl_entry *) Q_malloc (sizeof(AFS_acl_entry));

      strcpy(dir, argv[1]);
      strcpy(acl_ent->name, argv[2]);

      acl_ent->bits = Q_acl_string_to_long (argv[3], &code);
      if (acl_ent->bits == -1)
	{
	  com_err (whoami, code, "while processing permission string");
	  Q_free (dir);
	  Q_free (acl_ent);
	  return;
	}

      if (Q_set_afs_acl (dir, acl_ent, negative, &code) != 0)
	{
	  com_err (whoami, code, "while changing permissions");
	  Q_free (dir);
	  Q_free (acl_ent);
	  return;
	}
    }
}

void
qtest_file_system_type (argc, argv)
     int argc;
     char **argv;
{
  int which_fs;
  char *dir;
  long code;

  dir = (char *) Q_malloc (MAXPATHLEN * sizeof (char));

  if (argc == 1)
    strcpy (dir, dot);
  else
    strcpy (dir, argv[1]);

  which_fs = Q_file_system_type (dir, &code);

  if (which_fs == -1)
    {
      com_err (whoami, code, "while getting filesystem type");
      Q_free (dir);
      return;
    }

  switch (which_fs)
    {
    case ON_AFS:
      printf ("%s is on AFS\n", dir);
      break;
    case ON_NFS:
      printf ("%s in on NFS\n", dir);
      break;
    case ON_UFS:
      printf ("%s is on the local disk\n", dir);
      break;
    default:
      abort (); /* impossible */
    }

  Q_free (dir);
}

void
qtest_list_access (argc, argv)
     int argc;
     char **argv;
{
  AFS_acl *acl;
  int which_fs;
  char *dir;
  long code;
  int i;

  dir = (char *) malloc (MAXPATHLEN * sizeof (char));

  if (argc == 1)
    strcpy (dir, dot);
  else
    strcpy (dir, argv[1]);

  which_fs = Q_file_system_type (dir, &code);

  switch (which_fs)
    {
    case -1:
      com_err (whoami, code, "while getting filesystem type");
      return;

    case ON_AFS:
      acl = Q_get_afs_acl (dir, &code);
      if (acl == NULL)
	{
	  com_err (whoami, code, "while getting AFS acl");
	  return;
	}
      printf ("positive acls:\n");
      for (i = 0; i < acl->num_pos; i++)
	printf ("%s\t%s\n", acl->pos_entries[i].name,
		Q_long_to_acl_string (acl->pos_entries[i].bits));
      printf ("negative acls:\n");
      for (i = 0; i < acl->num_neg; i++)
	printf ("%s\t%s\n", acl->neg_entries[i].name,
		Q_long_to_acl_string (acl->neg_entries[i].bits));

      Q_free_acl (acl);
      break;

    case ON_UFS:
      fprintf (stderr, "access list for UFS not yet implemented\n");
      break;

    case ON_NFS:
      fprintf (stderr, "access list for NFS not yet implemented\n");
      break;

    default: /* impossible condition */
      abort ();
    }
  
  Q_free (dir);
}

main (argc, argv)
     int argc;
     char **argv;
{
  long code;

  sci_idx = ss_create_invocation ("qtest", q_rcs_revision, NULL, 
				  &qtest_cmds, &code);

  if (code)
    {
      ss_perror (sci_idx, code, "while creating invocation");
      exit (1);
    }

  printf ("QTEST Version %s - Type `?' for a list of commands.\n", q_rcs_revision);

  ss_listen (sci_idx, &code);

  exit (0);
}
