/**********************************************************************
 * Bruce Lewis
 * MIT Project Athena
 * Created:  8/1/87
 *
 * $Source: /site/u1/exchange/teacher/RCS/fngrade.c,v $
 * $Author: brlewis $
 * $Header: fngrade.c,v 1.17 89/04/27 13:34:29 brlewis Exp $
 *
 * Copyright 1987 by the Massachusetts Institute of Technology.
 * For copying and distribution information, see the file
 * "mit-copyright.h".
 *
 * fngrade.c module -- functions of the grade menu
 **********************************************************************/
#include "mit-copyright.h"

#ifndef lint
static char rcsid_fngrade_c[] = "$Header: fngrade.c,v 1.17 89/04/27 13:34:29 brlewis Exp $";
#endif /* lint */

#include <sys/types.h>
#include<hesiod.h>
#include"teacher.h"

/**********************************************************************
 * glist(argc, argv)
 *   + lists files by student and/or assignment
 **********************************************************************/

glist(argc, argv)

     int argc;
     char *argv[];
{
  show_list(argc, argv, TURNIN);
}

/**********************************************************************
 * whois(argc, argv)
 *   + prints full name from username in Hesiod database
 **********************************************************************/

whois(argc, argv)

       int argc;
       char *argv[];
{
  char username[GENLEN];
  char **matches, *fullname, *tmp;
  int i;

  Debug((stderr, ">>>> Enter whois\n"));
  newline(1);

  if (argc == 2) (void) strcpy(username, argv[1]);
  else promptfor("Username", username);

  if ((matches = hes_resolve(username, "passwd")) == NULL)
    switch(hes_error()) {
    case HES_ER_NOTFOUND:
      printf("Could not find %s in the Hesiod database.\n", username);
      return;
    case HES_ER_CONFIG:
      printf("Local problem (bad config file?) prevents Hesiod use.\n");
      return;
    case HES_ER_NET:
      printf("Could not reach Hesiod because of network problems.\n");
      return;
    default:
      printf("Could not get information from Hesiod.\n");
      return;
    }
  /* pull full name from passwd entry: */
  /* user:password:uid:group:fullname[,,,]:homedir:shell */
  fullname = matches[0];
  for (i=0; i<4; i++)
    if ((fullname = index(++fullname, ':')) == NULL) {
      printf("%s\n", matches[0]);
      return;
    }
  if ((tmp = index(++fullname, ':')) != NULL)
    *tmp = '\0';
  if ((tmp = index(fullname, ',')) != NULL)
    *tmp = '\0';

  printf("User %s is %s.\n", username, fullname);

  newline(1);
  Debug((stderr, "<<<< Exit whois\n"));
  return;
}

/**********************************************************************
 * gdisplay(argc, argv)
 *   + copy turnin files to /tmp
 *   + start editor
 **********************************************************************/

gdisplay(argc, argv)

     int argc;
     char *argv[];
{
  teacher_display(argc, argv, TURNIN);
}

/**********************************************************************
 * gpdisplay(argc, argv)
 *   + copy pickup files to /tmp
 *   + start editor
 **********************************************************************/

gpdisplay(argc, argv)

     int argc;
     char *argv[];
{
  teacher_display(argc, argv, PICKUP);
}

/**********************************************************************
 * gannotate(argc, argv)
 *   + copy file to /tmp
 *   + start editor
 *   + add to list of annotated files
 **********************************************************************/

gannotate(argc, argv)

     int argc;
     char *argv[];
{
  FILE_ID *target;
  LIST *tlist;
  char localname[GENLEN], cargv[NOFILE][GENLEN];
  char **cargv2;  /* array of pointers needed for execv */
  int i, pid, cargc=0;  /* process id, child arg count */
  int nothing_annotated = TRUE;
  struct llist *l, *m;
  extern struct llist *anno_list;
  extern GENLIST Editor[2];

  Debug((stderr, ">>>> Enter gannotate\n"));
  newline(1);

  /* get list of files to annotate */
  if ((tlist = teacher_list(argc, argv, TURNIN)) == NULL)
    return;
  if (how_many_files(tlist) == 0)
    return;

  /* determine what editor to use */
  for(i=0; i<Editor[1].n; i++) {
    (void) strcpy(cargv[cargc++], Editor[1].genlist[i]);
    Debug((stderr, ">> cargv[%d] = %s\n", cargc-1, cargv[cargc-1]));
  }

  for(i=0; i<how_many_files(tlist); i++) {

    target = file_in(tlist, i);
    gshow(stdout, target);

    l = anno_list;
    while(l != NULL) {
      if (l->fname == NULL) break;
      else
	if (same_id(target, l->fid)) break;
      l = l->child;
    }
    if (l != NULL && l->fname != NULL) {
      printf("Already being annotated.\n");
      continue;
    }

    /* prepare a unique filename */
    uniqname(localname, target, "/tmp/");

    if (strcmp(w_status(target), NEW) != 0) {
      printf("This file is not new.\n");
      if (! say_yes("Annotate it anyway?", FALSE))
	continue;
    }

    /* retrieve the file */
    if (Fx_retrieve(target, localname) != SUCCEEDED) {
      Fx_error(localname);
    }
    else {
      nothing_annotated = FALSE;
      (void) strcpy(cargv[cargc++], localname);
      Debug((stderr, ">> cargv[%d] = %s\n", cargc-1, cargv[cargc-1]));

      /* add to list of annotated files */
      l = anno_list;
      while (l != NULL) {
	if (l->fname == NULL) break;
	else {
	  m = l;
	  l = l->child;
	}
      }
      if (l == NULL) {
	l = New(struct llist);
	m->child = l;
	l->parent = m;
	l->child = NULL;
      }
      l->fname = NewArray(char, strlen(localname) + 1);
      (void) strcpy(l->fname, localname);
      l->fid = target;
      l->status = FALSE;   /* until successfully annotated */
    }
    if (cargc > NOFILE) {
      fprintf(stderr, "Maximum files per editor reached.\n");
      fprintf(stderr, "Repeat %s request to annotate the rest.\n", argv[0]);
      break;
    }
  }

  if (nothing_annotated == TRUE) {
    Fx_destroy_list(&tlist);
    printf("No files annotated.\n");
  }
  else {
    cargv2 = NewArray(char *, 2 + cargc);
    for(i=0; i<cargc; i++) {
      cargv2[i] = cargv[i];
      Debug((stderr, ">> cargv2[%d] = %s\n", i, cargv2[i]));
    }
    cargv2[cargc] = NULL;

    if (!(pid = fork())) {
      setpgrp(0, getpid());
      if (execv(cargv[0], cargv2) == -1) {
	fprintf(stderr, "%s:  Cannot execute.\n", cargv[0]);
	_exit(-1);
      }
    }

    if (pid == -1) {
      fprintf(stderr, "Can't create subprocess for %s.", cargv[0]);
      Fx_destroy_list(&tlist);
      free( (char *) cargv2);
      return;
    }
  }

  newline(1);
  Debug((stderr, "<<<< Exit gannotate\n"));
  return;
}

/**********************************************************************
 * gdup(argc, argv)
 *   + copy files from the turnin bin
 *   + copy from /tmp if currently annotated
 **********************************************************************/

gdup(argc, argv)

     int argc;
     char *argv[];
{
  LIST *tlist;
  FILE_ID *source;
  int i;
  char destination[GENLEN], call[GENLEN], *from;
  struct llist *l;
  extern struct llist *anno_list;
  Debug((stderr, ">>>> Enter gdup\n"));
  newline(1);

  if ((tlist = teacher_list(argc, argv, TURNIN)) == NULL)
    return;

  for(i=0; i<how_many_files(tlist); i++) {
    source = file_in(tlist, i);
    gshow(stdout, source);

    promptfor("Local filename", destination);

    if (strlen(destination)==0)
      (void) strcpy(destination, f_filename(source));

    from = "from the turnin bin";
    l = anno_list;
    while (l != NULL) {
      if ((l->fname != NULL) && (same_id(l->fid, source))) {
	from = "annotated";
	Debug((stderr, "Getting local copy: %s\n", l->fname));
	(void) strcpy(call, "cp -i ");
	(void) strcat(call, l->fname);
	(void) strcat(call, " ");
	(void) strcat(call, destination);
	Debug((stderr, "System call: %s\n", call));
	if (system(call) !=0)
	  printf("System call failed: %\n", call);
	else {
	  Fx_destroy_fid(source);
	  return;
	}
      }
      l = l->child;
    }

    if (Fx_retrieve(source, destination) != SUCCEEDED)
      Fx_error("Can't retrieve file");
    else printf("Retrieved %s %s.\n", destination, from);
  }

  newline(1);
  Debug((stderr, "<<<< Exit gdup\n"));
  Fx_destroy_list(&tlist);
  return;
}

/**********************************************************************
 * greturn(argc, argv)
 *   + copy an annotated file to the pickup bin
 **********************************************************************/

greturn(argc, argv)

     int argc;
     char *argv[];
{
  /* LIST *tlist; */
  FILE_ID *crit;
  struct llist *l;
  extern struct llist *anno_list;

  newline(1);
  Debug((stderr, ">>>> Enter greturn\n"));

  crit = get_crit(argc, argv, TURNIN);
  l = anno_list;
  while (l != NULL) {
    if (l->fname != NULL)
      if (match_file_id(crit, l->fid)) {
	f_type(l->fid) = PICKUP;
	if (Fx_send(l->fname, l->fid) != SUCCEEDED) {
	  Fx_error("Can't return file");
	  Debug((stderr, "<<<< Exit greturn (failure)\n"));
	  return;
	}
	else printf("Returned %s to %s.\n", f_filename(l->fid),
		    f_student(l->fid));
	/* remove from list of annotated files */
	del_anno(l);
      }
    l = l->child;
  }

  Fx_destroy_fid(crit);
  Debug((stderr, "<<<< Exit greturn\n"));
  newline(1);
  return;
}

/**********************************************************************
 * ghput(argc, argv)
 *   + make turned-in file into a handout
 **********************************************************************/

ghput(argc, argv)

     int argc;
     char **argv;
{
  LIST *tlist;
  FILE_ID *source;
  int i, anno_flag;
  char tmpfile[GENLEN];
  struct llist *l;
  extern struct llist *anno_list;
  Debug((stderr, ">>>> Enter ghput\n"));
  newline(1);

  if ((tlist = teacher_list(argc, argv, TURNIN)) == NULL)
    return;

  for(i=0; i<how_many_files(tlist); i++) {
    source = file_in(tlist, i);
    gshow(stdout, source);

    anno_flag = FALSE;  /* until found in list of annotated files */
    l = anno_list;
    while (l != NULL) {
      if ((l->fname != NULL) && (same_id(l->fid, source))) {
	Debug((stderr, "Getting local copy: %s\n", l->fname));
	(void) strcpy(tmpfile, l->fname);
	anno_flag = TRUE;
	break;
      }
      l = l->child;
    }

    if (!anno_flag) {
      uniqname(tmpfile, source, "/tmp/#");
      if (Fx_retrieve(source, tmpfile) != SUCCEEDED) {
	Fx_error("Can't retrieve file");
	newline(1);
	Debug((stderr, "<<<< Exit ghput\n"));
	Fx_destroy_list(&tlist);
	return;
      }
    }

    f_type(source) = HANDOUTS;
    if (Fx_send(tmpfile, source) != SUCCEEDED)
      Fx_error("Can't place in handout bin");
    else printf("Placed in handout bin.");
  }

  newline(1);
  Debug((stderr, "<<<< Exit ghput\n"));
  Fx_destroy_list(&tlist);
  return;
}

/**********************************************************************
 * gput(argc, argv)
 *   + copy a local file to the pickup bin
 **********************************************************************/

gput(argc, argv)

       int argc;
       char **argv;
{
  teacher_put(argc, argv, PICKUP);
}

/**********************************************************************
 * gpurge(argc, argv)
 *   + remove a file from the turnin and pickup bins
 **********************************************************************/

gpurge(argc, argv)

     int argc;
     char *argv[];
{
  FILE_ID *target;
  LIST *tlist;
  int i;

  Debug((stderr, ">>>> Enter gpurge\n"));
  newline(1);

  if ((tlist = teacher_list(argc, argv, TURNIN)) == NULL)
    return;

  for(i=0; i<how_many_files(tlist); i++) {
    target = file_in(tlist, i);
    gshow(stdout, target);

    if (strcmp(w_status(target), PICKEDUP) != 0) {
      printf("This file is has not been picked up.\n");
      if (! say_yes("Really delete it?", FALSE))
	continue;
    }

    if (Fx_delete(target) != SUCCEEDED)
      Fx_error("Can't delete from turnin bin");
    else printf("Deleted %s from turnin bin.\n", f_filename(target));

    f_type(target) = PICKUP;

    if (Fx_delete(target) != SUCCEEDED)
      Fx_error("Can't delete from pickup bin");
    else printf("Deleted %s from pickup bin.\n", f_filename(target));
  }

  newline(1);
  Fx_destroy_list(&tlist);
  Debug((stderr, "<<<< Exit gpurge\n"));
  return;
}

/**********************************************************************
 * pblist(argc, argv)
 *   + lists pickup bin contents by student and/or assignment
 **********************************************************************/

pblist(argc, argv)
       int argc;
       char *argv[];
{
  show_list(argc, argv, PICKUP);
}

/**********************************************************************
 * ppurge(argc, argv)
 *   + remove a file from the pickup bin
 **********************************************************************/

ppurge(argc, argv)

     int argc;
     char *argv[];
{
  LIST *target;
  int i;

  Debug((stderr, ">>>> Enter ppurge\n"));
  newline(1);

  if ((target = teacher_list(argc, argv, PICKUP)) == NULL)
    return;

  for(i=0; i<how_many_files(target); i++) {
    gshow(stdout, target);
    if (! say_yes("Really delete it?", FALSE))
      {
	Fx_destroy_fid(file_in(target, i));
	return;
      }

    if (Fx_delete(file_in(target, i)) != SUCCEEDED)
      Fx_error("Can't delete from pickup bin");
    else printf("Deleted %s from pickup bin.\n",
		f_filename(file_in(target, i)));
  }

  newline(1);
  Fx_destroy_list(&target);
  Debug((stderr, "<<<< Exit ppurge\n"));
  return;
}

/**********************************************************************
 * geditor(argc, argv)
 *     change or display current editor
 *        editor 0 for display
 *        editor 1 for annotation
 **********************************************************************/

geditor(argc, argv)
     int argc;
     char *argv[];
{
  int i, num = 0;
  extern GENLIST Editor[2];
  char *command;

  if (argc > 1) {
    if (is_integer(argv[1])) {
      num = atoi(argv[1]);
      if (num == 0 || num == 1) {
	if (argc > 2) {
	  if (index(argv[2], '/') != NULL)
	    command = argv[2];
	  else
	    if ((command = find_in_path(argv[2])) == NULL) {
	      printf("%s:  Command not found.\n", argv[2]);
	      return;
	    }
	  free(Editor[num].genlist[0]);
	  Editor[num].genlist[0] = command;
	  for(i=1; i<Editor[num].n; i++)
	    free(Editor[num].genlist[i]);
	  Editor[num].n = argc - 2;
	  Editor[num].genlist = BiggerArray(char *,
					    Editor[num].genlist, argc - 1);
	  for (i=3; i<argc; i++)
	    savestring(argv[i], Editor[num].genlist[i-2]);
	  printf("Editor changed to:\n");
	}
	printf("Editor %d:  ", num);
	for(i=0; i<Editor[num].n; i++)
	  printf("%s ", Editor[num].genlist[i]);
	newline(1);
	return;
      }
    }
  }
  printf("Usage:  %s (0 or 1) [ command ]\n", argv[0]);
  return;
}
