#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <dos.h>
#include <exec/types.h>
#include <libraries/dosextens.h>

#include <dlg/resman.h>
#include <dlg/dlg.h>
#include <dlg/msg.h>
#include <dlg/user.h>
#include <dlg/input.h>
#include <dlg/misc.h>
#include <dlg/portconfig.h>

#include <link/config.h>
#include <link/io.h>
#include <link/lang.h>
#include <link/msg.h>

#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/dlg.h>

#include <pragmas/dlg.h>

#include <private/Version.h>
#define  ObjRev "3"
const UBYTE version[]="\0$VER: SendMsg " BUILDVER "." ObjRev " ©" COPYRIGHT " by Digerati Dreams "__AMIGADATE__;

#define IGNORE_CM      1024

int    main(int, char **);
void   HandleLineTermination(char *, LONG);
void   Paragraph(char *, UBYTE);
BOOL   Route(UBYTE *);
short  ConCat(char *, char *, char *);
long   FindNetArea(struct Msg_Area *);
void   CleanUp(char *);
void  _CXBRK(void);
void   Usage(char *);

struct Global_Settings Globals;
struct Msg_Header      header;
struct USER_DATA       UserDat;
struct USER_DATA       TempUser;
struct Ram_File        RStruct;
struct Msg_Area        msgarea;
struct Msg_Area        pvtarea;
struct Msg_Area        netarea;
struct fido            fido;
struct fido            destfido;
struct MsgStruct       ms;
struct MsgStruct       ms1;
struct UserInfo        ui      = {&UserDat, &RStruct};
struct Query           q       = {NULL, NULL, NULL, NULL, NULL, 0, 0, 0};

ULONG             size;
long              area;

char              port  [4]   = "";
char              uname [36];

char             *from        =  NULL;
char             *body        =  NULL;
unsigned char    *bodybuf     =  NULL;
unsigned char    *route       =  NULL;
unsigned char    *subj        =  NULL;
unsigned char    *transbuf    =  NULL;
char             *newbody     = "ram:SendMsg.body";
char              editanyway  =  FALSE;
char              delfile     =  FALSE;
char              print       =  TRUE;
UBYTE             interactive =  FALSE;
UBYTE             noformat    =  FALSE;

BPTR              sout        =  NULL;
struct Library   *DLGBase     =  NULL;
char            **SA;
long            __stack       =  16000;

/// main
int main(int argc, char *argv[])
{
   sout = Output();
   if (!sout)  print = FALSE;

   if (!(DLGBase = OpenLibrary(DLGNAME, DLGVERSION)))  exit(5);

   GetDevName(port);
   if (!(SA = getlang(port)))  CleanUp("Can't read Language file");

/// parse args
   while(--argc > 0)
   {
      char *s;

      s = *++argv;

      if (*s++ == '-')
      {
         while(*s)
         {
            switch(*s++)
            {
               case 'F':
               case 'f':
                  if (!--argc) break;
                  from = *++argv;
                  break;

               case 'S':
               case 's':
                  if (!--argc) break;
                  subj = (unsigned char *)*++argv;
                  break;

               case 'B':
               case 'b':
                  if (!--argc) break;
                  body = *++argv;
                  break;

               case 'R':
               case 'r':
                  if (!--argc) break;
                  route = (unsigned char *)*++argv;
                  break;

               case 'N':
               case 'n':
                  noformat   = TRUE;
                  break;

               case 'Q':
               case 'q':
                  print      = FALSE;
                  break;

               case 'E':
               case 'e':
                  editanyway = TRUE;
                  break;

               default:
                  Usage(SA[2976]);
                  break;
            }
         }
      }
   }
//-

   if (print)  AFPrintf(NULL, sout, "\n");

/// Interactive
   if (route && port[0])
   {
      interactive = TRUE;
      
      if (ReadUser(&RStruct,&UserDat,port))
      {
         if (!from)
         {
            strcpy(header.From, RStruct.Name);
            from = header.From;
         }

         if (!subj) 
         {
            q.prompt     = "\n Subject: ";
            q.string     = header.Title;
            q.length     = 75;
            q.typelength = 75;

            if (!DLGQuery(&q, &ui))
            {
               AFPrintf(NULL, sout, SA[2977]);
               CleanUp(NULL);
            }
            else
               subj = header.Title;

            AFPrintf(NULL, sout, "\n");
         }

         Chk_Abort();

         if (!body || editanyway)
         {
            char headerfile[36];

            ASPrintf(NULL, headerfile, "t:%s.header", port);

            if (!body)
            {
               body = newbody;
               delfile++;
            }

            if (body && editanyway)
            {
               Copy(body, newbody);
               body = newbody;
               delfile++;
            }

            DeleteFile(headerfile);

            strncpy(header.To,    route, 35);
            header.To[35] = 0;

            strncpy(header.From,  from,  35);
            header.From[35] = 0;
            
            strncpy(header.Title, subj,  72);
            header.Title[72] = 0;

            AddStruct(headerfile,(char *)&header,sizeof(header),1);

            if (CallEditor(NULL,headerfile,body,TEXT,&UserDat,&RStruct,port)==-1)
            {
               DeleteFile(headerfile);
               AFPrintf(NULL, sout, SA[2977]);
               CleanUp(NULL);
            }

            DeleteFile(headerfile);
         }
         else
         {
            Copy(body, newbody);
            body = newbody;
            delfile++;
         }
      }
      else
      {
         interactive = FALSE;
         CleanUp("Unable to read user data");
      }
   }
   else
      if (!from || !subj || !body || !route)
         Usage("Not enough args");
      else
         strcpy(port,"N/A");
//-

   if (GetFirstStruct("dlgconfig:port/FidoNet.Settings",(char *)&fido,sizeof(fido))==-1)
   {
      fido.net   = 0;
      fido.flags = 0;
   }

   if (ReadGlobals(interactive?port:"TR0", &Globals) == -1)  Globals.PrivateArea = 0;

   if (Globals.PrivateArea)
   if (!ReadArea(Globals.PrivateArea, &pvtarea, 0))
      Globals.PrivateArea = 0;

   if (!FindNetArea(&netarea))  netarea.Number = 0;

   if (FileSize(body, &size) == -1)
      CleanUp("Unable to access body file");

   bodybuf  = malloc(size + 256);
   transbuf = malloc((size * 2) + 512);

   if (!transbuf || !bodybuf)  CleanUp(SA[2978]);

   if (GetFirstStruct(body, (char *)bodybuf, size) == -1)
      CleanUp(SA[2979]);

   bodybuf[size] = 0;

   if (interactive && !noformat)   HandleLineTermination(bodybuf,size);
   Paragraph(bodybuf, noformat);

   {
      long len;

      len = strlen(bodybuf);

      if (!len || (bodybuf[len-1]!=13))
      {
         bodybuf[len++] = 13;
         bodybuf[len]   =  0;
      }
   }

   if (interactive)
   {
      BPTR   ofh;
      USHORT pos = 0;

      if (delfile)  DeleteFile(body);

      if (ofh = Open(body, MODE_NEWFILE))
      {
         movmem(&UserDat,&TempUser,sizeof(struct USER_DATA));
         TempUser.Screen_Len   = 127;
         TempUser.Screen_Width =  77;
         TempUser.Ansi_Flag    =   0;
         TempUser.More_Flag    =   0;
         DispBuffer(ofh,bodybuf,&pos,0,NULL,1,NULL,&TempUser);
         Close(ofh);
      }
      else
         CleanUp(SA[2980]);
   }

   strncpy(header.From,  from, 35);
   header.From[35]  = 0;
   strncpy(header.Title, subj, 72);
   header.Title[72] = 0;

   if (!interactive)  RStruct.Baud_Rate = 19200;
   Route(route);

   if (print)  AFPrintf(NULL, sout, "\n");
   CleanUp(NULL);
}
//-

/// HandleLineTermination
void HandleLineTermination(char *buffer,LONG size)
{
   long  index    = 0;
   long  newindex = 0;
   UBYTE crflag   = FALSE;

   for(;index < size; index++)
   {
      switch(buffer[index])
      {
         case 12:       /* Screen Clear */
            crflag = FALSE;
            continue;
            break;

         case 141:         /* Soft return */
            crflag = TRUE;
            continue;
            break;

         case 13:         /* Carriage Return */
            buffer[index] = 10;
            crflag        = TRUE;
            break;

         case 10:         /* Line Feed */
            if (!((!crflag) && (index==size-1L || buffer[index+1L]!=13)))
            {
               crflag = FALSE;
               continue;
            }
            crflag = FALSE;
            break;

         default:         /* Any other character */
            crflag = FALSE;
            break;
      }

      buffer[newindex++] = buffer[index];
   }

   buffer[newindex] = 0;
}
//-

/// Paragraph
void Paragraph(char *buf, UBYTE noformat)
{
   char *ptr;
   char *nptr;

   for(ptr = nptr = buf; *ptr; ptr++)
   {
      if (*ptr == 10)
      {
         if (noformat || (*(ptr+1)==10) || ((ptr!=buf) && ((*(ptr-1)==10) || (*(ptr-1)==13))))
         {
            *nptr++=13;
         }
         else
            if (!(isalnum(*(ptr+1)))&&(*(ptr+1)!='%'))
               *nptr++=13;
            else
               *nptr++=' ';
      }
      else
         *nptr++ = *ptr;
   }

   *nptr = 0;
}
//-

/// Route
BOOL Route(UBYTE *route)
{
   char buf[256];

   header.TimesRead = 0;
   header.DestNode  = 0;
   header.OrigNode  = 0;
   header.Cost      = 0;
   header.OrigNet   = 0;
   header.DestNet   = 0;
   header.ReplyTo   = 0;
   header.NextReply = 0;
   header.Attribute = Local;

   MDate(header.Date);

   if (print)  AFPrintf(NULL, sout, SA[2981],route);

/// Area
   if (!Strnicmp(route, "AREA", 4))
   {
      strcat(route,"|");
      sscanf(route,"%*s %ld %35[^|]",&area,header.To);

      if (ReadArea(area, &msgarea, 0))
      {
         EnterArea(area, MSGLOCK + ENTERPEND);

         ms.header    = &header;
         ms.repheader =  NULL;
         ms.body      =  transbuf;
         ms.replyto   =  0;
         ms.areainfo  = &msgarea;
         ms.flags     =  0;

         strcpy(transbuf, bodybuf);
         SendPublicMsg(&ms,&fido,"SendMsg",(interactive)?port:"N/A");

         LeaveArea(area, MSGLOCK);
         if (interactive && !from)  UserDat.Messages_Entered++;
      }

      return(TRUE);
   }
//-

/// Net
   if (!Strnicmp(route, "NET", 3))
   {
      char *s;
      char  flags[5];

      destfido.point    =  0;
//      header.Attribute |= (Private | (fido.flags & ~IGNORE_CM)); removed 1/99 & replaced w/ next line
      header.Attribute = header.Attribute | Private & ~Crash;

      if (sscanf(route, "%*s -%4s", flags))
      {
         for(s = flags; *s; s++)
         {
            switch(toupper(*s))
            {
               case 'C':  header.Attribute |= Crash;
               break;

               case 'F':  header.Attribute |= FFileRequest;
               break;

               case 'A':  header.Attribute |= FileAttached;
               break;

               case 'P':  header.Attribute &= ~Private;
               break;
            }
         }

         if (sscanf(route,"%*s %*s %hd:%hd/%hd.%hd",&(destfido.zone),&(destfido.net),&(destfido.node),&(destfido.point))<3)
         {
            AFPrintf(NULL, sout, SA[2982]);
            return(FALSE);
         }

         strcat(route,"|");
         if (!sscanf(route,"%*s %*s %*s %35[^|]",header.To))
         {
            AFPrintf(NULL, sout, SA[2983]);
            return(FALSE);
         }
      }
      else
      {
         if (sscanf(route,"%*s %hd:%hd/%hd.%hd",&(destfido.zone),&(destfido.net),&(destfido.node),&(destfido.point))<3)
         {
            AFPrintf(NULL, sout, SA[2982]);
            return(FALSE);
         }

         strcat(route,"|");
         if (!sscanf(route,"%*s %*s %35[^|]",header.To))
         {
            AFPrintf(NULL, sout, SA[2983]);
            return(FALSE);
         }
      }

      if (netarea.Number)
      {
         EnterArea(area,MSGLOCK&ENTERPEND);
         SendNet(&header,&fido,&destfido,bodybuf,(interactive)?&UserDat:NULL,0,"SendMsg",(interactive)?port:"N/A");
         if (header.Attribute&Crash)  Execute("Execute DLGConfig:Batch/CrashMail.batch",0,0);
         LeaveArea(area,MSGLOCK);
         if (interactive && !from)   UserDat.Messages_Entered++;
      }

      return(TRUE);
   }
//-

   if (!Strnicmp(route, "UUCP", 4) || !Strnicmp(route, "USENET", 6))
   {
      FILE *ufp;
      UBYTE newsflag = FALSE;

      if (toupper(*(route+1)) == 'S')  newsflag = TRUE;

      if (ufp = fopen("ram:SendMsg.tmp", "w"))
      {
         if (newsflag)
         {
            sscanf(route, "%*s %255s", buf);
            fwrite("Newsgroups: ", 12, 1, ufp);
            fwrite(buf, strlen(buf),   1, ufp);
            fwrite("\n",      1,       1, ufp);
         }
         else
         {
            sscanf(route, "%*s %255s", buf);
            fwrite("To: ",    4,       1, ufp);
            fwrite(buf, strlen(buf),   1, ufp);
            fwrite("\n",      1,       1, ufp);
         }

         fwrite("Subject: ",    9,    1, ufp);
         fwrite(subj, strlen(subj),   1, ufp);
         fwrite("\n",       1,        1, ufp);

         if (newsflag)  fwrite("Distribution: world\n", 20, 1, ufp);
         fwrite("\n", 1, 1, ufp);
         fclose(ufp);

         ASPrintf(NULL, buf, "\n\n-- Via %s\n\n", DLGSHORTNAME);
         ConCat("ram:SendMsg.tmp", body, buf);

         strcpy(uname, from);
         UnderScore(uname);

         if (newsflag)
         ASPrintf(NULL, buf, "PostNews <ram:SendMsg.tmp -f %s -r %c%s%c",uname,34,from,34);
         else
         ASPrintf(NULL, buf,"Sendmail <ram:SendMsg.tmp -f %s -R %c%s%c",uname,34,from,34);

         Execute(buf,NULL,NULL);
         DeleteFile("ram:SendMsg.tmp");
      }
      else
      AFPrintf(NULL, sout, SA[2984]);

      return(TRUE);
   }

   if (!Strnicmp(route, "FILE", 4))
   {
      FILE  *rfp;

      sscanf(route,"%*s %s", buf);

      if (rfp = fopen(buf, "r+"))
      {
         while(fgets(buf, 256, rfp))
         {
            buf[strlen(buf)-1] = 0;
            Route(buf);
         }
      }
      else
      AFPrintf(NULL, sout, SA[2985],buf);

      return(TRUE);
   }

   {
      char  transflag = FALSE;

      strncpy(header.To, route, 35);
      header.To[35] = 0;

      if (!CheckUser(header.To))
      {
         AFPrintf(NULL, sout, SA[2986]);
         return(FALSE);
      }

      DeScore(route);
      strncpy(header.To, route, 35);
      header.To[35] = 0;

      ASPrintf(NULL, buf, "USER:%s/User.Data", header.To);
      UnderScore(buf);

      if (GetFirstStruct(buf, (char *)&TempUser, sizeof(struct USER_DATA)) != -1)
      {
         strcpy(RStruct.Name, header.To);
         TranslateBuffer(bodybuf, transbuf, size*2, &TempUser, &RStruct, (interactive)?port:"N/A");
         transflag++;
         strcpy(RStruct.Name, header.From);
         SendPrivateMsg(&header, transbuf, PRI_MSG, "SendMsg", (interactive)?port:"N/A");
      }
      else
      SendPrivateMsg(&header, bodybuf, PRI_MSG, "SendMsg", "N/A");

      strcpy(RStruct.Name, header.To);

      /* Do Private redirect area */
      if (Globals.PrivateArea)
      {
         ms1.header    = &header;
         ms1.repheader =  NULL;
         ms1.body      =  transflag?transbuf:bodybuf;
         ms1.replyto   =  0;
         ms1.areainfo  = &pvtarea;
         ms1.flags     =  0;
         SendRawMsg(&ms1, NULL, "SendMsg");
      }

      if (interactive && !from)  UserDat.Messages_Entered++;
   }

   return(TRUE);
}


short ConCat(char *file1,char *file2,char *joiner)

{
   SHORT f1;
   SHORT f2;
   SHORT charsread;
   SHORT count = 0;
   char  buffer[256];

   if ((f1=open(file1,O_RDWR+O_CREAT))==EOF)  return(0);
   if ((f2=open(file2,O_RDONLY))==EOF)
   {
      close(f1);
      return(0);
   }

   lseek(f1, 0, 2);
   while((charsread = read(f2,buffer,256))==256)
   {
      write(f1, buffer, 256);
      count += 256;
   }

   write(f1, buffer, charsread);
   count += charsread;

   charsread = strlen(joiner);
   count    += charsread;
   write(f1, joiner, charsread);

   close(f1);
   close(f2);
   return(count);
}


long FindNetArea(struct Msg_Area *msgarea)

{
   int fd;

   if ((fd=open("MSG:Area.bbs",O_RDONLY))==EOF) return(FALSE);

   while(read(fd,msgarea,sizeof(struct Msg_Area))==sizeof(struct Msg_Area))
   if (msgarea->Flag&NETMAIL_AREA)
   {
      close(fd);
      return(msgarea->Number);
   }

   close(fd);
   return(FALSE);
}


void CleanUp(char *s)

{
   if (body && delfile)       DeleteFile(body);

   if (bodybuf)               free(bodybuf);
   if (transbuf)              free(transbuf);

   if (interactive && !from)  WriteUser(RStruct.Name, &UserDat);
   CloseLibrary(DLGBase);

   if (s && sout)
   {
      Write(sout, "\n Error: ", 9);
      Write(sout, s, strlen(s));
      Write(sout, "\n\n", 2);
   }

   exit(s?5:0);
}


void _CXBRK(void)

{
   CleanUp(NULL);
}


void Usage(char *string)

{
   AFPrintf(NULL, sout, SA[2987],string);
   AFPrintf(NULL, sout, SA[2988]);
   AFPrintf(NULL, sout, SA[2989]); 
   AFPrintf(NULL, sout, SA[2990]);
   AFPrintf(NULL, sout, SA[2991]);
   AFPrintf(NULL, sout, SA[2992]);
   AFPrintf(NULL, sout, SA[2993]);
   AFPrintf(NULL, sout, SA[2994]);
   AFPrintf(NULL, sout, SA[2995]);
   AFPrintf(NULL, sout, SA[2996]);
   AFPrintf(NULL, sout, SA[2997]);
   AFPrintf(NULL, sout, SA[2998]);
   AFPrintf(NULL, sout, SA[2999]);
   AFPrintf(NULL, sout, SA[3000]);
   AFPrintf(NULL, sout, SA[3001]);

   CleanUp(NULL);
}
