// --------------------------------------------------------------------
//        a t t a c h . c p p
//                                                                     
//        Fido messages tracker                            
//        work with attached files
// --------------------------------------------------------------------
//        Copyright (c) 1998-2000 by Fyodor Ustinov                         
//                                   FIDONet 2:5020/79                      
//                                                                     
//        All rights reserved.                                         
// --------------------------------------------------------------------
#include <sys/types.h>
#include <sys/stat.h>
#ifndef UNIX
#include <io.h>
#endif
#if defined (UNIX) || defined(__DJGPP__)
#include <unistd.h>
#endif
#if defined(__DJGPP__)
#include <dos.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include "constant.hpp"
#include "help.hpp"
#include "utils.hpp"
#include "vars.hpp"
#include "configure.hpp"
#include "fidoaddr.h"
#include "scandir.hpp"
#include "attach.hpp"
#include "outbound.hpp"
#include "ufmtypes.h"
#include "msg.hpp"
#ifndef O_BINARY
#define O_BINARY 0
#endif

#ifdef __NT__
#undef byte
#undef EXPENTRY
#include <windows.h>
#endif

// --------------------------------------------------------------------
static char NewPath[1024];
static char NewSubj[1024];
static int  AttSize;
// --------------------------------------------------------------------

static char *FullName(char *name) {
static char Buff[1024];
   if (FileInbound != NULL) {
      strcpy(Buff,FileInbound);
   } else {
      Buff[0] = '\0';
   }
   if (strchr(name,PATHDELIMC) == NULL 
#ifndef UNIX   
   && strchr(name,':') == NULL
#endif   
   ) {
      strcat(Buff,name);
   } else {
      strcpy(Buff,name);
   }
   return Buff;
}

int _PrintAttach(char *Buff) {
   Log.Level(LOGI) << "Attached '" << FullName(Buff) << "'" << EOL;
   return TRUE;
}

int _AttToSize(char *Buff) {
int i;
int fh;
char *tmt;

   tmt = FullName(Buff);
#ifdef __NT__
   OemToChar(tmt,tmt);
#endif
   fh = open(tmt,O_RDONLY | O_BINARY);
#ifdef __NT__
   CharToOem(tmt,tmt);
#endif
   i = errno;
   if (fh == -1) {
      if (i != ENOENT) {
         Log.Level(LOGE) << "   Unable to open file: '" << tmt << "', Errno: " << i << EOL;
         return FALSE;
      } else {
         return TRUE;
      }
   }
   
   i = filelength(fh);
   if (i == -1) {
      i = errno;
      close(fh);
      Log.Level(LOGE) << "   Unable to get size of file: '" << tmt << "', Errno: " << i << EOL;
      return FALSE;
   }
   close(fh);
   AttSize += i;
   return TRUE;
}

int _AddToLo(char *Buff) {
char tmt[1024];
   tmt[0] = NewPath[0];
   tmt[1] = '\0';
   strcat(tmt,FullName(Buff));
   AddToLo(tmt);
   return TRUE;
}

int _DelFromLo(char *Buff) {
   DelFromLo(FullName(Buff));
   return TRUE;
}

int _ChangePath(char *Buff) {
char *tmt;
   strcat(NewSubj,NewPath);
   if ((tmt = strrchr(Buff,PATHDELIMC)) != NULL) {
      tmt++;
#ifndef UNIX      
   } else if ((tmt = strrchr(Buff,':')) != NULL) {
      tmt++;
#endif      
   } else {
      tmt = Buff;
   }
   strcat(NewSubj,tmt);
   strcat(NewSubj," ");
   return TRUE;
}

int _DeleteAttach(char *Buff) {
char *tmt;
   tmt = FullName(Buff);
#ifdef __NT__
   OemToChar(tmt,tmt);
#endif
   if (access(tmt,F_OK) != 0) {
#ifdef __NT__
      CharToOem(tmt,tmt);
#endif
      Log.Level(LOGI) << "   File not found: '" << tmt << "'" << EOL;
      return TRUE;
   }
   if (unlink(tmt) != 0) {
#ifdef __NT__
      CharToOem(tmt,tmt);
#endif
      Log.Level(LOGE) << "   Unable to delete: '" << tmt << "'" << EOL;
      return FALSE;
   }
#ifdef __NT__
   CharToOem(tmt,tmt);
#endif
   Log.Level(LOGI) << "   Delete: '" << tmt << "'" << EOL;
   return TRUE;
}

int _AttachExists(char *Buff) {
struct stat dd;
char *tmt;
   tmt = FullName(Buff);
#ifdef __NT__
   OemToChar(tmt,tmt);
#endif
   if (stat(tmt,&dd) != 0) return FALSE;
   if (!S_ISREG(dd.st_mode)) return FALSE;
#ifdef __MINGW32__
   if (SkipHiddenFiles) {
      struct _finddata_t fd;
      int h = _findfirst(tmt, &fd);
      if (h != -1) {
         _findclose(h);
         if (!strcmp(fd.name, tmt) && (fd.attrib|_A_HIDDEN)) return FALSE;
      }
   }
#elif defined(__DJGPP__)
   if (SkipHiddenFiles) {
      unsigned int attrs;
      _dos_getfileattr(tmt, &attrs);
      if (attrs|_A_HIDDEN) return FALSE;
   }
#elif !defined(UNIX)
   if (SkipHiddenFiles && (dd.st_attr & 2)) return FALSE;
#endif
   return TRUE;
}

int _MoveAttach(char *Buff) {
char *tmt;
char B[1024];
   tmt = FullName(Buff);
#ifdef __NT__
   OemToChar(tmt,tmt);
#endif
   if (access(tmt,F_OK) != 0) {
#ifdef __NT__
      CharToOem(tmt,tmt);
#endif
      Log.Level(LOGI) << "   File not found: '" << tmt << "'" << EOL;
      return TRUE;
   }
   strcpy(B,NewPath);
   if ((tmt = strrchr(Buff,PATHDELIMC)) != NULL) {
      tmt++;
#ifndef UNIX      
   } else if ((tmt = strrchr(Buff,':')) != NULL) {
      tmt++;
#endif      
   } else {
      tmt = Buff;
   }
   strcat(B,tmt);
   tmt = FullName(Buff);
#ifdef __NT__
   OemToChar(tmt,tmt);
   OemToChar(B,B);
#endif
   if (!FileMove(B,tmt)) {
#ifdef __NT__
      CharToOem(tmt,tmt);
#endif
      Log.Level(LOGE) << "   Unable to move file '" << tmt << "' to " << NewPath << EOL;
      return FALSE;
   }
#ifdef __NT__
   CharToOem(tmt,tmt);
#endif
   Log.Level(LOGI) << "   Move: '" << tmt << "' ==> " << NewPath << EOL;
   return TRUE;
}

int _CopyAttach(char *Buff) {
char *tmt;
char B[1024];
   tmt = FullName(Buff);
#ifdef __NT__
   OemToChar(tmt,tmt);
#endif
   if (access(tmt,F_OK) != 0) {
#ifdef __NT__
      CharToOem(tmt,tmt);
#endif
      Log.Level(LOGI) << "   File not found: '" << tmt << "'" << EOL;
      return TRUE;
   }
   strcpy(B,NewPath);
   if ((tmt = strrchr(Buff,PATHDELIMC)) != NULL) {
      tmt++;
#ifndef UNIX      
   } else if ((tmt = strrchr(Buff,':')) != NULL) {
      tmt++;
#endif      
   } else {
      tmt = Buff;
   }
   strcat(B,tmt);
   tmt = FullName(Buff);
#ifdef __NT__
   OemToChar(tmt,tmt);
   OemToChar(B,B);
#endif
   if (!FileCopy(B,tmt)) {
#ifdef __NT__
      CharToOem(tmt,tmt);
#endif
      Log.Level(LOGE) << "   Unable to copy file '" << tmt << "' to " << NewPath << EOL;
      return FALSE;
   }
#ifdef __NT__
   CharToOem(tmt,tmt);
#endif
   Log.Level(LOGI) << "   Copy: '" << tmt << "' ==> " << NewPath << EOL;
   return TRUE;
}

// --------------------------------------------------------------------
#if defined(UNIX) || defined(__EMX__)

typedef int (*faff)(char *b);

int ForAllFiles(faff Action,cMSG &m) {
#else
int ForAllFiles(int (*Action)(char *Fname),cMSG &m) {
#endif
// For all Files attached to message do Action.
// return Action value.
// Action - int Action(char *FName);
char Buff[73];
char *tmt;
   if (m._Subject == NULL) {
      return FALSE;
   }
   if (strlen(m._Subject) == 0) {
      return FALSE;
   }
   memset(Buff,0,73);
   strncpy(Buff,m._Subject,72);
   tmt = Buff;
   while (*tmt == ' ') tmt++;
   if (*tmt == '\0') return FALSE;
   while (*tmt != '\0') {
      while (*tmt == ' ') tmt++;
      if (*tmt == '\0') break;
      int i;
      i = FALSE;
      if (strchr(tmt,' ') != NULL) {
         i = TRUE;
         *strchr(tmt,' ') = '\0';
      }
      if (!Action(tmt)) return FALSE;
      while (*tmt != '\0') tmt++;
      if (i) tmt++;
   }
   return TRUE;
}

// --------------------------------------------------------------------

int PrintAttach(cMSG &m) {
   return ForAllFiles(&_PrintAttach,m);
}

int AddAttachToLo(cMSG &m) {
   NewPath[0] = '\0';
   if (m.fTFS) {
      NewPath[0] = '#';
   }
   if (m.fKFS) {
      NewPath[0] = '^';
   }
   return ForAllFiles(&_AddToLo,m);
}

int DelAttachFromLo(cMSG &m) {
   return ForAllFiles(&_DelFromLo,m);
}

int DeleteAttach(cMSG &m) {
   return ForAllFiles(&_DeleteAttach,m);
}

int ChangePath(cMSG &m,char *Path) {
int rc;
   strcpy(NewPath,Path);
   memset(NewSubj,0,73);
   if (strlen(NewPath) != 0 && NewPath[strlen(NewPath)-1] != PATHDELIMC) {
      strcat(NewPath,PATHDELIMS);
   }

   rc = ForAllFiles(&_ChangePath,m);
   if (!rc) {
      return FALSE;
   }

   if (NewSubj[0] != '\0') {
      NewSubj[strlen(NewSubj)-1]='\0';
   }

   if (strlen(NewSubj) > 71) {
      Log.Level(LOGE) << "New subject too long. '" << NewSubj << "'" << EOL;
      return FALSE;
   }
   strncpy(m._Subject,NewSubj,72);
   return TRUE;
}
    
int GetAttSize(cMSG &m) {
int rc;
   AttSize = 0;
   rc = ForAllFiles(&_AttToSize,m);
   if (!rc) {
      return -1;
   }
   return AttSize;
}

int MoveAttach(cMSG &m,char *Path) {
int rc;
   strcpy(NewPath,Path);
   memset(NewSubj,0,73);
   if (strlen(NewPath) != 0 && NewPath[strlen(NewPath)-1] != PATHDELIMC) {
      strcat(NewPath,PATHDELIMS);
   }

   rc = ForAllFiles(&_ChangePath,m);
   if (!rc) {
      return FALSE;
   }

   if (NewSubj[0] != '\0') {
      NewSubj[strlen(NewSubj)-1]='\0';
   }

   if (strlen(NewSubj) > 71) {
      Log.Level(LOGE) << "New subject too long. '" << NewSubj << "'" << EOL;
      return FALSE;
   }
   rc = ForAllFiles(&_MoveAttach,m);
   if (!rc) {
      return FALSE;
   }
   
   strncpy(m._Subject,NewSubj,72);
   return TRUE;
}

int CopyAttach(cMSG &m,char *Path) {
int rc;
   strcpy(NewPath,Path);
   if (strlen(NewPath) != 0 && NewPath[strlen(NewPath)-1] != PATHDELIMC) {
      strcat(NewPath,PATHDELIMS);
   }

   rc = ForAllFiles(&_CopyAttach,m);
   if (!rc) {
      return FALSE;
   }
   
   return TRUE;
}

int AttachExists(cMSG &m) {
   return ForAllFiles(&_AttachExists,m);
}

// --------------------------------------------------------------------
int SetFileInbound(char *tmt) {
IndBiList<ScanDir>::ElemPtr sd;

   sd = ScanDirs.GetLast();

   if (sd == NULL) {
      if (FileInbound != NULL) {
         yyerror("File inbound directory aready defined.");
         return (-1);
      }
   } else {
      if (sd->_FileInbound != NULL) {
         yyerror("File inbound directory for this scandir aready defined.");
         return (-1);
      }
   }
   if (strlen(tmt) == 0) {
      yyerror("Missed parameter: Inbound directory name.");
      return (-1);
   }
   if (!DirExists(tmt)) {
      yyerror("Unable to open file inbound directory.");
      return (-1);
   }
   if (sd == NULL) {
      FileInbound = (char *) malloc(strlen(tmt) + 2);
      CheckMem(FileInbound);
      strcpy(FileInbound,tmt);
      if (FileInbound[strlen(FileInbound)-1] != PATHDELIMC) {
         strcat(FileInbound,PATHDELIMS);
      }
   } else {
      sd->_FileInbound = (char *) malloc(strlen(tmt) + 2);
      CheckMem(sd->_FileInbound);
      strcpy(sd->_FileInbound,tmt);
      if (FileInbound[strlen(sd->_FileInbound)-1] != PATHDELIMC) {
         strcat(sd->_FileInbound,PATHDELIMS);
      }
   }
   return 0;
}

int SetSkipHiddenFiles(void) {
   if (SkipHiddenFiles) {
      yyerror("SkipHiddenFiles already set.");
      return (-1);
   }
   SkipHiddenFiles = TRUE;
   return (0);
}

// ---------------------------- END --------------------------------------


syntax highlighted by Code2HTML, v. 0.9.1