/* Copyright (C) 1993,1994 by the author(s).
 
 This software is published in the hope that it will be useful, but
 WITHOUT ANY WARRANTY for any part of this software to work correctly
 or as described in the manuals. See the ShapeTools Public License
 for details.

 Permission is granted to use, copy, modify, or distribute any part of
 this software but only under the conditions described in the ShapeTools 
 Public License. A copy of this license is supposed to have been given
 to you along with ShapeTools in a file named LICENSE. Among other
 things, this copyright notice and the Public License must be
 preserved on all copies.
*/
/*
 * AtFStk -- Attribute Filesystem Toolkit Library
 *
 * lock.c -- AtFS toolkit library
 *
 * Author: Axel Mahler (Axel.Mahler@cs.tu-berlin.de)
 *         Andreas Lampen (Andreas.Lampen@cs.tu-berlin.de)
 *
 * $Header: lock.c[7.0] Fri Jun 25 16:38:59 1993 andy@cs.tu-berlin.de frozen $
 */

#include "atfs.h"
#include "sttk.h"
#include "atfstk.h"

LOCAL char *getText (msgText, msg)
     char *msgText, *msg;
{
  static char *txt = AT_EMPTYLOG;
  FILE *txtFile;
  struct stat statbuf;
  static int firsttime = TRUE;

  if (firsttime) {
    firsttime = FALSE;
    if (!msgText || !*msgText) {
      sprintf (stMessage, "empty %s.", msg);
      stLog (stMessage, ST_LOG_WARNING);
      return (txt);
    }
    if (*msgText == '@') { /* filename */
      if ((txtFile = fopen (&msgText[1], "r")) == NULL) {
	sprintf (stMessage, "cannot open '%s' -- empty %s.", &msgText[1], msg);
	stLog (stMessage, ST_LOG_WARNING);
	return (txt);
      }
      if (fstat (fileno(txtFile), &statbuf) == -1) {
	sprintf (stMessage, "cannot stat '%s' -- empty %s.", &msgText[1], msg);
	stLog (stMessage, ST_LOG_WARNING);
	return (txt);
      }
      if ((txt = malloc ((unsigned)(statbuf.st_size+1))) == NULL) {
	sprintf (stMessage, "not enough memory for %s.", msg);
	stLog (stMessage, ST_LOG_WARNING);
	return (txt);
      }
      memset (txt, 0, (int) statbuf.st_size+1);
      fread (txt, sizeof (char), (size_t)statbuf.st_size, txtFile);
      fclose (txtFile);
    }
    else { /* plain message text */
      txt = msgText;
    }
  }
  return (txt);
}

LOCAL int setLogAttribute (aso, attrName, prologue, attrText)
     Af_key *aso;
     char *attrName, *prologue, *attrText;
{
  char *completeAttr;

  if ((completeAttr = malloc ((unsigned)(strlen (attrName) + strlen (prologue) + strlen (attrText) + 2))) == NULL) {
    atError (AT_ERROR, "not enough memory");
    return (FALSE);
  }
  
  if (!strcmp (attrName, AT_ATTINTENT)) {
    sprintf (completeAttr, "%s=%s%s", attrName, prologue, attrText);
    if (af_setattr (aso, AF_REPLACE, completeAttr) == -1) {
      free (completeAttr);
      atError (AT_ERROR, af_errmsg ("af_setattr"));
      return (FALSE);
    }
  }
  else {
    sprintf (completeAttr, "%s%s", prologue, attrText);
    if (af_snote (aso, completeAttr) == -1) {
      free (completeAttr);
      atError (AT_ERROR, af_errmsg ("af_snote"));
      return (FALSE);
    }
  }
  free (completeAttr);
  return (TRUE);
}

static char *commentText = NULL;
static char *oldText = NULL;

EXPORT int atSetComment (aso, commentType, newText, mode)
     Af_key *aso;
     int    commentType;
     char   *newText;
     int    mode;
     /* mode = AT_FROMSTDIN -- read text from standard input
      *        AT_REUSE     -- reuse old text
      *        AT_CONFIRM   -- ask for confirmation
      */
{
  char *tmpName, *edName;
  char prologue[64], *timeStr = af_asctime(), *ptr;
  char *commentAttrName, *commentEmptyText, *commentLogText;
  FILE *tmpFile;

  if ((ptr = strrchr (timeStr, '\n')))
    *ptr = '\0';

  switch (commentType) {
  case AT_COMMENT_INTENT:
    commentAttrName = AT_ATTINTENT;
    sprintf (prologue, "[%s]%s", timeStr, AT_STARTINTENT);
    commentEmptyText = AT_EMPTYINTENT;
    commentLogText = "change intent";
    break;
  case AT_COMMENT_DESCR:
    commentAttrName = AT_ATTDESCR;
    sprintf (prologue, "[%s]%s", timeStr, AT_STARTDESCR);
    commentEmptyText = AT_EMPTYDESCR;
    commentLogText = "description";
    break;
  case AT_COMMENT_LOG:
    commentAttrName = AT_ATTLOG;
    sprintf (prologue, "[%s]%s", timeStr, AT_STARTLOG);
    commentEmptyText = AT_EMPTYLOG;
    commentLogText = "change log";
    break;
  }    

  if (!(mode & AT_REUSE)) {
    if (commentText)
      free (commentText);
    commentText = NULL;
  }

  if (newText && *newText) {
    if (commentText)
      free (commentText);
    commentText = getText (newText, commentLogText);
    return (setLogAttribute (aso, commentAttrName, prologue, commentText));
  }

  if (oldText)
    free(oldText);
  if (commentType == AT_COMMENT_INTENT)
    oldText = af_retattr (aso, commentAttrName);
  else
    oldText = af_rnote (aso);

  if (mode & AT_FROMSTDIN) {
    if (feof(stdin)) {
      if (commentText)
	return (setLogAttribute (aso, commentAttrName, prologue, commentText));
      else
	return (setLogAttribute (aso, commentAttrName, prologue, oldText ? oldText : commentEmptyText));
    }
    else {
      if (commentText)
	free (commentText);
      commentText = stGetFromStdin ('.');
      return (setLogAttribute (aso, commentAttrName, prologue, commentText[0] ? commentText : 
			       (oldText ? oldText : commentEmptyText)));
    }
  }

  if (!(isatty (fileno(stdin)))) 
    return (setLogAttribute (aso, commentAttrName, prologue, oldText ? oldText : commentEmptyText));

  if (commentText) {
    sprintf (stMessage, "Same %s as before for %s ?", commentLogText, af_retattr (aso, AF_ATTUNIXNAME));
    if (stAskConfirm (stMessage, "yes")) {
      return (setLogAttribute (aso, commentAttrName, prologue, commentText));
    }
    else {
      free (commentText);
      commentText = NULL;
    }
  }

  if (mode & AT_CONFIRM) {
    sprintf (stMessage, "Write %s for %s ?", commentLogText, af_retattr (aso, AF_ATTUNIXNAME));
    if (!stAskConfirm (stMessage, "yes"))
      return (setLogAttribute (aso, commentAttrName, prologue, oldText ? oldText : commentEmptyText));
  }

  tmpName = stTmpFile (NULL);
  tmpFile = fopen (tmpName, "w");
  fwrite (prologue, sizeof (char), (size_t)strlen (prologue), tmpFile);
  if (oldText)
    fwrite (oldText, sizeof (char), (size_t)strlen (oldText), tmpFile);
  fclose (tmpFile);

  if (!(edName = getenv ("EDITOR")))
    edName = AT_DEFAULT_EDITOR;

  sprintf (stMessage, "starting up %s ...", edName);
  stLog (stMessage, ST_LOG_MSG);
  sprintf (stMessage, "%s %s", edName, tmpName);
  if (system (stMessage) == AT_NOSHELL) {
    stLog ("couldn't execute shell", ST_LOG_ERROR);
    atError (AT_WARNING, "couldn't execute shell");
  }
  else {
    if ((tmpFile = fopen (tmpName, "r")) == NULL) {
      sprintf (stMessage, "empty %s.", commentLogText);
      stLog (stMessage, ST_LOG_MSG);
      return (setLogAttribute (aso, commentAttrName, prologue, commentEmptyText));
    }
    else {
      struct stat statbuf;

      if (fstat (fileno(tmpFile), &statbuf) == -1) {
	atError (AT_ERROR, "couldn't stat temporary file");
      }
      else {
	if ((commentText = malloc ((size_t)(statbuf.st_size+1))) == NULL)
	if (!commentText) {
	  atError (AT_ERROR, "not enough memory.");
	}
	fread (commentText, sizeof (char), (size_t)statbuf.st_size, tmpFile);
	fclose (tmpFile);
	unlink (tmpName);
	stUnRegisterFile (tmpName);
	commentText[statbuf.st_size] = '\0';
	return (setLogAttribute (aso, commentAttrName, "", commentText));
      }
    }
  }
  stLog ("Couldn't start editor. Please check EDITOR environment variable.", ST_LOG_ERROR);
  atError (AT_WARNING, "Couldn't start editor");
  return (setLogAttribute (aso, commentAttrName, prologue, commentEmptyText));
}

/*====================
 *  Locking
 *====================*/

EXPORT int atUnlock (aso)
     Af_key *aso;
{
  Af_user *waslocker;
  
  waslocker = af_unlock (aso);
  if (waslocker) {
    af_setattr (aso, AF_REMOVE, AT_ATTINTENT);
    return (TRUE);
  }
  return (FALSE);
}

