/**********************************************************************
 * Stock Answer -> TechInfo program
 * by Bruce Lewis
 *
 * $Author: brlewis $
 * $Source: /mit/techinfodev/src/util/RCS/sa2ti.c,v $
 * $Header: /mit/techinfodev/src/util/RCS/sa2ti.c,v 1.6 1995/04/10 20:56:19 brlewis Exp $
 *
 * Copyright 1993 by the Massachusetts Institute of Technology.
 *
 * For copying and distribution information, please see the file
 * <mit-copyright.h>.
 **********************************************************************/
#include <mit-copyright.h>

static char rcsid_sa2ti_c[] = "$Header: /mit/techinfodev/src/util/RCS/sa2ti.c,v 1.6 1995/04/10 20:56:19 brlewis Exp $";

#define SA2TI_MAXENTRIES 255

#define ABORT { com_err("sa2ti", code, "(%s)", ti_context); exit(1); }
#define USAGEFMT "Usage: %s [-r] [-q] [-server H] [-port P]\n"
int quietf=0, recursef = 0;

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <ti/ti.h>
#include <ti/node.h>
#include <ctype.h>

/* global variables */
unsigned long guess = NT_ASCII;

new_menu(tp, title, parent, tids, tid_countp, locker, dir)
     TI *tp;
     char *title;
     ti_node *parent;
     long tids[];
     int *tid_countp;
     char *locker, *dir;
{
  long code;
  ti_node *newnode;
  char filename[256];
  FILE *fp;

  /* create new node */
  if (code=ti_newnode(&newnode)) ABORT;
  ti_settype(newnode, TI_NMENU);
  ti_settitle(newnode, title);
  ti_setsource(newnode, ti_source(parent));
  if (!quietf) printf("adding folder \"%s\"\n", title);
  if (code=ti_add(tp, newnode)) ABORT;
  if (code=ti_link(tp, ti_id(parent), ti_id(newnode)))
    ABORT;
  tids[(*tid_countp)++] = ti_id(newnode);

  /* create .ti_info file */
  sprintf(filename, "%s/.ti_info", dir);
  if (!(fp=fopen(filename, "w")))
    { perror(filename); exit(1); }
  fprintf(fp, "%s %s %ld\n", locker, dir, ti_id(newnode));
  if (fclose(fp) == EOF)
    { perror(filename);
      unlink(filename);
      exit(1); }
  ti_freenode(newnode);

  /* fill in child nodes */
  sa2ti(tp, dir);
  return;
}

found_node(tp, foundp, to_delete, tnodes, i, ititle, tids, tid_countp)
     TI *tp;
     int *foundp;
     ti_node *to_delete[], **tnodes;
     int i;
     char *ititle;
     long tids[];
     int *tid_countp;
{
  long code;

  /* found corresponding node */
  *foundp=1;

  /* rm from to_delete list */
  to_delete[i] = (ti_node *)0;

  /* fix title if necessary */
  if (strcmp(ti_title(tnodes[i]), ititle))
    {
      if (!quietf)
	printf("Changing \"%s\" to \"%s\"\n", ti_title(tnodes[i]), ititle);
      ti_settitle(tnodes[i], ititle);
      if (code=ti_replace(tp, tnodes[i])) ABORT;
    }

  /* set order */
  tids[(*tid_countp)++] = ti_id(tnodes[i]);
  return;
}

sa2ti_reorder(tp, myid, tids, tnodes, i)
     TI *tp;
     long myid;
     long tids[];
     ti_node **tnodes;
     int i;
{
  long code;
  ti_node *tmp;
  int j;

  if (!(code= ti_reorder(tp, myid, ti_id(tnodes[i+1]), tids[i])))
    {
      /* skip ahead to the node to move */
      for(j= i+1; ti_id(tnodes[j]) != tids[i]; j++)
	;

      /* rotate the nodes */
      if (!quietf) printf("Reordering \"%s\"\n", ti_title(tnodes[j]));
      tmp= tnodes[j];
      while (j > i)
	{
	  tnodes[j] = tnodes[j-1];
	  j--;
	}
      tnodes[i] = tmp;
    }
  else if (!quietf) com_err("sa2ti: warning", code, "(%s)", ti_context);

  return;
}

sa2ti(tp, dir)
     TI *tp;
     char *dir;
{
  long code;
  FILE *fp1, *fp2;
  char locker[64], cwd_path[256], childlocker[64], childpath[256];
  long myid, childid;
  char tmpstring1[256], tmpstring2[256], tmpstring3[256], *s;
  ti_node **tnodes;
  ti_menu *tmenu;
  int tnodecount, i, MIT_only;
  ti_node *to_delete[SA2TI_MAXENTRIES];
  char *itype, *ititle, *ifilename;
  long tids[256];
  int tid_count=0, found=0;
  ti_node *newnode;
  extern int errno;

  /* read .ti_info file */
  sprintf(tmpstring1, "%s/.ti_info", dir);
  if (!(fp1 = fopen(tmpstring1, "r")))
    {
      perror(tmpstring1);
      exit(1);
    }

  /* we want cwd_path from the file rather than getcwd()
     because we want /mit/foo/bar rather than /afs/..... */
  if (fscanf(fp1, "%s %s %ld", locker, cwd_path, &myid) == EOF)
    {
      perror(tmpstring1);
      exit(1);
    }
  fclose(fp1);

  /* check for MIT-eyes-only dotfile */
  MIT_only=
    (!access(strcat(strcpy(tmpstring1, dir), "/.mit-only"), F_OK) ||
     !access(strcat(strcpy(tmpstring1, dir), "/.usa-only"), F_OK));

  /* get corresponding menu from TechInfo */
  if (code = ti_otl(tp, &tmenu, TI_BELOW, myid, 1)) ABORT;
  if (code = ti_rdmenu(tmenu, &tnodes, &tnodecount)) ABORT;
  if (tnodecount < 1)
    {
      fprintf(stderr, "sa2ti: No TechInfo folder with id %ld!\n", myid);
      exit(1);
    }

  /* construct to_delete list */
  to_delete[0] = NULL;
  for (i=1; i<tnodecount; i++) to_delete[i] = tnodes[i];
  to_delete[tnodecount] = (ti_node *)0;

  /* open .index file */
  sprintf(tmpstring1, "%s/.index", dir);
  if (!(fp1 = fopen(tmpstring1, "r")))
    {
      perror("sa2ti: .index");
      exit(1);
    }
  while (fgets(tmpstring2, 255, fp1))
    {
      if (!*tmpstring2 || isspace(*tmpstring2)) continue;

      /* parse line from .index file */
      itype=tmpstring2;
      if (strncmp(tmpstring2, "entry:", 6) &&
	  strncmp(tmpstring2, "directory:", 10))
	{
	  fprintf(stderr, "sa2ti: Can't parse .index line \"%s\".\n",
		  tmpstring2);
	  exit(1);
	}
      ititle=strchr(itype, ':');
      *ititle++ = '\0';
      ifilename=strchr(ititle, ':');
      if (!ifilename)
	{
	  *(ititle-1)=':';
	  fprintf(stderr, "sa2ti: Can't parse .index line \"%s\".\n",
		  tmpstring2);
	  exit(1);
	}
      *ifilename++ = '\0';

      /* cut off at : or newline */
      for(s=ifilename; *s; s++)
	{
	  if (*s == ':' || *s < ' ')
	    { *s = '\0'; break; }
	}

      if (strchr(ifilename, ':')) *(char *)strchr(ifilename, ':') = '\0';
      if (strchr(ifilename, '\n')) *(char *)strchr(ifilename, '\n') = '\0';

      /* find corresponding TechInfo node for entry */
      if (!strcmp(itype, "entry"))
	{
	  sprintf(tmpstring3, "%s/%s", cwd_path, ifilename);
	  found=0;
	  for (i=1; i<tnodecount; i++)
	    {
	      if (!strcmp(ti_file(tnodes[i]), tmpstring3))
		{
		  found_node(tp, &found, to_delete, tnodes, i, ititle,
			     tids, &tid_count);
		  break;
		}
	    }
	  /* no corresponding node? insert, set order */
	  if (!found)
	    {
	      if (code=ti_newnode(&newnode)) ABORT;
	      ti_settitle(newnode, ititle);
	      ti_setsource(newnode, ti_source(tnodes[0]));
	      ti_setlocker(newnode, locker);
	      ti_setfile(newnode, tmpstring3);
	      ti_fixtype(newnode, guess);
	      if (MIT_only) ti_setflag(newnode, TI_NPRIVATE_IP);
	      if (!quietf) printf("adding document \"%s\"\n", ititle);
	      if (code=ti_add(tp, newnode)) ABORT;
	      if (code=ti_link(tp, myid, ti_id(newnode))) ABORT;
	      tids[tid_count++] = ti_id(newnode);
	      ti_freenode(newnode);
	    }
	}
      else /* directory */
	{
	  /* if .ti_info file exists, find corresponding node */
	  sprintf(tmpstring3, "%s/%s/.ti_info", dir, ifilename);
	  if ((fp2=fopen(tmpstring3, "r")) != NULL
	      && fscanf(fp2, "%s %s %ld",
			childlocker, childpath, &childid) != EOF)
	    {
	      
	      fclose(fp2);
	      found=0;
	      for(i=1; i<tnodecount; i++)
		{
		  if (ti_id(tnodes[i]) == childid)
		    {
		      found_node(tp, &found, to_delete, tnodes, i, ititle,
				 tids, &tid_count);
		      break;
		    }
		}

	      /* link into TechInfo folder if necssary */
	      if (!found)
		{
		  if (code=ti_newnode(&newnode)) ABORT;
		  if (code=ti_nodeinfo(tp, childid, newnode)) ABORT;
		  if ((code=ti_nodechk(newnode)) == TI_ERR_NONODE)
		    {
		      sprintf(tmpstring3, "%s/%s", cwd_path, ifilename);
		      new_menu(tp, ititle, tnodes[0], tids, &tid_count,
			       locker, tmpstring3);
		      continue;
		    }
		  else
		    {
		      if (code=ti_link(tp, myid, childid)) ABORT;
		    }
		}
	    }
	  else /* .ti_info file doesn't exist or is corrupt; create */
	    {
	      if (fp2)
		{
		  fclose(fp2);
		  unlink(tmpstring3);
		}
	      sprintf(tmpstring3, "%s/%s", cwd_path, ifilename);
	      new_menu(tp, ititle, tnodes[0], tids, &tid_count,
		       locker, tmpstring3);
	      continue;
	    }

	  /* recurse to new dir */
	  if (recursef)
	    {
	      sprintf(tmpstring3, "%s/%s", cwd_path, ifilename);
	      if (!quietf) printf("Checking \"%s\"\n", tmpstring3);
	      sa2ti(tp, tmpstring3);
	    }
	}
    }

  /* make sure there's no error */
  if (ferror(fp1))
    {
      fprintf(stderr, "sa2ti: %s/.index: %s\n", dir, error_message(errno));
      exit(1);
    }
  fclose(fp1);

  /* delete nodes in to_delete list */
  for(i=1; i<tnodecount; i++)
    {
      if (to_delete[i])
	{
	  if (!quietf) printf("deleting \"%s\"\n", ti_title(to_delete[i]));
	  if (code=ti_rmr(tp, myid, to_delete[i]))
	    fprintf(stderr, "sa2ti: Couldn't remove \"%s\"; %s (%s)\n",
		    ti_title(to_delete[i]), error_message(code), ti_context);
	}
    }

  if (tid_count)
    {
      /* get order of nodes in TechInfo */
      ti_freenodes(tnodes);
      if (code = ti_rdmenu(tmenu, &tnodes, &tnodecount)) ABORT;
      if (tnodecount < 2)
	{
	  fprintf(stderr, "sa2ti: No children of %ld!\n", myid);
	  exit(1);
	}

      /* reorder nodes */
      for(i=0; i<tid_count-1; i++)
	if (ti_id(tnodes[i+1]) != tids[i])
	  sa2ti_reorder(tp, myid, tids, tnodes, i);
    }

  return;
}

main(argc, argv)
     int argc;
     char *argv[];
{
  long code;
  char *server=NULL, *port=NULL;
  TI *tp;
  int arg;

  /* parse arguments */
  for(arg=1; arg<argc; arg++)
    {
      if (argv[arg][0] == '-')
	{
	  if (!strcmp(argv[arg], "-r"))
	    {
	      recursef = 1;
	      continue;
	    }
	  if (!strcmp(argv[arg], "-q"))
	    {
	      quietf = 1;
	      continue;
	    }
	  if (!strcmp(argv[arg], "-server"))
	    {
	      server = argv[++arg];
	      continue;
	    }
	  if (!strcmp(argv[arg], "-port"))
	    {
	      port = argv[++arg];
	      continue;
	    }
	  if (!strcmp(argv[arg], "-guess"))
	    {
	      guess = strtoul(argv[++arg], (char **)0, 10);
	      continue;
	    }
	  fprintf(stderr, USAGEFMT, argv[0]);
	  exit(1);
	}
      else
	{
	  fprintf(stderr, USAGEFMT, argv[0]);
	  exit(1);
	}
    }

  /* connect to the TechInfo server */
  if (code=ti_open(server, port, &tp)) ABORT;

  /* authenticate */
  if (code=ti_auth(tp, TI_KERBEROS, "")) ABORT;

  /* convert the current working directory */
  sa2ti(tp, ".");

  /* done */
  ti_close(tp);
  exit(0);
}
