#include <exec/types.h>
#include <dos/dos.h>
#include <dos/datetime.h>

#include <tosser/fidonet.h>
#include <tosser/chartabs.h>

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>

#include <clib/dos_protos.h>
#include <clib/exec_protos.h>

#define SWAP(x) ((x >> 8) + ((x & 255) * 256))

UBYTE *monthtab[12]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};

#define VERSION "2.1"
UBYTE *ver="\0$VER: CrashWrite "VERSION" ("__COMMODORE_DATE__")"; 

#define FROMNAME     0
#define FROMADDR     1
#define TONAME       2
#define TOADDR       3
#define SUBJECT      4
#define AREA         5
#define ORIGIN       6
#define NOMSGID      7
#define DIRECTORY    8
#define TEXT         9
#define CHRS         10
#define FATTACH      11

ULONG argarray[13];
UBYTE *argstring="FROMNAME=FN/K,FROMADDR=FA/K/A,TONAME=TN/K,TOADDR=TA/K/A,SUBJECT=SUBJ/K,AREA/K,ORIGIN/K,NOMSGID/S,DIR/K,TEXT/A,CHRS/K,FILEATTACH/S";

struct PktHeader PktHeader = { 0,      /* OrigNode */
                               0,      /* DestNode */

                               0,      /* Datum, fixas senare */
                               0,
                               0,
                               0,
                               0,
                               0,

                               0,      /* Baud    */
                               0x0200, /* PktType */

                               0,      /* OrigNet      */
                               0,      /* DestNet      */
                               0xfe,   /* ProdCodeLow  */
                               0,      /* RevMajor     */
                               "",     /* Password     */

                               0,      /* QOrigZone    */
                               0,      /* QDestZone    */

                               0,      /* AuxNet       */
                               0x0001, /* CWValidCopy  */
                               0,      /* ProdCodeHigh */
                               0,      /* RevMinor     */
                               0x0100, /* CW           */

                               0,      /* OrigZone     */
                               0,      /* DestZone     */
                               0,      /* OrigPoint    */
                               0,      /* DestPoint    */
                               0 };   /* ProdData     */

struct PktMsgHeader MsgHeader = { 0x0200,      /* PktType  */

                               0,           /* OrigNode */
                               0,           /* DestNode */
                               0,           /* OrigNet  */
                               0,           /* DestNet  */
                               0,           /* Attr     */
                               0 };         /* Cost     */

struct charset
{
   UBYTE *cmdname;
   UBYTE *chrsname;
   UBYTE *xlat;
};

#define NUM_CHARSETS 5

struct charset charsets[] = {  "LATIN-1","LATIN-1 2", NULL,
                               "IBMPC",  "IBMPC 2",   AmigaToIbm,
                               "MAC",    "MAC 2",     AmigaToMac,
                               "SWEDISH","SWEDISH 1", AmigaToSF7,
                               "IBNPC",  "IBMPC 2",   AmigaToIbn };

struct Node4D
{
   UWORD Zone,Net,Node,Point;
};
                 
UBYTE MsgTo[36]="All";
UBYTE MsgFrom[36]="CrashWrite";
UBYTE MsgSubj[72]="Information";

Xlat(UBYTE *buf,ULONG len,UBYTE *chrs)
{
   ULONG c;

   if(!chrs)
      return;

   for(c=0;c<len;c++)
   {
      if(buf[c]!=0 && chrs[buf[c]]==0)
         buf[c]='?';

      else
         buf[c]=chrs[buf[c]];
   }
}

Parse4D(UBYTE *buf, struct Node4D *node)
{
   ULONG c=0,val=0;
   BOOL GotZone=FALSE,GotNet=FALSE,GotNode=FALSE;

   node->Zone=0;
   node->Net=0;
   node->Node=0;
   node->Point=0;

	for(c=0;c<strlen(buf);c++)
	{
		if(buf[c]==':')
		{
         if(GotZone || GotNet || GotNode) return(FALSE);
			node->Zone=val;
         GotZone=TRUE;
			val=0;
	   }
		else if(buf[c]=='/')
		{
         if(GotNet || GotNode) return(FALSE);
         node->Net=val;
         GotNet=TRUE;
			val=0;
		}
		else if(buf[c]=='.')
		{
         if(GotNode) return(FALSE);
         node->Node=val;
         GotNode=TRUE;
			val=0;
		}
		else if(buf[c]>='0' && buf[c]<='9')
		{
         val*=10;
         val+=buf[c]-'0';
		}
		else return(FALSE);
	}
   if(GotZone && !GotNet)  node->Net=val;
   else if(GotNode)        node->Point=val;
   else                    node->Node=val;

   return(TRUE);
}

#define BUFSIZE 2048
UBYTE buf[BUFSIZE];

main()
{
   struct RDArgs *rdargs;
   struct Node4D fromnode,tonode;
   struct DateTime dt;
   UBYTE date[LEN_DATSTRING];
   UBYTE time[LEN_DATSTRING];
   UBYTE filenamebuf[200],tmpbuf[1000];
   struct charset *charset;
   ULONG t;
   LONG c,rlen;
   BPTR ifh,ofh,l;

   if(!(rdargs=(struct RDArgs *)ReadArgs(argstring,argarray,NULL)))
   {
      PrintFault(IoErr(),NULL);
      exit(10);
   }

   if(argarray[DIRECTORY]==NULL) argarray[DIRECTORY]="MAIL:Inbound";
   if(argarray[ORIGIN]==NULL) argarray[ORIGIN]="Another user of CrashMail!";

   if(argarray[FROMNAME])
   {
      strncpy(MsgFrom,(UBYTE *)argarray[FROMNAME],36);
      MsgFrom[35]=0;
   }

   if(argarray[TONAME])
   {
      strncpy(MsgTo,(UBYTE *)argarray[TONAME],36);
      MsgTo[35]=0;
   }

   if(argarray[SUBJECT])
   {
      strncpy(MsgSubj,(UBYTE *)argarray[SUBJECT],72);
      MsgSubj[71]=0;
   }

   if(argarray[FROMADDR])
   {
      if(!(Parse4D((UBYTE *)argarray[FROMADDR],&fromnode)))
      {
         Printf("Invalid address \"%s\"\n",(long)argarray[FROMADDR]);
         FreeArgs(rdargs);
         exit(10);
      }

      MsgHeader.OrigNode  = SWAP(fromnode.Node);
      MsgHeader.OrigNet   = SWAP(fromnode.Net);

      PktHeader.OrigNode  = SWAP(fromnode.Node);
      PktHeader.OrigNet   = SWAP(fromnode.Net);

      PktHeader.QOrigZone = SWAP(fromnode.Zone);
      PktHeader.OrigZone  = SWAP(fromnode.Zone);

      PktHeader.OrigPoint = SWAP(fromnode.Point);
   }

   if(argarray[TOADDR])
   {
      if(!(Parse4D((UBYTE *)argarray[TOADDR],&tonode)))
      {
         Printf("Invalid address \"%s\"\n",(long)argarray[TOADDR]);
         FreeArgs(rdargs);
         exit(10);
      }
      MsgHeader.DestNode  = SWAP(tonode.Node);
      MsgHeader.DestNet   = SWAP(tonode.Net);

      PktHeader.DestNode  = SWAP(tonode.Node);
      PktHeader.DestNet   = SWAP(tonode.Net);

      PktHeader.QDestZone = SWAP(tonode.Zone);
      PktHeader.DestZone  = SWAP(tonode.Zone);

      PktHeader.DestPoint = SWAP(tonode.Point);
   }

   charset=NULL;

   if(argarray[CHRS])
   {
      for(c=0;c<NUM_CHARSETS;c++)
         if(stricmp((UBYTE *)argarray[CHRS],charsets[c].cmdname)==0) break;

      if(c == NUM_CHARSETS)
      {
         Printf("Unknown charset \"%s\"\n",(long)argarray[CHRS]);
         FreeArgs(rdargs);
         exit(10);
      }

      charset=&charsets[c];
   }

   PutStr("\x1b[4mCrashWrite "VERSION" © 1995-1996 Johan Billing\x1b[24m\n");

   DateStamp(&dt.dat_Stamp);

   dt.dat_Format=FORMAT_CDN;
   dt.dat_Flags=0;
   dt.dat_StrDay=NULL;
   dt.dat_StrDate=date;
   dt.dat_StrTime=time;

   DateToStr(&dt);

   date[2]=0;
   date[5]=0;
   time[2]=0;
   time[5]=0;

   PktHeader.Year   = SWAP(atoi(&date[6])+1900);
   PktHeader.Month  = SWAP(atoi(&date[3])-1);
   PktHeader.Day    = SWAP(atoi(date));
   PktHeader.Hour   = SWAP(atoi(time));
   PktHeader.Minute = SWAP(atoi(&time[3]));
   PktHeader.Second = SWAP(atoi(&time[6]));

   if(argarray[AREA]==NULL)
      MsgHeader.Attr|=PVT;

   if(argarray[FATTACH])
      MsgHeader.Attr|=FILEATTACH;

   MsgHeader.Attr=SWAP(MsgHeader.Attr);

   t=dt.dat_Stamp.ds_Days*24*60*60+dt.dat_Stamp.ds_Minute*60+dt.dat_Stamp.ds_Tick/50;

   strcpy(filenamebuf,(UBYTE *)argarray[DIRECTORY]);
   sprintf(tmpbuf,"%08lx.PKT",t);
   AddPart(filenamebuf,tmpbuf,200);

   l=Lock(filenamebuf,SHARED_LOCK);

   while(l || IoErr()==ERROR_OBJECT_IN_USE)
   {
      if(l) UnLock(l);
      t++;

      strcpy(filenamebuf,(UBYTE *)argarray[DIRECTORY]);
      sprintf(tmpbuf,"%08lx.PKT",t);
      AddPart(filenamebuf,tmpbuf,200);

      l=Lock(filenamebuf,SHARED_LOCK);
   }

   if(!(ifh=Open((UBYTE *)argarray[TEXT],MODE_OLDFILE)))
   {
      Printf("Error! Unable to open \"%s\" for reading\n",(long)argarray[TEXT]);
      FreeArgs(rdargs);
      exit(10);
   }

   if(!(ofh=Open(filenamebuf,MODE_NEWFILE)))
   {
      Printf("Error! Unable to open \"%s\" for writing\n",(long)filenamebuf);
      Close(ifh);
      FreeArgs(rdargs);
      exit(10);
   }

   PutStr("Writing...\n");
   Printf(" From: %-36s (%lu:%lu/%lu.%lu)\n",(long)MsgFrom,fromnode.Zone,fromnode.Net,fromnode.Node,fromnode.Point);
   Printf("   To: %-36s (%lu:%lu/%lu.%lu)\n",(long)MsgTo,tonode.Zone,tonode.Net,tonode.Node,tonode.Point);
   Printf(" Subj: %s\n",(long)MsgSubj);

   FWrite(ofh,&PktHeader,sizeof(struct PktHeader),1);
   FWrite(ofh,&MsgHeader,sizeof(struct PktMsgHeader),1);

   FPrintf(ofh,"%02ld %s %02ld  %02ld:%02ld:%02ld",
         atoi(date),
         monthtab[atoi(&date[3])-1],
         atoi(&date[6]),
         atoi(time),
         atoi(&time[3]),
         atoi(&time[6]));

   FPutC(ofh,0);

   if(charset)
   {
      Xlat(MsgTo,strlen(MsgTo),charset->xlat);
      Xlat(MsgFrom,strlen(MsgFrom),charset->xlat);
      Xlat(MsgSubj,strlen(MsgSubj),charset->xlat);
   }

   FPuts(ofh,MsgTo);
   FPutC(ofh,0);

   FPuts(ofh,MsgFrom);
   FPutC(ofh,0);

   FPuts(ofh,MsgSubj);
   FPutC(ofh,0);

   if(argarray[AREA])
   {
      FPrintf(ofh,"AREA:%s\x0d",argarray[AREA]);
   }
   else
   {
      if(fromnode.Point)
      {
         FPrintf(ofh,"\x01FMPT %ld\x0d",fromnode.Point);
      }

      if(tonode.Point)
      {
         FPrintf(ofh,"\x01TOPT %ld\x0d",tonode.Point);
      }

      FPrintf(ofh,"\x01INTL %lu:%lu/%lu %lu:%lu/%lu\x0d",tonode.Zone,
                                                         tonode.Net,
                                                         tonode.Node,
                                                         fromnode.Zone,
                                                         fromnode.Net,
                                                         fromnode.Node);
   }

   if(!argarray[NOMSGID])
   {
      FPrintf(ofh,"\x01MSGID: %lu:%lu/%lu.%lu %08lx\x0d",
         fromnode.Zone,
         fromnode.Net,
         fromnode.Node,
         fromnode.Point,
         (dt.dat_Stamp.ds_Days%1100)*24*60*60*10+dt.dat_Stamp.ds_Minute*60*10+dt.dat_Stamp.ds_Tick/10);
   }

   if(charset)
      FPrintf(ofh,"\x01CHRS: %s\x0d",charset->chrsname);

   Flush(ofh);

   while(rlen=Read(ifh,tmpbuf,1000))
   {
      for(c=0;c<rlen;c++)
         if(tmpbuf[c]==10) tmpbuf[c]=13;

      if(charset)
         Xlat(tmpbuf,rlen,charset->xlat);

      Write(ofh,tmpbuf,rlen);
   }

   Flush(ofh);

   if(argarray[AREA])
   {
      UBYTE origin[80];

      strncpy(origin,(UBYTE *)argarray[ORIGIN],79);
      origin[79]=0;

      if(charset)
         Xlat(origin,strlen(origin),charset->xlat);

      FPrintf(ofh,"\x0d--- CrashWrite "VERSION"\x0d * Origin: %s (%s)\x0d",argarray[ORIGIN],argarray[FROMADDR]);
   }

   FPutC(ofh,0);
   FPutC(ofh,0);
   FPutC(ofh,0);

   Close(ifh);
   Close(ofh);

   SetComment(filenamebuf,"No security");

   FreeArgs(rdargs);
   exit(0);
}
