/*///---------------------------------------------------------------------\\\*/
/*// Copyright (c)               (_)/=\~/_(_)         All rights reserved. \\*/
/*/  2005-2006                (_)  /=\  ~/_  (_)        Released under the  \*/
/*\  Jim Peters            (_)    /=\    ~/_    (_)             GNU GPL v2  /*/
/*\\ http://uazu.net    (_) ____ /=\ ____ ~/_ ____ (_)      http://fsf.org //*/
/*\\\---------------------------------------------------------------------///*/

//
//	SMAct -- see SYMIRR.jot for docs
//   

#ifdef HEADER

typedef struct SMAct SMAct;
struct SMAct {
   char **inp;			// Input string reference
   char *base;
};

#else

#include "all.h"

//
//	SMAct
//

SMAct *
smact(char **inp, char *base, char *idts) {
   SMAct *tt= ALLOC(SMAct);

   tt->inp= inp;
   tt->base= StrDup(base);

   if (!chlog) error("smact() called without an open 'chlog' change-log");

   return tt;
}

#define RETURN goto cleanup

int 
smact_do(SMAct *tt) {
   char *freeme1= 0;
   char *freeme2= 0;
   char *freeme3= 0;
   char *p;
   char *cmd, *mug, *nam, *szt;
   char *path;
   char *fullcmd;

   if (!*tt->inp) return 0;	// Nothing to do until we have input
   if (isEOF(*tt->inp)) return 0;

   freeme1= *tt->inp;
   *tt->inp= 0;
   freeme3= fullcmd= StrDup(freeme1);

   cmd= freeme1;
   while (isspace(*cmd)) cmd++;
   if (cmd[0] == '#' || cmd[0] == 0) RETURN;

   mug= skipTSV(cmd);
   nam= skipTSV(mug);
   szt= skipTSV(nam);

   freeme2= path= StrDupF("%s%s", tt->base, nam);

   // Local mkdir
   if (str_eq(cmd, "<<mkdir")) {
      do_mkdir(path, mug);
      wrlog(nam, path);
      pipe_wrlin("%s", fullcmd); pipe_rdOK(cmd);
      RETURN;
   }

   // Local chmug
   if (str_eq(cmd, "<<chmug")) {
      do_chmug(path, mug);
      wrlog(nam, path);
      pipe_wrlin("%s", fullcmd); pipe_rdOK(cmd);
      RETURN;
   }

   // Local recursive removal
   if (str_eq(cmd, "<<rm")) {
      char *path0= StrDupF("%s%s", tt->base, mug);
      do_rm(path0);
      wrlog(mug, path0);
      free(path0);
      pipe_wrlin("%s", fullcmd); pipe_rdOK(cmd);
      RETURN;
   }

   // Local rename
   if (str_eq(cmd, "<<mv")) {
      char *nam0= mug;
      char *nam1= nam;
      char *path0= StrDupF("%s%s", tt->base, nam0);
      char *path1= path;
      if (rename(path0, path1))
	 error("Rename failed (%s): %s -> %s", strerror(errno), path0, path1);
      wrlog(nam0, path0);
      wrlog(nam1, path1);
      free(path0);
      pipe_wrlin("%s", fullcmd); pipe_rdOK(cmd);
      RETURN;
   }

   // Copy to local
   if (str_eq(cmd, "<<cp")) {
      int siz, mtim, sym;
      decode_szt(szt, &siz, &mtim, &sym);

      pipe_wrlin("%s", fullcmd);
      p= pipe_rdlin();
      if (!starts_with(p, "BIN")) 
	 error("Can't get file remotely:\n  %s\n  %s", fullcmd, p);

      if (sym) {
	 char *buf= Alloc(siz+1);
	 pipe_rdmem(buf, siz);
	 buf[siz]= 0;
	 do_symlink(path, buf);
	 free(buf);
      } else {
	 do_backup(path);
	 pipe_rdfile(path, siz);
	 do_mtime(path, mtim);
      }
      do_chmug(path, mug);

      wrlog(nam, path);

      // Expecting a sync-check blank line to end the exchange
      p= pipe_rdlin();
      if (*p) error("Bad sync in '<<cp' command remote exchange:\n  %s", p);
      RETURN;
   }

   // Remote changes
   if (str_eq(cmd, ">>mkdir")) {
      pipe_wrlin("%s", fullcmd); pipe_rdOK(cmd);
      wrlog(nam, path);
      RETURN;
   }
   if (str_eq(cmd, ">>chmug")) {
      pipe_wrlin("%s", fullcmd); pipe_rdOK(cmd);
      wrlog(nam, path);
      RETURN;
   }
   if (str_eq(cmd, ">>rm")) {
      char *path0= StrDupF("%s%s", tt->base, mug);
      pipe_wrlin("%s", fullcmd); pipe_rdOK(cmd);
      wrlog(mug, path0);
      free(path0);
      RETURN;
   }
   if (str_eq(cmd, ">>mv")) {
      // We log both files, just in case; this will result in
      // duplicate entries for some files in the log
      char *nam0= mug;
      char *nam1= nam;
      char *path0= StrDupF("%s%s", tt->base, nam1);
      char *path1= path;
      wrlog(nam0, path0);
      wrlog(nam1, path1);
      free(path0);
      pipe_wrlin("%s", fullcmd); pipe_rdOK(cmd);
      RETURN;
   }
   if (str_eq(cmd, ">>cp")) {
      int siz, mtim, sym;
      decode_szt(szt, &siz, &mtim, &sym);
      pipe_wrlin("%s", fullcmd);
      if (sym) {
	 char *buf= Alloc(siz+1);
	 int cnt= readlink(path, buf, siz+1);
	 if (cnt <= 0) error("Can't read symlink (%s): %s", strerror(errno), path);
	 if (cnt != siz) error("Symbolic link length has changed (was %d): %s", siz, path);
	 pipe_wrmem(buf, siz);
	 free(buf);
      } else {
	 pipe_wrfile(path, siz);
      }
      pipe_wrlin("");	// Blank line to sync-check after data
      pipe_rdOK(cmd);
      wrlog(nam, path);
      RETURN;
   }

   warn("Unknown command provided to SMAct *ignored*:\n  %s", cmd);
   RETURN;

 cleanup:
   if (freeme1) free(freeme1);
   if (freeme2) free(freeme2);
   if (freeme3) free(freeme3);
   return 1;
}
   
void 
smact_del(SMAct *tt) {
   chlog_close();
   free(tt->base);
   free(tt);
}

#endif

/*///---------------------------------------------------------------------\\\*/
/*// )`( )()/)(`/\`//\`          (_)/=\~/_(_)           '/\\'/\')(\()( )'( \\*/
/*/ ()(')()\)(/`/\\ `         (_)  /=\  ~/_  (_)          ' //\'\)(/()(`)() \*/
/*\  )`()( )(/'            (_)    /=\    ~/_    (_)             `\)( )()'(  /*/
/*\\  ()()(`)(/         (_) ____ /=\ ____ ~/_ ____ (_)          \)(')()()  //*/
/*\\\---------------------------------------------------------------------///*/
