#include <CrashTick.h>
#include <crc.h>
#include <misc.h>

#include <time.h>

extern APTR mempool;

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

extern struct Config config;

short SendFile(struct Area *area,struct ConfigNode *cnode,uchar *filename,struct jbList *tick);

short AddSeenby(struct jbList *list,struct TickLine **last,struct Node4D *n4d)
{
   struct TickLine *seenby;

   if(!(seenby=AllocCleared(sizeof(struct TickLine))))
      return(FALSE);

   if(n4d->Point)
      sprintf(seenby->line,"Seenby %lu:%lu/%lu.%lu",n4d->Zone,n4d->Net,n4d->Node,n4d->Point);

   else
      sprintf(seenby->line,"Seenby %lu:%lu/%lu",n4d->Zone,n4d->Net,n4d->Node);

   jbInsertNode(list,(struct jbNode *)(*last),(struct jbNode *)seenby);
   (*last)=seenby;
   return(TRUE);
}

short AddPath(struct jbList *list,struct TickLine *last,struct Node4D *n4d)
{
   struct TickLine *path;
   uchar addr[20],timebuf[50];
   time_t t;

   if(!(path=AllocCleared(sizeof(struct TickLine))))
      return(FALSE);

   time(&t);
   strcpy(timebuf,ctime(&t));

   if(timebuf[strlen(timebuf)-1]==10)
      timebuf[strlen(timebuf)-1]=0;

   if(n4d->Point)
      sprintf(addr,"%lu:%lu/%lu.%lu",n4d->Zone,n4d->Net,n4d->Node,n4d->Point);

   else
      sprintf(addr,"%lu:%lu/%lu",n4d->Zone,n4d->Net,n4d->Node);

   sprintf(path->line,"Path %s %lu %s",addr,(ulong )t,timebuf);

   jbInsertNode(list,(struct jbNode *)last,(struct jbNode *)path);
   return(TRUE);
}

short WriteTick(struct jbList *tick,struct Area *area,uchar *realfilename)
{
   uchar areaname[100],desc[200],filename[100],fromnode[30],fullfilename[200],magic[100],origin[30],sizebuf[20];
   uchar replaces[100],linebuf[200],cmdbuf[300],flowline[200],filebasename[200];
   uchar faultbuf[100],buf[50];
   struct TickLine *tickline,*nextline,*lastpath,*lastseenby;
   struct ConfigNode *cnode;
   short res,c;
   ulong replacenum,size;
   uchar *path;
   struct Node4D from4d,seenby4d;
   struct TickNode *tn;
   short akainseenby,oldzone,oldnet,checkseenby;
   BPTR l;
   struct DateStamp ds;

   areaname[0]=0;
   desc[0]=0;
   filename[0]=0;
   magic[0]=0;
   origin[0]=0;
   fromnode[0]=0;

   for(tickline=(struct TickLine *)tick->First;tickline;tickline=tickline->Next)
   {
      jbcpos=0;

      if(jbstrcpy(linebuf,tickline->line,50))
      {
         if(stricmp(linebuf,"File")==0)
            if(!jbstrcpy(filename,tickline->line,100)) filename[0]=0;

         if(stricmp(linebuf,"Area")==0)
            if(!jbstrcpy(areaname,tickline->line,100)) areaname[0]=0;

         if(stricmp(linebuf,"Desc")==0)
         {
            if(strlen(tickline->line)>5)
               mystrncpy(desc,&tickline->line[5],200);
         }

         if(stricmp(linebuf,"From")==0)
            if(!jbstrcpy(fromnode,tickline->line,30)) fromnode[0]=0;

         if(stricmp(linebuf,"Origin")==0)
            if(!jbstrcpy(origin,tickline->line,30)) origin[0]=0;

         if(stricmp(linebuf,"Magic")==0)
            if(!jbstrcpy(magic,tickline->line,100)) magic[0]=0;
      }
   }

   strcpy(filename,FilePart(filename)); /* Just to be on the safe side */

   if(desc[0]==0)
      strcpy(desc,"No description");

   if(config.cfg_Loglevel >= 4)
   {
      printf("\n");
      LogWrite(4,TICKINFO,getString(TXT_TICK_AREA),areaname);
      LogWrite(4,TICKINFO,getString(TXT_TICK_FILE),filename);
      LogWrite(4,TICKINFO,getString(TXT_TICK_DESC),desc);
   }

   /* Replace */

   replacenum=0;

   if(config.cfg_ReplaceCommand[0]!=0 && area->Directory[0]!=0 && !(area->Flags & AREA_NOREPLACE))
   {
      for(tickline=(struct TickLine *)tick->First;tickline;tickline=tickline->Next)
      {
         jbcpos=0;

         if(jbstrcpy(linebuf,tickline->line,50))
         {
            if(stricmp(linebuf,"Replaces")==0)
            {
               if(jbstrcpy(replaces,tickline->line,100))
               {
                  if(replacenum < 5)
                  {
                     LogWrite(3,TICKINFO,getString(TXT_TICK_REPLACES),replaces);

                     strcpy(fullfilename,area->Directory);
                     AddPart(fullfilename,replaces,200);

                     MakeCommand(cmdbuf,300,config.cfg_ReplaceCommand,
                        areaname,
                        FilePart(replaces),
                        area->Directory,
                        fullfilename,
                        desc,
                        fromnode,
                        magic,
                        origin,
                        "0",
                        area->UserData);

                     LogWrite(6,DEBUG,getString(TXT_EXECUTING_COMMAND),cmdbuf);
                     res=SystemTags(cmdbuf,TAG_DONE);

                     if(res != 0)
                        LogWrite(3,TICKERR,getString(TXT_EXTERNAL_FAILED),res);

                     replacenum++;
                  }
               }
            }
         }
      }
   }

   /* Import file */

   if(area->Directory[0]!=0)
   {
      /* Create directory if missing */

      if(!(l=Lock(area->Directory,SHARED_LOCK)))
      {
         LogWrite(3,TICKINFO,getString(TXT_CREATING_DIR),area->Directory);
         l=CreateDir(area->Directory);
      }

      if(l) UnLock(l);

      strcpy(fullfilename,area->Directory);
      AddPart(fullfilename,filename,200);

      if(!MoveFile(realfilename,fullfilename))
      {
         LogWrite(1,TICKERR,getString(ERR_FAILED_TO_MOVE),realfilename,fullfilename);
         Fault(IoErr(),NULL,faultbuf,100);
         LogWrite(1,TICKERR,getString(ERR_IO_ERROR),faultbuf);
         return(TRUE);
      }

      /* Filenote */

      if(config.cfg_Flags & CFG_FILENOTE)
      {
         uchar filenotebuf[80];
         
         mystrncpy(filenotebuf,desc,79);
         SetComment(fullfilename,filenotebuf);
      }

      strcpy(flowline,fullfilename);
      path=area->Directory;

      if(config.cfg_Flags & CFG_USEFILEBASE && config.cfg_Filebase[0]!=0)
      {
         strcpy(filebasename,config.cfg_Filebase);
         AddPart(filebasename,filename,200);
         strcpy(flowline,filebasename);

         if(!CopyFile(fullfilename,filebasename))
         {
            LogWrite(1,TICKERR,getString(ERR_FAILED_TO_COPY),fullfilename,filebasename);
            Fault(IoErr(),NULL,faultbuf,100);
            LogWrite(1,TICKERR,getString(ERR_IO_ERROR),faultbuf);
            return(TRUE);
         }

         SetComment(filebasename,"Filebase");
         DateStamp(&ds);
         SetFileDate(filebasename,&ds); /* Make sure that the file date is correct for notify */
      }
   }
   else
   {
      strcpy(filebasename,config.cfg_Filebase);
      AddPart(filebasename,filename,200);
      strcpy(fullfilename,filebasename);
      strcpy(flowline,filebasename);
      path=config.cfg_Filebase;

      if(!MoveFile(realfilename,filebasename))
      {
         LogWrite(1,TICKERR,getString(ERR_FAILED_TO_MOVE),realfilename,filebasename);
         Fault(IoErr(),NULL,faultbuf,100);
         LogWrite(1,TICKERR,getString(ERR_IO_ERROR),faultbuf);
         return(TRUE);
      }

      DateStamp(&ds);
      SetFileDate(filebasename,&ds); /* Make sure that the file date is correct for notify */
      SetComment(filebasename,"Filebase");
   }

   size=jbGetSize(fullfilename);
   sprintf(sizebuf,"%ld",size);

   /* Areacommand */

   if(area->AreaCommand[0]!=0)
   {
      MakeCommand(cmdbuf,300,area->AreaCommand,
         areaname,
         filename,
         path,
         fullfilename,
         desc,
         fromnode,
         magic,
         origin,
         sizebuf,
         area->UserData);

      LogWrite(6,DEBUG,getString(TXT_EXECUTING_COMMAND),cmdbuf);
      res=SystemTags(cmdbuf,TAG_DONE);

      if(res != 0)
         LogWrite(3,TICKERR,getString(TXT_EXTERNAL_FAILED),res);
   }

   /* Importcommand */

   if(config.cfg_ImportCommand[0]!=0 && area->Directory[0]!=0)
   {
      strcpy(fullfilename,area->Directory);
      AddPart(fullfilename,filename,200);

      MakeCommand(cmdbuf,300,config.cfg_ImportCommand,
         areaname,
         filename,
         area->Directory,
         fullfilename,
         desc,
         fromnode,
         magic,
         origin,
         sizebuf,
         area->UserData);

      LogWrite(6,DEBUG,getString(TXT_EXECUTING_COMMAND),cmdbuf);
      res=SystemTags(cmdbuf,TAG_DONE);

      if(res != 0)
         LogWrite(3,TICKERR,getString(TXT_EXTERNAL_FAILED),res);
   }

   /* Magic command */

   if(config.cfg_MagicCommand[0]!=0 && area->Directory[0]!=0)
   {
      uchar magictmp[50];

      for(tickline=(struct TickLine *)tick->First;tickline;tickline=tickline->Next)
      {
         jbcpos=0;

         if(jbstrcpy(linebuf,tickline->line,50))
         {
            if(stricmp(linebuf,"Magic")==0)
            {
               if(jbstrcpy(magictmp,tickline->line,100))
               {
                  strcpy(fullfilename,area->Directory);
                  AddPart(fullfilename,filename,200);

                  MakeCommand(cmdbuf,300,config.cfg_MagicCommand,
                     areaname,
                     filename,
                     area->Directory,
                     fullfilename,
                     desc,
                     fromnode,
                     magictmp,
                     origin,
                     sizebuf,
                     area->UserData);

                  LogWrite(6,DEBUG,getString(TXT_EXECUTING_COMMAND),cmdbuf);
                  res=SystemTags(cmdbuf,TAG_DONE);

                  if(res != 0)
                     LogWrite(3,TICKERR,getString(TXT_EXTERNAL_FAILED),res);
               }
            }
         }
      }
   }

   /* Strip some fields */

   tickline=(struct TickLine *)tick->First;

   while(tickline)
   {
      nextline=tickline->Next;

      jbcpos=0;

      if(jbstrcpy(linebuf,tickline->line,50))
      {
         if(stricmp(linebuf,"To")==0)
            jbFreeNode(tick,(struct jbNode *)tickline,sizeof(struct TickLine));

         else if(stricmp(linebuf,"From")==0)
            jbFreeNode(tick,(struct jbNode *)tickline,sizeof(struct TickLine));

         else if(stricmp(linebuf,"Pw")==0)
            jbFreeNode(tick,(struct jbNode *)tickline,sizeof(struct TickLine));

         else if(stricmp(linebuf,"Created")==0)
            jbFreeNode(tick,(struct jbNode *)tickline,sizeof(struct TickLine));
      }

      tickline=nextline;
   }

   /* Find last seenby and path */

   lastseenby=NULL;
   lastpath=NULL;

   for(tickline=(struct TickLine *)tick->First;tickline;tickline=tickline->Next)
   {
      jbcpos=0;

      if(jbstrcpy(buf,tickline->line,50))
      {
         if(stricmp(buf,"Seenby")==0)
            lastseenby=tickline;

         if(stricmp(buf,"Path")==0)
            lastpath=tickline;
      }
   }

   /* Check seenby */

   for(tn=(struct TickNode *)area->TickNodes.First;tn;tn=tn->Next)
      tn->ConfigNode->IsInSeenBy=FALSE;

   akainseenby=FALSE;

   for(tickline=(struct TickLine *)tick->First;tickline;tickline=tickline->Next)
   {
      jbcpos=0;
      oldzone=0;
      oldnet=0;

      if(jbstrcpy(buf,tickline->line,50))
      {
         if(stricmp(buf,"Seenby")==0)
         {
            while(jbstrcpy(buf,tickline->line,50))
            {
               for(c=0;buf[c]!=0;c++)
                  if(buf[c]=='@') buf[c]=0;

               if(Parse4D(buf,&seenby4d))
               {
                  if(seenby4d.Zone == 0)
                     seenby4d.Zone=oldzone;

                  if(seenby4d.Net == 0)
                     seenby4d.Net=oldnet;

                  for(tn=(struct TickNode *)area->TickNodes.First;tn;tn=tn->Next)
                     if(Compare4D(&seenby4d,&tn->ConfigNode->Node)==0) tn->ConfigNode->IsInSeenBy=TRUE;

                  if(Compare4D(&seenby4d,&area->Aka->Node)==0)
                     akainseenby=TRUE;

                  oldzone=seenby4d.Zone;
                  oldnet=seenby4d.Net;
               }
            }
         }
      }
   }

   /* Add seenby */

   if(!lastseenby)
      lastseenby=(struct TickLine *)tick->Last;

   if(!akainseenby)
   {
      if(!AddSeenby(tick,&lastseenby,&area->Aka->Node))
      {
         LogWrite(1,SYSTEMERR,getString(ERR_OUT_OF_MEMORY));
         return(FALSE);
      }
   }

   for(tn=(struct TickNode *)area->TickNodes.First;tn;tn=tn->Next)
      if(!tn->ConfigNode->IsInSeenBy)
      {
         if(!AddSeenby(tick,&lastseenby,&tn->ConfigNode->Node))
         {
            LogWrite(1,SYSTEMERR,getString(ERR_OUT_OF_MEMORY));
            return(FALSE);
         }
      }

   /* Add path */

   if(!lastpath)
      lastpath=(struct TickLine *)tick->Last;

   if(!AddPath(tick,lastpath,&area->Aka->Node))
   {
      LogWrite(1,SYSTEMERR,getString(ERR_OUT_OF_MEMORY));
      return(FALSE);
   }

   /* Write to all nodes */

   strcpy(buf,fromnode);

   for(c=0;buf[c]!=0;c++)
      if(buf[c]=='@') buf[c]=0;

   Parse4D(buf,&from4d); /* already checked */

   /* Lite stats */

   for(cnode=(struct ConfigNode *)config.CNodeList.First;cnode;cnode=cnode->Next)
      if(Compare4D(&cnode->Node,&from4d)==0)
      {
         cnode->GotFiles++;
         cnode->GotBytes+=size;
      }

   area->NewFiles++;
   area->NewBytes+=size;

   checkseenby=FALSE;

   if(config.cfg_Flags & CFG_CHECKSEENBY)
      checkseenby=TRUE;

   if(area->Flags & AREA_IGNORESEENBY)
      checkseenby=FALSE;

   for(tn=(struct TickNode *)area->TickNodes.First;tn;tn=tn->Next)
   {
      /* is not sender of file */
      if(Compare4D(&from4d,&tn->ConfigNode->Node)!=0)
      {
         /* is not passive */
         if(!(tn->ConfigNode->Flags & NODE_PASSIVE))
         {
            /* is not write-only */
            if(!(tn->Flags & TICKNODE_WRITEONLY))
            {
               /* is not already in seen-by */
               if(!tn->ConfigNode->IsInSeenBy || !checkseenby)
               {
                  tn->ConfigNode->SentFiles++;
                  tn->ConfigNode->SentBytes+=size;

                  if(!SendFile(area,tn->ConfigNode,flowline,tick))
                     return(FALSE);
               }
            }
         }
      }
   }

   res=AddAnnounce(area,
         areaname,
         filename,
         area->Directory,
         fullfilename,
         desc,
         fromnode,
         magic,
         origin,
         sizebuf);

   if(!res)
   {
      LogWrite(1,SYSTEMERR,getString(ERR_OUT_OF_MEMORY));
      return(FALSE);
   }

   printf("\n");
   return(TRUE);
}

short rawAddFlow(uchar *flow,uchar *line)
{
   BPTR fh;

   if(!(fh=Open(flow,MODE_READWRITE)))
   {
      LogWrite(1,TICKERR,getString(ERR_UNABLE_TO_ADD_FLOW),flow);
      return(FALSE);
   }
/*
   while(FGets(fh,buf,299) && buf[0]!=0)
   {
      if(buf[strlen(buf)-1]==10)
         buf[strlen(buf)-1]=0;

      if(stricmp(buf,line)==0)
      {
         Close(fh);
         return(TRUE);
      }
   }
*/
   Seek(fh,0,OFFSET_END);
   FPrintf(fh,"%s\n",line);
   Close(fh);
   return(TRUE);
}

void AddFlow(uchar *file,struct ConfigNode *cnode,int delaftersent)
{
   uchar buf[100],*ext;
   uchar flowname[200],addline[200],dolaterbuf[200];

   switch(cnode->Pri)
   {
      case PRI_HOLD:
         ext="hlo";
         break;

      case PRI_CRASH:
         ext="clo";
         break;

      case PRI_DIRECT:
         ext="dlo";
         break;

      default:
         ext="flo";
         break;
   }

   sprintf(buf,"%lu.%lu.%lu.%lu.%s",
      cnode->Node.Zone,
      cnode->Node.Net,
      cnode->Node.Node,
      cnode->Node.Point,
      ext);

   strcpy(flowname,config.cfg_Outbound);
   AddPart(flowname,buf,200);

   if(delaftersent)
      sprintf(addline,"-%s",file);

   else
      sprintf(addline,"%s",file);

   if(rawAddFlow(flowname,addline))
   {
      return;
   }

   sprintf(dolaterbuf,"Addflow %s %s",flowname,addline);
   WriteDoLater(dolaterbuf);
}

short rawPackFile(uchar *file,struct ConfigNode *cnode)
{
   uchar buf[100],*ext,*packer;
   uchar flowname[200],cmdbuf[300],temparcname[200];
   ulong num;
   short stop,arcres;
   BPTR fh;
   struct DateStamp ds;
   BPTR l;
   short creatednew;
   
   creatednew=FALSE;
   
   if(cnode->Packer == PACKER_NONE)
   {
      LogWrite(1,TICKERR,getString(ERR_NO_PACKER),
         file,
         cnode->Node.Zone,
         cnode->Node.Net,
         cnode->Node.Node,
         cnode->Node.Point);

      return(FALSE);
   }

   if(cnode->Packer == PACKER_ZIP) packer="ZIP";
   if(cnode->Packer == PACKER_LHA) packer="LHA";

   switch(cnode->Pri)
   {
      case PRI_HOLD:
         ext="hlo";
         break;

      case PRI_CRASH:
         ext="clo";
         break;

      case PRI_DIRECT:
         ext="dlo";
         break;

      default:
         ext="flo";
         break;
   }

   if(cnode->ArchiveName[0]==0)
   {
      sprintf(buf,"%lu.%lu.%lu.%lu.%s",
         cnode->Node.Zone,
         cnode->Node.Net,
         cnode->Node.Node,
         cnode->Node.Point,
         ext);

      strcpy(flowname,config.cfg_Outbound);
      AddPart(flowname,buf,200);

      if(fh=Open(flowname,MODE_OLDFILE))
      {
         while(FGets(fh,buf,200) && buf[0])
         {
            if(buf[strlen(buf)-1]==10)
               buf[strlen(buf)-1]=0;

            if(buf[0]=='#')
               strcpy(buf,&buf[1]);

            if(buf[0]=='-')
               strcpy(buf,&buf[1]);

            if(buf[0]=='^')
               strcpy(buf,&buf[1]);

            if(cnode->Packer == PACKER_LHA)
               if(IsLick(FilePart(buf))) strcpy(cnode->ArchiveName,buf);

            if(cnode->Packer == PACKER_ZIP)
               if(IsZick(FilePart(buf))) strcpy(cnode->ArchiveName,buf);
         }

         Close(fh);
      }

      if(cnode->ArchiveName[0] == 0)
      {
         creatednew=TRUE;

         DateStamp(&ds);
         num=(ds.ds_Days*24*60*60+ds.ds_Minute*60+ds.ds_Tick/50) % 0xffffff;

         stop=FALSE;

         while(!stop)
         {
            if(cnode->Packer == PACKER_LHA)
               sprintf(buf,"tk%06lx.lic",num);

            if(cnode->Packer == PACKER_ZIP)
               sprintf(buf,"tk%06lx.zic",num);

            strcpy(cnode->ArchiveName,config.cfg_Tickdir);
            AddPart(cnode->ArchiveName,buf,100);

            l=Lock(cnode->ArchiveName,SHARED_LOCK);

            if(l || IoErr()==ERROR_OBJECT_IN_USE)
            {
               if(l) UnLock(l);
               num++;
            }
            else
            {
               stop=TRUE;
            }
         }
      }
   }

   strcpy(temparcname,cnode->ArchiveName);
   *PathPart(temparcname)=0;
   AddPart(temparcname,"CT_Temp.",150);
   strcat(temparcname,FilePart(cnode->ArchiveName));

   LogWrite(3,TICKINFO,getString(TXT_PACKING_FILE),
      file,
      cnode->Node.Zone,
      cnode->Node.Net,
      cnode->Node.Node,
      cnode->Node.Point,
      packer);

   if(cnode->Packer == PACKER_ZIP)
      ExpandPacker(cmdbuf,300,config.cfg_ZipAdd,temparcname,file);

   if(cnode->Packer == PACKER_LHA)
      ExpandPacker(cmdbuf,300,config.cfg_LhaAdd,temparcname,file);

   Rename(cnode->ArchiveName,temparcname);      
   arcres=SystemTags(cmdbuf,TAG_DONE);
   Rename(temparcname,cnode->ArchiveName);

   if(arcres != 0)
   {
      LogWrite(3,TICKERR,getString(ERR_PACKER_FAILED),arcres);
      return(FALSE);
   }

   if(creatednew)
      AddFlow(cnode->ArchiveName,cnode,TRUE);

   return(TRUE);
}

void PackFile(uchar *file,struct ConfigNode *cnode,int delafter)
{
   uchar dolaterbuf[300];

   if(rawPackFile(file,cnode))
   {
      if(delafter) DeleteFile(file);
      return;
   }

   if(delafter)
      sprintf(dolaterbuf,"Packdelete %s %lu:%lu/%lu.%lu",
         file,
         cnode->Node.Zone,
         cnode->Node.Net,
         cnode->Node.Node,
         cnode->Node.Point);

   else
      sprintf(dolaterbuf,"Pack %s %lu:%lu/%lu.%lu",
         file,
         cnode->Node.Zone,
         cnode->Node.Net,
         cnode->Node.Node,
         cnode->Node.Point);

   WriteDoLater(dolaterbuf);
}

short SendFile(struct Area *area,struct ConfigNode *cnode,uchar *filename,struct jbList *tick)
{
   uchar tickname[200];
   uchar buf[200],addr[30];
   BPTR fh,l;
   struct DateStamp ds;
   ulong num;
   struct TickLine *tickline;

   LogWrite(5,TICKINFO,getString(TXT_SENDING_FILE_TO),
      cnode->Node.Zone,
      cnode->Node.Net,
      cnode->Node.Node,
      cnode->Node.Point);

   if(!(cnode->Flags & NODE_NOTICFILES))
   {
      DateStamp(&ds);
      num=(ds.ds_Days*24*60*60+ds.ds_Minute*60+ds.ds_Tick/50)%0xffffff;

      fh=NULL;

      while(!fh)
      {
         sprintf(buf,"tk%06lx.tic",num);
         strcpy(tickname,config.cfg_Tickdir);
         AddPart(tickname,buf,200);
   
         l=Lock(tickname,SHARED_LOCK);

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

            sprintf(buf,"tk%06lx.tic",num);
            strcpy(tickname,config.cfg_Tickdir);
            AddPart(tickname,buf,200);

            l=Lock(tickname,SHARED_LOCK);
         }

         if(!(fh=Open(tickname,MODE_NEWFILE)))
         {
            if(IoErr()==ERROR_OBJECT_IN_USE)
            {
               num++;
            }
            else
            {
               LogWrite(1,TICKERR,getString(ERR_FAILED_OPEN_WRITE),tickname);
               return(FALSE);
            }
         }
      }

      FPrintf(fh,"Created by CrashTick "VERSION" (c) Johan Billing\x0d\x0a");

      if(area->Aka->Node.Point)
      {
         sprintf(addr,"%lu:%lu/%lu.%lu",
            area->Aka->Node.Zone,
            area->Aka->Node.Net,
            area->Aka->Node.Node,
            area->Aka->Node.Point);
      }
      else
      {
         sprintf(addr,"%lu:%lu/%lu",
            area->Aka->Node.Zone,
            area->Aka->Node.Net,
            area->Aka->Node.Node);
      }

      FPrintf(fh,"From %s\x0d\x0a",addr);

      for(tickline=(struct TickLine *)tick->First;tickline;tickline=tickline->Next)
         if(tickline->line[0]!=0)
         {
            if(strnicmp(tickline->line,"Seenby",6)==0)
            {
               if(!(cnode->Flags & NODE_TINYSEENBY))
                  FPrintf(fh,"%s\x0d\x0a",tickline->line);
            }
            else
            {
               FPrintf(fh,"%s\x0d\x0a",tickline->line);
            }
         }

      if(cnode->Flags & NODE_TINYSEENBY)
      {
         FPrintf(fh,"Seenby %s\x0d\x0a",addr);

         if(cnode->Node.Point)
            FPrintf(fh,"Seenby %lu:%lu/%lu.%lu\x0d\x0a",
               cnode->Node.Zone,
               cnode->Node.Net,
               cnode->Node.Node,
               cnode->Node.Point);

         else
            FPrintf(fh,"Seenby %lu:%lu/%lu\x0d\x0a",
               cnode->Node.Zone,
               cnode->Node.Net,
               cnode->Node.Node);
      }

      if(cnode->TickPW[0])
         FPrintf(fh,"Pw %s\x0d\x0a",cnode->TickPW);

      Close(fh);

      sprintf(buf,"File %s to %lu:%lu/%lu.%lu",
         FilePart(filename),
         cnode->Node.Zone,
         cnode->Node.Net,
         cnode->Node.Node,
         cnode->Node.Point);

      SetComment(tickname,buf);
   }

   /* Send file */

   if(cnode->Packmode == PACKMODE_PACKALL)
      PackFile(filename,cnode,FALSE);

   else
      AddFlow(filename,cnode,FALSE);

   /* Send tick file */

   if(!(cnode->Flags & NODE_NOTICFILES))
   {
      if(cnode->Packmode == PACKMODE_PACKALL || cnode->Packmode == PACKMODE_PACKTIC)
         PackFile(tickname,cnode,TRUE);

      else
         AddFlow(tickname,cnode,TRUE);

      return(TRUE);
   }
}
