#include <CrashMail.h>

BOOL UMSDateToStamp(UBYTE *M,struct DateStamp *ds);
BOOL FidoToStamp(UBYTE *date,struct DateStamp *ds);

UBYTE UMS_DomainAddress[100];
ULONG UMS_Version;

void MSGID_FidoToRfc(UBYTE *src,UBYTE *dest,ULONG defaultzone,UBYTE *fido4dtxt);
void MSGID_RfcToFido(UBYTE *src,UBYTE *dest);

ULONG UMS_MsgidConvertCache_Zone;
UBYTE UMS_MsgidConvertCache_Domain[100];

ULONG copymemcr(UBYTE *src,UBYTE *dest,ULONG len);

void MausifyAddress(UBYTE *addr,UBYTE *mausname,UBYTE *mausaddr);
void UnMausifyAddress(UBYTE *name,UBYTE *addr);
void makemailname(char *dest,char *name,char *addr);

struct jbList UMSAddrMapList;

struct UMSAddrMap
{
   struct UMSAddrMap *Next;
   UBYTE ParsedPattern[402];
   struct Node4D FidoAddr;
   UBYTE Address[100];
};

void UMSStart(void)
{
   UBYTE *var,*str;
   UBYTE buf[200];
   struct UMSAddrMap addrmap,*addrmapptr;
   ULONG line;
   
   jbNewList(&UMSAddrMapList);

   if(!(UMSBase=(struct Library *)OpenLibrary(UMSNAME,11)))
   {
      LogWrite(1,SYSTEMERR,"Unable to open %s %ld or higher\n",(long)UMSNAME,11);
      exitprg=TRUE;
      CleanUp();
   }

   UMS_Version=UMSBase->lib_Version;

   if(!(UMSHandle=(UMSUserAccount)UMSRLogin(cfg_UMSServer,cfg_UMSName,cfg_UMSPassword)))
   {
      LogWrite(1,SYSTEMERR,"Unable to login into UMS msgbase");
      exitprg=TRUE;
      CleanUp();
   }

   UMS_DomainAddress[0]=0;

   var=(UBYTE *)ReadUMSConfigTags(UMSHandle,UMSTAG_CfgGlobalOnly, 1,
                                            UMSTAG_CfgName,       "DOMAIN-ADDRESS",
                                            TAG_DONE);

   if(var)
   {
      if(var[0]=='@')
         strcpy(UMS_DomainAddress,&var[1]);

      else
         strcpy(UMS_DomainAddress,var);

      FreeUMSConfig(UMSHandle,var);
   }

   var=(UBYTE *)ReadUMSConfigTags(UMSHandle,UMSTAG_CfgGlobalOnly, 1,
                                            UMSTAG_CfgName,       "Sysname",
                                            TAG_DONE);

   if(var)
   {
      if(var[0]=='@')
         strcpy(UMS_DomainAddress,&var[1]);

      else
         strcpy(UMS_DomainAddress,var);

      FreeUMSConfig(UMSHandle,var);
   }

   var=(UBYTE *)ReadUMSConfigTags(UMSHandle,
      UMSTAG_CfgName,       "crashmail.addressmapping.outgoing",
      TAG_DONE);

   if(var)
   {
      jbcpos=0;
      str=var;
      line=0;
      
      while(jbstrcpy(buf,str,200))
      {
         line++;

         if(ParsePatternNoCase(buf,addrmap.ParsedPattern,402)==-1)
         {
            LogWrite(1,SYSTEMERR,"Invalid AmigaDOS pattern in crashmail.addressmapping.outgoing, line %ld",
               buf,line);

            exitprg=TRUE;
            CleanUp();
         }

         if(!jbstrcpy(buf,str,100))
         {
            LogWrite(1,SYSTEMERR,"Missing fidonet address in crashmail.addressmapping.outgoing, line %ld",
               line);

            exitprg=TRUE;
            CleanUp();
         }

         if(!Parse4D(buf,&addrmap.FidoAddr))
         {
            LogWrite(1,SYSTEMERR,"Invalid node number %s in crashmail.addressmapping.outgoing, line %ld",
               buf,line);

            exitprg=TRUE;
            CleanUp();
         }

         addrmap.Next=NULL;
         addrmap.Address[0]=0;

         if(!jbstrcpy(addrmap.Address,str,100))
         {
            LogWrite(1,SYSTEMERR,"Missing domain address in crashmail.addressmapping.outgoing, line %ld",
               line);

            exitprg=TRUE;
            CleanUp();
         }

         if(!(addrmapptr=(struct UMSAddrMap *)AllocMem(sizeof(struct UMSAddrMap),MEMF_ANY)))
         {
            nomem=TRUE;
            CleanUp();
         }

         CopyMem(&addrmap,addrmapptr,sizeof(struct UMSAddrMap));
         jbAddNode(&UMSAddrMapList,(struct jbNode *)addrmapptr);

         str=strchr(str,'\n');
         if(str) str++;
         jbcpos=0;
      }

      FreeUMSConfig(UMSHandle,var);
   }
}

void UMSClose(void)
{
   if(UMSHandle)  UMSLogout(UMSHandle);
   UMSHandle=NULL;

   if(UMSBase)    CloseLibrary(UMSBase);
   UMSBase=NULL;

   jbFreeList(&UMSAddrMapList,UMSAddrMapList.First,sizeof(struct UMSAddrMap));
}

UBYTE UMSTo[36],UMSFrom[36],UMSSubject[80];
UBYTE UMSFromAddr[80],UMSToAddr[80];
UBYTE UMSPID[50];
UBYTE UMSOrganization[100];
UBYTE UMSReply[200];
UBYTE UMSMsgid[200];
UBYTE UMSAttribs[80];

UBYTE UMSFileName[100];
UBYTE UMSTempFileName[100];

/* Import UMS Message */

#include <Chartabs.h>

void ImportUMS(struct Area *area)
{
   ULONG res,link,c,d,e;
   ULONG tpos,cpos,pos;
   UBYTE *Text,*Comments,*umserrbuf;
   ULONG TotalLength=0,msgiddefzone;
   UBYTE buf[40],fido4dtxt[30];
   struct Node4D n4d;
   struct TextChunk *chunk;
   APTR chrs;
   struct Aka *aka;
   BOOL done,kludge;
   ULONG UMSCDate;
   struct DateStamp ds;
   UBYTE charset[20];
   UBYTE *umsgroup,*umsfolder;
   struct Node5D Origin5D,n5d;
   struct UMSAddrMap *addrmap;

   /* Get umsgroup and umsfolder */

   if(stricmp(area->Path,"Mail")==0)
   {
      umsgroup=NULL;
      umsfolder=NULL;
   }
   else if(strnicmp(area->Path,"Mail:",5)==0)
   {
      umsgroup=NULL;
      umsfolder=&area->Path[5];
   }
   else
   {
      umsgroup=area->Path;
      umsfolder=NULL;
   }

   UMSPID[0]=0;
   UMSFrom[0]=0;
   UMSFromAddr[0]=0;
   UMSOrganization[0]=0;
   UMSMsgid[0]=0;
   UMSReply[0]=0;
   UMSAttribs[0]=0;
   UMSTo[0]=0;
   UMSToAddr[0]=0;

   charset[0]=0;

   Origin5D.Zone=0;

   /* Convert body text */

   for(chunk=MemMessage.TextChunks.First;chunk;chunk=chunk->Next)
      TotalLength+=chunk->Length;

   TotalLength++; /* NULL character */
   TotalLength+=strlen(MemMessage.BadReason);

   if(!(Comments=(UBYTE *)AllocMem(6000,MEMF_ANY)))
   {
      nomem=TRUE;
      return;
   }

   if(!(Text=(UBYTE *)AllocMem(TotalLength,MEMF_ANY)))
   {
      nomem=TRUE;
      FreeMem(Comments,6000);
      return;
   }

   chunk=MemMessage.TextChunks.First;

   Comments[0]=0;
   Text[0]=0;

   strcpy(Comments,"Fido/CrashMail\n");

   if(MemMessage.BadReason[0]!=0)
      copymemcr(MemMessage.BadReason,Text,strlen(MemMessage.BadReason)+1);

   cpos=strlen(Comments);
   tpos=strlen(Text);
   pos=0;

   for(chunk=(struct TextChunk *)MemMessage.TextChunks.First;chunk;chunk=chunk->Next)
   {
      c=0;

      while(c<chunk->Length)
      {
         while(c<chunk->Length && chunk->Data[c]==10) c++;   /* Skip LF */

         d=c;

         while(d<chunk->Length && chunk->Data[d]!=13) d++;   /* Find CR */
         if(d<chunk->Length && chunk->Data[d]==13)    d++;   /* Skip CR */

         if(d!=c)
         {
            kludge=FALSE;

            if(chunk->Data[c] == 1)
               kludge=TRUE;

            if(strncmp(&chunk->Data[c],"\x01PID: ",6)==0)
            {
               if(d-c-7 < 50)
               {
                  strncpy(UMSPID,&chunk->Data[c+6],d-c-7);
                  UMSPID[d-c-7]=0;
               }
            }

            if(strncmp(&chunk->Data[c],"\x01CHRS: ", 7)==0)
            {
               if(d-c-8 < 20)
               {
                  strncpy(charset,&chunk->Data[c+7],d-c-8);
                  charset[d-c-8]=0;
               }
            }

            if(strncmp(&chunk->Data[c],"\x01CHARSET: ", 10)==0)
            {
               if(d-c-11 < 20)
               {
                  strncpy(charset,&chunk->Data[c+10],d-c-11);
                  charset[d-c-11]=0;
               }
            }

            if(strncmp(&chunk->Data[c],"\x01REPLYADDR ",11)==0)
            {
               char replyaddrbuf[80],linebuf[80];

               if(d-c-12 < 80)
               {
                  strncpy(linebuf,&chunk->Data[c+11],d-c-12);
                  linebuf[d-c-12]=0;

                  jbcpos=0;
                  UMSFromAddr[0]=0;

                  while(UMSFromAddr[0]==0 && jbstrcpy(replyaddrbuf,linebuf,79))
                  {
                     if(replyaddrbuf[0]=='<' && replyaddrbuf[strlen(replyaddrbuf)-1]=='>')
                     {
                        replyaddrbuf[strlen(replyaddrbuf)-1]=0;
                        strcpy(UMSFromAddr,&replyaddrbuf[1]);
                     }
                  }


                  if(UMSFromAddr[0]==0)
                  {
                     jbcpos=0;
                     jbstrcpy(UMSFromAddr,linebuf,79);
                  }

                  if(cfg_Flags & CFG_UMSMAUSGATE)
                     MausifyAddress(UMSFromAddr,UMSFrom,UMSFromAddr);

LogWrite(6,DEBUG,"REPLYADDR FromAddr: %s",UMSFromAddr);
               }
            }

            if(strncmp(&chunk->Data[c],"--- ",4)==0 || strncmp(&chunk->Data[c],"---\x0d",4)==0)
            {
               if(chunk->Data[c+3] == 32 && d-c-4 < 49 && UMSPID[0] == 0)
               {
                  strncpy(UMSPID,&chunk->Data[c+4],d-c-4);
                  UMSPID[d-c-4]=0;
               }

               if(!(cfg_Flags & CFG_UMSKEEPORIGIN))
                  kludge=TRUE;
            }

            if(strncmp(&chunk->Data[c]," * Origin: ",11)==0 && !(area->Flags & AREA_NETMAIL))
            {
               ULONG pos,orgend;

               pos=d-2;

               while(pos>c && chunk->Data[pos]!='(') pos--;
                  /* Find address */

               if(c==pos)
               {
                  orgend=d-1;
               }
               else
               {
                  UBYTE origbuf[60];

                  orgend=pos-1;
                  pos++;

                  while(chunk->Data[pos]!=10 && (chunk->Data[pos]<'0' || chunk->Data[pos]>'9')) pos++;
                     /* (FidoNet ... ) */

                  e=0;
                  while(chunk->Data[pos]!=')' && e<50) origbuf[e++]=chunk->Data[pos++];
                  origbuf[e]=0;

                  Parse5D(origbuf,&Origin5D);

                  if(Origin5D.Domain[0]==0) strcpy(Origin5D.Domain,area->Aka->Domain);
                  if(Origin5D.Zone == 0)    Origin5D.Zone=PktOrig.Zone;

                  if(cfg_Flags & CFG_UMSIGNOREORIGINDOMAIN)
                     strcpy(Origin5D.Domain,area->Aka->Domain);

                  if(UMSFromAddr[0]==0)
                  {
                     if(Origin5D.Point == 0)
                        sprintf(UMSFromAddr,"%lu:%lu/%lu@%s",Origin5D.Zone,Origin5D.Net,Origin5D.Node,Origin5D.Domain);

                     else
                        sprintf(UMSFromAddr,"%lu:%lu/%lu.%lu@%s",Origin5D.Zone,Origin5D.Net,Origin5D.Node,Origin5D.Point,Origin5D.Domain);

LogWrite(6,DEBUG,"ORIGIN FromAddr: %s",UMSFromAddr);
                  }
               }

               e=0;
               pos=c+11;

               while(pos<orgend && e<100) UMSOrganization[e++]=chunk->Data[pos++];
               UMSOrganization[e]=0;

               if(!(cfg_Flags & CFG_UMSKEEPORIGIN))
                  kludge=TRUE;
            }

            if(kludge)
            {
               if(cpos + d-c + 1 < 6000)
               {
                  if(chunk->Data[c] == 1)
                  {
                     Comments[cpos++]='^';
                     Comments[cpos++]='A';
                     c++;
                  }

                  cpos+=copymemcr(&chunk->Data[c],&Comments[cpos],d-c);
               }
            }
            else
            {
               tpos+=copymemcr(&chunk->Data[c],&Text[tpos],d-c);
            }

            c=d;
         }
      }
   }

   Comments[cpos]=0;
   Text[tpos]=0;

   if(cfg_Flags & CFG_IMPORTSEENBY)
      WriteSeenbyBuf(Comments,&MemMessage.SeenBy,6000);

   WritePathBuf(Comments,&MemMessage.Path,6000);

   /* Convert main header fields like from, to and subject */

LogWrite(6,DEBUG,"OrigNode %ld:%ld/%ld.%ld",
   MemMessage.OrigNode.Zone,
   MemMessage.OrigNode.Net,
   MemMessage.OrigNode.Node,
   MemMessage.OrigNode.Point);

   if(UMSFromAddr[0]==0)
   {
      UBYTE *domain;
      struct Aka *tmpaka;

LogWrite(6,DEBUG,"Ingen FromAddr redan");

      if(area->Flags & AREA_NETMAIL) /* Netmail */
      {
         tmpaka=GetRouteAka(&MemMessage.OrigNode);

         if(tmpaka)
            domain=tmpaka->Domain;

         else
            domain="fidonet";
      }
      else
      {
         domain=area->Aka->Domain;
      }

      if(MemMessage.OrigNode.Point == 0)
         sprintf(UMSFromAddr,"%lu:%lu/%lu@%s",MemMessage.OrigNode.Zone,MemMessage.OrigNode.Net,MemMessage.OrigNode.Node,domain);

      else
         sprintf(UMSFromAddr,"%lu:%lu/%lu.%lu@%s",MemMessage.OrigNode.Zone,MemMessage.OrigNode.Net,MemMessage.OrigNode.Node,MemMessage.OrigNode.Point,domain);

LogWrite(6,DEBUG,"Set FromAddr: %s",UMSFromAddr);
   }

   strcpy(UMSTo,MemMessage.To);
   if(UMSTo[0]==0) strcpy(UMSTo," ");

   if(UMSFrom[0]==0)
   {
      strcpy(UMSFrom,MemMessage.From);
      if(UMSFrom[0]==0) strcpy(UMSFrom," ");
   }

   strcpy(UMSSubject,MemMessage.Subject);
   if(UMSSubject[0]==0) strcpy(UMSSubject," ");

   /* Convert MSGID:s */

   if(area->Flags & AREA_NETMAIL)
   {
      sprintf(fido4dtxt,"%lu:%lu/%lu.%lu",
         MemMessage.OrigNode.Zone,
         MemMessage.OrigNode.Net,
         MemMessage.OrigNode.Node,
         MemMessage.OrigNode.Point);

      msgiddefzone=MemMessage.OrigNode.Zone;
   }
   else
   {
      sprintf(fido4dtxt,"%lu:%lu/%lu.%lu",
         Origin5D.Zone,
         Origin5D.Net,
         Origin5D.Node,
         Origin5D.Point);

      msgiddefzone=Origin5D.Zone;
   }

   if(msgiddefzone == 0)
      msgiddefzone=area->Aka->Node.Zone;

   MSGID_FidoToRfc(MemMessage.MSGID,UMSMsgid,msgiddefzone,fido4dtxt);

   if(MemMessage.REPLY[0])
      MSGID_FidoToRfc(MemMessage.REPLY,UMSReply,msgiddefzone,fido4dtxt);

   /* Convert back REPLY to domain-address */

   if(MemMessage.REPLY[0]!=0 && (cfg_Flags & CFG_CHANGEUMSMSGID))
   {
      jbcpos=0;
      jbstrcpy(buf,MemMessage.REPLY,40);

      if(Parse4D(buf,&n4d))
      {
         for(aka=AkaList.First;aka;aka=aka->Next)
            if(Compare4D(&n4d,&aka->Node)==0) break;

         if(aka)
         {
            jbstrcpy(buf,MemMessage.REPLY,40);
            sprintf(UMSReply,"%s@%s",buf,UMS_DomainAddress);
         }
      }
   }

   /* Attributes */

   if(MemMessage.Attr & CRASH)
   {
      if(UMSAttribs[0]!=0) strcat(UMSAttribs," ");
      strcat(UMSAttribs,"crash");
   }

   if(MemMessage.Attr & FILEATTACH)
   {
      if(UMSAttribs[0]!=0) strcat(UMSAttribs," ");
      strcat(UMSAttribs,"file-attach");
   }

   if(MemMessage.Attr & RREQ)
   {
      if(UMSAttribs[0]!=0) strcat(UMSAttribs," ");
      strcat(UMSAttribs,"receipt-request");
   }

   if(MemMessage.Attr & IRRR)
   {
      if(UMSAttribs[0]!=0) strcat(UMSAttribs," ");
      strcat(UMSAttribs,"receipt");
   }

   if(MemMessage.Attr & HOLD)
   {
      if(UMSAttribs[0]!=0) strcat(UMSAttribs," ");
      strcat(UMSAttribs,"hold");
   }

   if(MemMessage.Attr & AUDIT)
   {
      if(UMSAttribs[0]!=0) strcat(UMSAttribs," ");
      strcat(UMSAttribs,"audit-request");
   }

   chrs=(UBYTE *)GetCharset(charset,area->DefaultCHRS);

   Xlat(UMSTo,chrs,strlen(UMSTo));
   Xlat(UMSFrom,chrs,strlen(UMSFrom));
   Xlat(UMSSubject,chrs,strlen(UMSSubject));
   Xlat(Text,chrs,strlen(Text));
   Xlat(Comments,chrs,strlen(Comments));
   Xlat(UMSOrganization,chrs,strlen(UMSOrganization));

   UMSCDate=0;

   if(FidoToStamp(MemMessage.DateTime,&ds))
      UMSCDate=ds.ds_Days*86400+ds.ds_Minute*60+ds.ds_Tick/50;

   if(area->Flags & AREA_BAD)
   {
      UMSMsgid[0]=0;
      UMSReply[0]=0;
   }

   if((area->Flags & AREA_NETMAIL) && cfg_UMSGatewayName[0] && stricmp(UMSTo,cfg_UMSGatewayName)==0)
   {
      UBYTE address[100];
      ULONG c,d;

      c=0;
      d=0;

      /* Skip empty lines */

      while(Text[c] == 10) c++;

      /* Copy first line */

      while(Text[c]!=0 && Text[c]!=10 && d!=99)
         address[d++]=Text[c++];

      address[d]=0;

      /* Did we find an address? */

      UMSTo[0]=0;

      if(strnicmp(address,"To:",3)==0)
      {
         /* Remove To: */

         d=3;

         while(address[d]==' ')
            d++;

         strcpy(address,&address[d]);

         /* Make this new UMSTo */

         makemailname(address,UMSTo,UMSToAddr);

         /* Mausify? */

         if(cfg_Flags & CFG_UMSMAUSGATE)
            MausifyAddress(UMSToAddr,UMSTo,UMSToAddr);

         /* Skip empty lines */

         while(Text[c] == 10)
            c++;

         /* Copy buffer */

         strcpy(Text,&Text[c]);
      }


      if(UMSTo[0]==0)
      {
         LogWrite(3,TOSSINGERR,"Bounced message from %lu:%lu/%lu.%lu to UMS gateway -- no destination specified",
            MemMessage.OrigNode.Zone,MemMessage.OrigNode.Net,MemMessage.OrigNode.Node,MemMessage.OrigNode.Point);

         sprintf(MemMessage.BadReason,"Warning! Your message to the gateway has been bounced because no\x0d"
                                      "To: line with a new destination address was specified.\x0d\x0d");
         Bounce();
         return;
      }

      LogWrite(5,TOSSINGINFO,"Gating mail to \"%s, %s\"",UMSTo,UMSToAddr);
   }

   done=FALSE;

   /* Start converting FromAddr according to crashmail.addressmapping.outgoing */

   if(Parse5D(UMSFromAddr,&n5d) && n5d.Zone!=0 && n5d.Net!=0)
   {
      /* Only convert Fidonet addresses */

      n4d.Zone=n5d.Zone;
      n4d.Net=n5d.Net;
      n4d.Node=n5d.Node;
      n4d.Point=n5d.Point;

      for(addrmap=UMSAddrMapList.First;addrmap;addrmap=addrmap->Next)
         if(Compare4D(&addrmap->FidoAddr,&n4d)==0 && MatchPatternNoCase(addrmap->ParsedPattern,area->Path)) break;

      if(addrmap)
      {
         /* Found statement for this address */

         if(strchr(addrmap->Address,'@'))
         {
            /* Already a complete address */

            mystrncpy(UMSFromAddr,addrmap->Address,79);
         }
         else
         {
            int c;

            strcpy(UMSFromAddr,UMSFrom);

            for(c=0;UMSFromAddr[c];c++)
               if(UMSFromAddr[c]==' ') UMSFromAddr[c]='_';

            strcat(UMSFromAddr,"@");

            strncat(UMSFromAddr,addrmap->Address,79);
            UMSFromAddr[79]=0;
         }
      }
   }

LogWrite(6,DEBUG,"Write FromAddr: %s",UMSFromAddr);

   if((MemMessage.Attr & FILEATTACH) && UMS_Version >=11)
   {
      UBYTE firstfile[100];
      UBYTE c;

      c=0;

      while(MemMessage.Subject[c]!=0 && MemMessage.Subject[c]!=32)
      {
         firstfile[c]=MemMessage.Subject[c];
         c++;
      }

      firstfile[c]=0;

      strcpy(UMSFileName,FilePart(firstfile));

      strcpy(UMSTempFileName,cfg_Inbound);
      AddPart(UMSTempFileName,firstfile,190);

      res = WriteUMSMsgTags(UMSHandle,UMSTAG_WMsgText,       Text,
                                      UMSTAG_WComments,      Comments,
                                      UMSTAG_WFromName,      UMSFrom,
                                      UMSTAG_WFromAddr,      UMSFromAddr,
                                      UMSTAG_WNewsreader,    UMSPID,
                                      UMSTAG_WOrganization,  UMSOrganization,
                                      UMSTAG_WToName,        UMSTo,
                                      UMSTAG_WToAddr,        UMSToAddr,
                                      UMSTAG_WCreationDate,  MemMessage.DateTime,
                                      UMSTAG_WMsgCDate,      UMSCDate,
                                      UMSTAG_WGroup,         umsgroup,
                                      UMSTAG_WFolder,        umsfolder,
                                      UMSTAG_WSubject,       UMSSubject,
                                      UMSTAG_WMsgID,         UMSMsgid,
                                      UMSTAG_WReferID,       UMSReply,
                                      UMSTAG_WFidoID,        MemMessage.MSGID,
                                      UMSTAG_WAttributes,    UMSAttribs,
                                      UMSTAG_WFileName,      UMSFileName,
                                      UMSTAG_WTempFileName,  UMSTempFileName,
                                      TAG_END);

      if(!res)
      {
         LogWrite(1,TOSSINGINFO,"Failed writing UMS V11 file-attach, using old style...");
         LogWrite(1,TOSSINGINFO,"UMS-error: %s",UMSErrTxt(UMSHandle));
      }
      else
      {
         DeleteFile(UMSTempFileName);
         done=TRUE;
      }
   }

   if(!done)
   {
      res = WriteUMSMsgTags(UMSHandle,UMSTAG_WMsgText,       Text,
                                      UMSTAG_WComments,      Comments,
                                      UMSTAG_WFromName,      UMSFrom,
                                      UMSTAG_WFromAddr,      UMSFromAddr,
                                      UMSTAG_WNewsreader,    UMSPID,
                                      UMSTAG_WOrganization,  UMSOrganization,
                                      UMSTAG_WToName,        UMSTo,
                                      UMSTAG_WToAddr,        UMSToAddr,
                                      UMSTAG_WCreationDate,  MemMessage.DateTime,
                                      UMSTAG_WMsgCDate,      UMSCDate,
                                      UMSTAG_WGroup,         umsgroup,
                                      UMSTAG_WFolder,        umsfolder,
                                      UMSTAG_WSubject,       UMSSubject,
                                      UMSTAG_WMsgID,         UMSMsgid,
                                      UMSTAG_WReferID,       UMSReply,
                                      UMSTAG_WFidoID,        MemMessage.MSGID,
                                      UMSTAG_WAttributes,    UMSAttribs,
                                      TAG_END);
   }

   if(!res)
   {
      link=0;

      umserrbuf=UMSErrTxt(UMSHandle);

      if(UMSErrNum(UMSHandle)==UMSERR_Dupe)
      {
         if(area->Flags & AREA_NETMAIL)
         {
            link=FindLink(UMSMsgid,NULL);

            if(link)
            {
               res = WriteUMSMsgTags(UMSHandle,UMSTAG_WMsgText,       Text,
                                               UMSTAG_WComments,      Comments,
                                               UMSTAG_WFromName,      UMSFrom,
                                               UMSTAG_WFromAddr,      UMSFromAddr,
                                               UMSTAG_WNewsreader,    UMSPID,
                                               UMSTAG_WOrganization,  UMSOrganization,
                                               UMSTAG_WToName,        UMSTo,
                                               UMSTAG_WToAddr,        UMSToAddr,
                                               UMSTAG_WCreationDate,  MemMessage.DateTime,
                                               UMSTAG_WMsgCDate,      UMSCDate,
                                               UMSTAG_WGroup,         umsgroup,
                                               UMSTAG_WFolder,        umsfolder,
                                               UMSTAG_WSubject,       UMSSubject,
                                               UMSTAG_WMsgID,         UMSMsgid,
                                               UMSTAG_WReferID,       UMSReply,
                                               UMSTAG_WFidoID,        MemMessage.MSGID,
                                               UMSTAG_WAttributes,    UMSAttribs,
                                               UMSTAG_WSoftLink,      link,
                                               TAG_END);

               if(!res)
                  umserrbuf=UMSErrTxt(UMSHandle);
            }
         }
         else
         {
            link=FindLink(UMSMsgid,umsgroup);

            if(link)
            {
               res = WriteUMSMsgTags(UMSHandle,UMSTAG_WMsgText,       Text,
                                               UMSTAG_WComments,      Comments,
                                               UMSTAG_WFromName,      UMSFrom,
                                               UMSTAG_WFromAddr,      UMSFromAddr,
                                               UMSTAG_WNewsreader,    UMSPID,
                                               UMSTAG_WOrganization,  UMSOrganization,
                                               UMSTAG_WToName,        UMSTo,
                                               UMSTAG_WToAddr,        UMSToAddr,
                                               UMSTAG_WCreationDate,  MemMessage.DateTime,
                                               UMSTAG_WMsgCDate,      UMSCDate,
                                               UMSTAG_WGroup,         area->Path,
                                               UMSTAG_WSubject,       UMSSubject,
                                               UMSTAG_WMsgID,         UMSMsgid,
                                               UMSTAG_WReferID,       UMSReply,
                                               UMSTAG_WFidoID,        MemMessage.MSGID,
                                               UMSTAG_WAttributes,    UMSAttribs,
                                               UMSTAG_WHardLink,      link,
                                               TAG_END);

               if(!res)
                  umserrbuf=UMSErrTxt(UMSHandle);
            }
         }
      }

      if(!res)
      {
         if(UMSErrNum(UMSHandle)>=300)
         {
            LogWrite(1,TOSSINGERR,"Fatal UMS-error: \"%s\" Exiting...",UMSErrTxt(UMSHandle));
         }
         else
         {
            LogWrite(2,TOSSINGERR,"UMS-error: %s",umserrbuf);
         }

         LogWrite(3,TOSSINGERR,"Area: %s",area->Tagname);
         LogWrite(3,TOSSINGERR,"Message-ID: %s",UMSMsgid);

         if(UMSErrNum(UMSHandle)>=300)
         {
            exitprg=TRUE;
            return;
         }
      }
   }

   if(!(area->Flags & AREA_BAD))
      toss_import++;

   FreeMem(Comments,6000);
   FreeMem(Text,TotalLength);
}

ULONG FindLink(UBYTE *msgid,UBYTE *notarea)
{
   UBYTE *group;
   ULONG res,num,ret;

   res=UMSSelectTags(UMSHandle,UMSTAG_SelWriteLocal,TRUE,
                               UMSTAG_SelSet,       0,
                               UMSTAG_SelUnset,     UMSFLAG_FINDLINK,
                               TAG_DONE);

   res=UMSSelectTags(UMSHandle,UMSTAG_SelWriteLocal, TRUE,
                               UMSTAG_SelQuick,      TRUE,
                               UMSTAG_WMsgID,        msgid,
                               UMSTAG_SelSet,        UMSFLAG_FINDLINK,
                               UMSTAG_SelUnset,      0,
                               TAG_DONE);

   if(!res)
      return(0);

   num=0;
   ret=0;

   for(;;)
   {
      num=UMSSearchTags(UMSHandle,UMSTAG_SearchLocal, TRUE,
                                  UMSTAG_SearchLast,  num,
                                  UMSTAG_SearchMask,  UMSFLAG_FINDLINK,
                                  UMSTAG_SearchMatch, UMSFLAG_FINDLINK,
                                  TAG_DONE);

      if(!num)
         return(ret);

      res=ReadUMSMsgTags(UMSHandle,UMSTAG_RMsgNum,         num,
                                   UMSTAG_RGroup,          &group,
                                   UMSTAG_RNoUpdate,       1,
                                   TAG_DONE);

      if(res)
      {
         if(group && notarea)
            if(stricmp(group,notarea)==0)
            {
               FreeUMSMsg(UMSHandle,num);
               return(0);
            }

         ret=num;
         FreeUMSMsg(UMSHandle,num);
      }
   }
}

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

   if(!chrs) return;

   if(cfg_Flags & CFG_CODEPAGE865)
   {
      if(chrs == IbmToAmiga) chrs=IbnToAmiga;
      if(chrs == AmigaToIbm) chrs=AmigaToIbn;
      if(chrs == DefToAmiga) chrs=DfnToAmiga;
   }

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

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

void WriteSeenbyBuf(UBYTE *dest,struct jbList *list,ULONG maxlen)
{
   UWORD c;
   struct Nodes2D *nodes;
   UWORD lastnet;
   UBYTE buf[100],buf2[50],buf3[20];

   strcpy(buf,"SEEN-BY:");
   lastnet=0;

   for(nodes=list->First;nodes;nodes=nodes->Next)
   {
      for(c=0;c<nodes->Nodes;c++)
      {
         if(maxlen-strlen(dest) < 100)
            return;

         if(nodes->Net[c]!=0 && nodes->Node[c]!=0)
         {
            strcpy(buf2," ");

            if(nodes->Net[c]!=lastnet)
            {
               sprintf(buf3,"%lu/",nodes->Net[c]);
               strcat(buf2,buf3);
            }

            sprintf(buf3,"%lu",nodes->Node[c]);
            strcat(buf2,buf3);

            lastnet=nodes->Net[c];

            if(strlen(buf)+strlen(buf2) > 77)
            {
               strcat(dest,buf);
               strcat(dest,"\n");

               strcpy(buf,"SEEN-BY:");
               sprintf(buf2," %lu/%lu",nodes->Net[c],nodes->Node[c]);
               lastnet=nodes->Net[c];

               strcat(buf,buf2);
            }
            else
            {
               strcat(buf,buf2);
            }
         }
      }
   }

   if(strlen(buf)>8)
   {
      strcat(dest,buf);
      strcat(dest,"\n");
   }
}

void WritePathBuf(UBYTE *dest,struct jbList *list,ULONG maxlen)
{
   UWORD c;
   struct Path *path;

   for(path=list->First;path;path=path->Next)
      for(c=0;c<path->Paths;c++)
         if(path->Path[c][0]!=0)
         {
            if(maxlen-strlen(dest) < 200)
               return;

            strcat(dest,"^APATH: ");
            strcat(dest,path->Path[c]);
            strcat(dest,"\n");
         }
}

void MausifyAddress(UBYTE *addr,UBYTE *mausname,UBYTE *mausaddr)
{
   ULONG c;

   if(strlen(addr)<=8)
      return;

   if(stricmp(&addr[strlen(addr)-8],".maus.de")!=0)
      return;

   addr[strlen(addr)-8]=0;

   for(c=0;addr[c]!='@' && addr[c]!=0;c++)
   {
      if(addr[c]=='_') mausname[c]=' ';
      else             mausname[c]=addr[c];
   }

   mausname[c]=0;

   if(addr[c]=='@') c++;

   strcpy(mausaddr,&addr[c]);

   for(c=0;addr[c]!=0;c++)
      mausaddr[c]=toupper(addr[c]);

   strcat(mausaddr,".maus");
}

void UnMausifyAddress(UBYTE *name,UBYTE *addr)
{
   ULONG c;
   UBYTE buf[100];

   if(strlen(addr)<=5)
      return;

   if(stricmp(&addr[strlen(addr)-5],".maus")!=0)
      return;

   addr[strlen(addr)-5]=0;

   strcpy(buf,name);

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

   strcat(buf,"@");

   for(c=0;addr[c];c++)
      addr[c]=tolower(addr[c]);

   strcat(buf,addr);
   strcat(buf,".maus.de");

   strcpy(addr,buf);
}

void makemailname(char *dest,char *name,char *addr)
{
   char *b;
   char rec[100];

   strcpy(rec,dest);

   name[0]=0;
   addr[0]=0;

   if(b=strchr(rec,','))
   {
      *b=0;
      mystrncpy(name,rec,100);
      mystrncpy(addr,&b[1],100);
   }
   else
   {
      if(b=strchr(rec,'@'))
      {
         mystrncpy(addr,rec,100);
         *b=0;
         mystrncpy(name,rec,100);
      }
      else
      {
         mystrncpy(name,rec,100);
      }
   }
}


RescanUMS(struct Area *area,ULONG max)
{
   UBYTE reason[80];
   BOOL res;
   ULONG num,rescan;

   UMSSelectTags(UMSHandle,UMSTAG_SelWriteLocal,TRUE,
                           UMSTAG_SelSet,       0,
                           UMSTAG_SelUnset,     UMSFLAG_TORESCAN | UMSFLAG_RESCANAREA | UMSFLAG_RESCAN,
                           TAG_DONE);

   UMSSelectTags(UMSHandle,UMSTAG_SelWriteLocal, TRUE,
                           UMSTAG_SelMask,       UMSUSTATF_ViewAccess | UMSUSTATF_ReadAccess,
                           UMSTAG_SelMatch,      UMSUSTATF_ViewAccess | UMSUSTATF_ReadAccess,
                           UMSTAG_SelSet,        UMSFLAG_TORESCAN,
                           UMSTAG_SelUnset,      0,
                           TAG_DONE);

   UMSSelectTags(UMSHandle,UMSTAG_SelWriteLocal, TRUE,
                           UMSTAG_SelQuick,      TRUE,
                           UMSTAG_WGroup,        area->Path,
                           UMSTAG_SelSet,        UMSFLAG_RESCANAREA,
                           UMSTAG_SelUnset,      0,
                           TAG_DONE);

   UMSSelectTags(UMSHandle,UMSTAG_SelWriteLocal, TRUE,
                           UMSTAG_SelReadLocal,  TRUE,
                           UMSTAG_SelQuick,      TRUE,
                           UMSTAG_SelMask,       UMSFLAG_TORESCAN | UMSFLAG_RESCANAREA,
                           UMSTAG_SelMatch,      UMSFLAG_TORESCAN | UMSFLAG_RESCANAREA,
                           UMSTAG_SelSet,        0,
                           UMSTAG_SelUnset,      UMSFLAG_RESCAN,
                           TAG_DONE);

   UMSSelectTags(UMSHandle,UMSTAG_SelWriteLocal, TRUE,
                           UMSTAG_SelReadLocal,  TRUE,
                           UMSTAG_SelQuick,      TRUE,
                           UMSTAG_SelMask,       UMSFLAG_TORESCAN | UMSFLAG_RESCANAREA,
                           UMSTAG_SelMatch,      UMSFLAG_TORESCAN | UMSFLAG_RESCANAREA,
                           UMSTAG_SelSet,        UMSFLAG_RESCAN,
                           UMSTAG_SelMaxCount,   max,
                           TAG_DONE);

   num=0;
   rescan=0;

   for(;;)
   {
      num=UMSSearchTags(UMSHandle,UMSTAG_SearchLocal, TRUE,
                                  UMSTAG_SearchLast,  num,
                                  UMSTAG_SearchMask,  UMSFLAG_RESCAN | UMSFLAG_RESCANAREA,
                                  UMSTAG_SearchMatch, UMSFLAG_RESCAN | UMSFLAG_RESCANAREA,
                                  TAG_DONE);

      if(!num)
         return(rescan);

      isrescanning=TRUE;
      res=ExportUMSMsg(area,num,reason);
      isrescanning=FALSE;
      rescan++;

      if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
         return;

      if(nomem || diskfull || exitprg)
         return;
   }
}

/* Export UMS Message */

ExportAreaUMS(struct Area *area)
{
   UBYTE reason[80];
   UBYTE *group;
   BOOL res;
   ULONG num;

   group=area->Path;

   if(stricmp(group,"Mail")==0 || strnicmp(group,"Mail:",5)==0)
      group="";

   if(group[0]==0)
   {
      if(scannedumsmail)
      {
         Printf("Skipping area %s, UMS mail already exported\n",(long)area->Tagname);
         return;
      }

      scannedumsmail=TRUE;
   }

   Printf("Scanning area %s\n",(long)area->Tagname);

   UMSSelectTags(UMSHandle,UMSTAG_SelWriteLocal,TRUE,
                           UMSTAG_SelReadLocal, TRUE,
                           UMSTAG_SelMask,      UMSFLAG_TOEXPORT,
                           UMSTAG_SelMatch,     UMSFLAG_TOEXPORT,
                           UMSTAG_SelSet,       0,
                           UMSTAG_SelUnset,     UMSFLAG_EXPORTAREA,
                           TAG_DONE);

   UMSSelectTags(UMSHandle,UMSTAG_SelWriteLocal, TRUE,
                           UMSTAG_SelQuick,      TRUE,
                           UMSTAG_WGroup,        group,
                           UMSTAG_SelSet,        UMSFLAG_EXPORTAREA,
                           UMSTAG_SelUnset,      0,
                           TAG_DONE);

   num=0;

   for(;;)
   {
      num=UMSSearchTags(UMSHandle,UMSTAG_SearchLocal, TRUE,
                                  UMSTAG_SearchLast,  num,
                                  UMSTAG_SearchMask,  UMSFLAG_EXPORTAREA | UMSFLAG_TOEXPORT,
                                  UMSTAG_SearchMatch, UMSFLAG_EXPORTAREA | UMSFLAG_TOEXPORT,
                                  TAG_DONE);

      if(!num)
         return;

      res=ExportUMSMsg(area,num,reason);

      if(res)
      {
         UMSSelectTags(UMSHandle,UMSTAG_SelWriteLocal, TRUE,
                                 UMSTAG_SelMsg,        num,
                                 UMSTAG_SelSet,        UMSFLAG_EXPORTED,
                                 TAG_DONE);
      }

      else
      {
         UMSCannotExport(UMSHandle,num,reason);
         LogWrite(1,TOSSINGERR,"Couldn't export message %ld: %s",num,reason);
      }

      if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
         return;

      if(nomem || diskfull || exitprg)
         return;
   }
}

#define UMSATTRARG_HOLD          0
#define UMSATTRARG_CRASH         1
#define UMSATTRARG_URGENT        2
#define UMSATTRARG_FILEATTACH    3
#define UMSATTRARG_RECEIPTREQ    4
#define UMSATTRARG_AUDITREQ      5
#define UMSATTRARG_ALIAS         6
#define UMSATTRARG_FIDOADDR      7
#define UMSATTRARG_IGNORE        8

UBYTE *umsattrargstr="HOLD/S,CRASH/S,URGENT/S,FILE-ATTACH/S,RECEIPT-REQUEST/S,AUDIT-REQUEST/S,ALIAS/K,FIDOADDR/K,IGNORE/M";

ULONG umsattrargarray[9];

ExportUMSMsg(struct Area *area,ULONG num,UBYTE *reason)
{
   ULONG res,c;
   UBYTE buf[200];
   UBYTE FromFidoAddr[30],FromRfcAddr[100],ToRfcAddr[100];
   struct TextChunk *chunk;
   ULONG MsgDate,MsgCDate,ChainUp,GlobalFlags;
   BOOL nodate;
   struct Node4D AttribFrom4D;
   BOOL OwnMessage,AttribFidoAddr,hasorigin;
   struct Aka *routeaka;
   struct Node5D n5d;
   struct DateStamp ds;
   char *fields[128];
   UBYTE *MsgText;

   OwnMessage=FALSE;
   AttribFidoAddr=FALSE;

   ToRfcAddr[0]=0;
   FromRfcAddr[0]=0;

   MemMessage.MSGID[0]=0;
   MemMessage.REPLY[0]=0;

   reason[0]=0;

   res=ReadUMSMsgTags(UMSHandle,UMSTAG_RMsgNum,         num,
                                UMSTAG_RNoUpdate,       1,
                                UMSTAG_RTextFields,     fields,
                                UMSTAG_RReadAll,        1,
                                UMSTAG_RChainUp,        &ChainUp,
                                UMSTAG_RGlobalFlags,    &GlobalFlags,
                                UMSTAG_RMsgDate,        &MsgDate,
                                UMSTAG_RMsgCDate,       &MsgCDate,
                                TAG_DONE);
   if(!res)
   {
      strcpy(reason,"Failed to read message");
      return(FALSE);
   }

   /* Clear MemMessage */

   ((struct TextChunk *)MemMessage.TextChunks.First)->Next=NULL;
   ((struct TextChunk *)MemMessage.TextChunks.First)->Data[0]=0;
   ((struct TextChunk *)MemMessage.TextChunks.First)->Length=0;
   ((struct Nodes2D *)MemMessage.SeenBy.First)->Nodes=0;
   ((struct Nodes2D *)MemMessage.SeenBy.First)->Next=NULL;
   ((struct Path *)MemMessage.Path.First)->Paths=0;
   ((struct Path *)MemMessage.Path.First)->Next=NULL;

   MemMessage.TextChunks.Last  = MemMessage.TextChunks.First;
   MemMessage.SeenBy.Last      = MemMessage.SeenBy.First;
   MemMessage.Path.Last        = MemMessage.Path.First;

   MemMessage.BadReason[0]=0;

   /* Make From, To and Subject */

   MemMessage.To[0]=0;
   MemMessage.From[0]=0;
   MemMessage.Subject[0]=0;

   if(fields[UMSCODE_ToName])
      mystrncpy(MemMessage.To,fields[UMSCODE_ToName],36);

   if(fields[UMSCODE_FromName])
      mystrncpy(MemMessage.From,fields[UMSCODE_FromName],36);

   if(fields[UMSCODE_Subject])
      mystrncpy(MemMessage.Subject,fields[UMSCODE_Subject],72);

   strip(MemMessage.From);
   strip(MemMessage.To);
   strip(MemMessage.Subject);

   if((cfg_Flags & CFG_UMSEMPTYTOALL) && MemMessage.To[0]==0)
      strcpy(MemMessage.To,"All");

   MemMessage.Attr=0;
   MemMessage.Cost=0;
   MemMessage.Rescanned=FALSE;

   chunk=MemMessage.TextChunks.First;

   /* Make date */

   nodate=TRUE;

   if(MsgCDate)
   {
      ds.ds_Days   = MsgCDate / 86400;
      ds.ds_Minute = (MsgCDate % 86400) / 60;
      ds.ds_Tick   = ((MsgCDate % 86400) % 60) * 50;
      nodate=FALSE;
   }

   if(nodate && fields[UMSCODE_CreationDate])
   {
      if(UMSDateToStamp(fields[UMSCODE_CreationDate],&ds))
         nodate=FALSE;

      else
         LogWrite(1,TOSSINGERR,"Unknown date format \"%s\", using other date",
            fields[UMSCODE_CreationDate]);
   }

   if(nodate && MsgDate)
   {
      ds.ds_Days   = MsgDate / 86400;
      ds.ds_Minute = (MsgDate % 86400) / 60;
      ds.ds_Tick   = ((MsgDate % 86400) % 60) * 50;
      nodate=FALSE;
   }

   if(nodate)
   {
      DateStamp(&ds);
   }

   MakeFidoDate(&ds,MemMessage.DateTime);

   /* Parse attributes */

   if(fields[UMSCODE_Attributes])
   {
      struct RDArgs *attrrdargs,*RDArgs;
      UBYTE argstr[200];
      UBYTE *rdabuf;

      mystrncpy(argstr,fields[UMSCODE_Attributes],199);
      strcat(argstr,"\n");

      if(!(RDArgs=(struct RDArgs *)AllocDosObject(DOS_RDARGS,NULL)))
      {
         nomem=TRUE;
         return;
      }

      if(!(rdabuf=(APTR)AllocMem(10000,MEMF_CLEAR)))
      {
         FreeDosObject(DOS_RDARGS,RDArgs);
         nomem=TRUE;
         return;
      }

      RDArgs->RDA_Source.CS_Buffer=argstr;
      RDArgs->RDA_Source.CS_Length=strlen(argstr);
      RDArgs->RDA_Source.CS_CurChr=0;
      RDArgs->RDA_Flags=RDAB_NOPROMPT;
      RDArgs->RDA_BufSiz=10000;
      RDArgs->RDA_Buffer=rdabuf;

      for(c=0;c<9;c++)
         umsattrargarray[c]=0;

      if(!(attrrdargs = (struct RDArgs *)ReadArgs(umsattrargstr,umsattrargarray,RDArgs)))
      {
         UBYTE rdargserrbuf[200];

         Fault(IoErr(),NULL,rdargserrbuf,190);
         LogWrite(1,TOSSINGERR,"Warning: Corrupt attributes string: %s",rdargserrbuf);
      }
      else
      {
         if(umsattrargarray[UMSATTRARG_HOLD])         MemMessage.Attr|=HOLD;
         if(umsattrargarray[UMSATTRARG_CRASH])        MemMessage.Attr|=CRASH;
         if(umsattrargarray[UMSATTRARG_URGENT])       MemMessage.Attr|=CRASH;
         if(umsattrargarray[UMSATTRARG_FILEATTACH])   MemMessage.Attr|=FILEATTACH;
         if(umsattrargarray[UMSATTRARG_RECEIPTREQ])   MemMessage.Attr|=RREQ;
         if(umsattrargarray[UMSATTRARG_AUDITREQ])     MemMessage.Attr|=AUDIT;

         if(umsattrargarray[UMSATTRARG_ALIAS])
         {
            UBYTE *realname1,*realname2;

            realname1=(UBYTE *)ReadUMSConfigTags(UMSHandle,UMSTAG_CfgUserName,(UBYTE *)umsattrargarray[UMSATTRARG_ALIAS],TAG_END);
            realname2=(UBYTE *)ReadUMSConfigTags(UMSHandle,UMSTAG_CfgUserName,fields[UMSCODE_FromName],TAG_END);

            if(realname1 && realname2 && stricmp(realname1,realname2)==0)
            {
               mystrncpy(MemMessage.From,(UBYTE *)umsattrargarray[UMSATTRARG_ALIAS],36);
            }
            else
            {
               LogWrite(1,TOSSINGERR,"%s is not a valid alias for %s",(UBYTE *)umsattrargarray[UMSATTRARG_ALIAS],realname2);
            }

            if(realname1) FreeUMSConfig(UMSHandle,realname1);
            if(realname2) FreeUMSConfig(UMSHandle,realname2);
         }

         if(umsattrargarray[UMSATTRARG_FIDOADDR])
         {
            struct Node4D n4d;
            char *tmp;

            tmp=ReadUMSConfigTags(UMSHandle,UMSTAG_CfgUser,fields[UMSCODE_FromName],
                                            UMSTAG_CfgName,"sysop",
                                            TAG_DONE);

            if(tmp)
               FreeUMSConfig(UMSHandle,tmp);

            if(!tmp)
            {
               LogWrite(1,TOSSINGERR,"Only sysop users may specify FIDOADDR, using normal address");
            }
            else
            {
               if(!Parse4D((UBYTE *)umsattrargarray[UMSATTRARG_FIDOADDR],&n4d))
               {
                  LogWrite(1,TOSSINGERR,"Invalid node number \"%s\" used with FIDOADDR, using normal address",
                     (UBYTE *)umsattrargarray[UMSATTRARG_FIDOADDR]);
               }
               else
               {
                  Copy4D(&AttribFrom4D,&n4d);
                  AttribFidoAddr=TRUE;
               }
            }
         }

         FreeArgs(attrrdargs);
      }

      FreeMem(rdabuf,10000);
      FreeDosObject(DOS_RDARGS,RDArgs);
   }

   OwnMessage=FALSE;

   if(fields[UMSCODE_Comments] && !(area->Flags & AREA_NETMAIL))
      if(strncmp("Fido/CrashMail",fields[UMSCODE_Comments],14)==0) OwnMessage=TRUE;

   if(OwnMessage)
   {
      /* It is an Echomail message imported by CrashMail. We just try to recreate it. */

      ULONG c,d;
      UBYTE dest[100];
      UBYTE *Comments;

      strcpy(MemMessage.Area,area->Tagname);

      Comments=fields[UMSCODE_Comments];

      c=0;

      while(Comments[c]!=0)
      {
         d=0;

         while(d<89 && Comments[c]!=10 && Comments[c]!=0)
            dest[d++]=Comments[c++];

         dest[d]=0;

         /* Rebuild 0x01 */

         if(dest[0]=='^' && dest[1]=='A')
         {
            dest[0]=1,
            strcpy(&dest[1],&dest[2]);
         }

         /* has a line in dest */

         if(dest[0]==1)
         {
            strcat(dest,"\x0d");

            if(strncmp(dest,"\x01CHRS: ",7)==0 || strncmp(dest,"\x01CHARSET: ",10)==0)
            {
               UBYTE dest2[100];

               sprintf(dest2,"\x01_%s",&dest[1]);

               if(chunk->Length - PKT_CHUNKLEN > strlen(dest2))
                  strcat(chunk->Data,dest2);
            }
            else if(strncmp(dest,"\x01PATH: ",7)!=0)
            {
               ProcessKludge(dest,strlen(dest));

               if(chunk->Length - PKT_CHUNKLEN > strlen(dest))
                  strcat(chunk->Data,dest);
            }
         }

         if(!(area->Flags & AREA_NETMAIL) && strncmp(dest,"SEEN-BY:",8)==0)
            AddSeenby(&dest[8],&MemMessage.SeenBy);

         else if(!(area->Flags & AREA_NETMAIL) && strncmp(dest,"\x01PATH:",6)==0)
            AddPath(&dest[7],&MemMessage.Path);

         while(Comments[c]!=10 && Comments[c]!=0) c++;
         if(Comments[c]==10) c++;
      }
   }
   else
   {
      /* Netmail or a message not from CrashMail */

      if(area->Flags & AREA_NETMAIL)
      {
         MemMessage.Area[0]=0;
         MemMessage.Attr|=PVT;

         /* Is netmail, create ToAddr and FromAddr accordingly */

         /* Create ToAddr */

         if(Parse5D(fields[UMSCODE_ToAddr],&n5d) && n5d.Zone!=0 && n5d.Net!=0)
         {
            /* FTN */

            LogWrite(4,TOSSINGINFO,"Exporting message from \"%s\" to \"%s\" at %s",
               MemMessage.From,
               MemMessage.To,
               fields[UMSCODE_ToAddr]);

            MemMessage.DestNode.Zone=n5d.Zone;
            MemMessage.DestNode.Net=n5d.Net;
            MemMessage.DestNode.Node=n5d.Node;
            MemMessage.DestNode.Point=n5d.Point;
         }
         else
         {
            /* UseNet */

            if(cfg_GatewayName[0]==0)
            {
               strcpy(reason,"No UUCP Gateway configured");
               FreeUMSMsg(UMSHandle,num);
               CleanMemMessage();
               return(FALSE);
            }

            strcpy(MemMessage.To,cfg_GatewayName);
            Copy4D(&MemMessage.DestNode,&cfg_GatewayNode);
            strcpy(ToRfcAddr,fields[UMSCODE_ToAddr]);

            if(cfg_Flags & CFG_UMSMAUSGATE)
               UnMausifyAddress(fields[UMSCODE_ToName],ToRfcAddr);

            LogWrite(4,TOSSINGINFO,"Exporting message from \"%s\" to \"%s\" via UseNet gateway",
               MemMessage.From,
               ToRfcAddr);
         }

         /* Find route to destination */

         if(!(routeaka=GetRouteAka(&MemMessage.DestNode)))
         {
            sprintf(reason,"No routing found for %lu:%lu/%lu.%lu",MemMessage.DestNode.Zone,
                                                                  MemMessage.DestNode.Net,
                                                                  MemMessage.DestNode.Node,
                                                                  MemMessage.DestNode.Point);

            FreeUMSMsg(UMSHandle,num);
            CleanMemMessage();
            return(FALSE);
         }

         /* Sätt egen adress om FromAddr */

         if(AttribFidoAddr)
            Copy4D(&MemMessage.OrigNode,&AttribFrom4D);

         else
            Copy4D(&MemMessage.OrigNode,&routeaka->Node);

         /* Sätt annan FromAddr om det redan fanns en */

         if(fields[UMSCODE_FromAddr])
         {
            if(Parse5D(fields[UMSCODE_FromAddr],&n5d) && n5d.Zone!=0 && n5d.Net!=0)
            {
               /* FTN */

               MemMessage.OrigNode.Zone=n5d.Zone;
               MemMessage.OrigNode.Net=n5d.Net;
               MemMessage.OrigNode.Node=n5d.Node;
               MemMessage.OrigNode.Point=n5d.Point;
            }
            else
            {
               /* UseNet */

               mystrncpy(FromRfcAddr,fields[UMSCODE_FromAddr],100);
            }
         }

         MakeNetmailKludges(&MemMessage.TextChunks,&MemMessage.OrigNode,&MemMessage.DestNode,cfg_Flags & CFG_ADDTID);
         chunk->Data[chunk->Length]=0;

         if(UMS_Version >=11 && (GlobalFlags & UMSGSTATF_HasFile))
         {
            UBYTE namebuf[200];

            MemMessage.Attr|=FILEATTACH;

            strcpy(MemMessage.Subject,cfg_PacketDir);
            AddPart(MemMessage.Subject,fields[UMSCODE_FileName],71);

            strcpy(namebuf,cfg_PacketDir);
            AddPart(namebuf,FilePart(fields[UMSCODE_TempFileName]),190);

            CopyFile(fields[UMSCODE_TempFileName],cfg_PacketDir);
            Rename(namebuf,MemMessage.Subject);
         }
      }
      else
      {
         strcpy(MemMessage.Area,area->Tagname);

         if(AttribFidoAddr)
            Copy4D(&MemMessage.OrigNode,&AttribFrom4D);

         else
            Copy4D(&MemMessage.OrigNode,&area->Aka->Node);

         /* Sätt annan FromAddr om det redan fanns en */

         if(fields[UMSCODE_FromAddr])
         {
            if(Parse5D(fields[UMSCODE_FromAddr],&n5d) && n5d.Zone!=0 && n5d.Net!=0)
            {
               /* FTN */

               MemMessage.OrigNode.Zone=n5d.Zone;
               MemMessage.OrigNode.Net=n5d.Net;
               MemMessage.OrigNode.Node=n5d.Node;
               MemMessage.OrigNode.Point=n5d.Point;
            }
            else
            {
               /* UseNet */

               mystrncpy(FromRfcAddr,fields[UMSCODE_FromAddr],100);

               if(cfg_Flags & CFG_UMSMAUSGATE)
                  UnMausifyAddress(fields[UMSCODE_FromName],FromRfcAddr);
            }
         }

         if(!isrescanning)
            LogWrite(4,TOSSINGINFO,"Exporting message from \"%s\" to \"%s\" in %s",MemMessage.From,MemMessage.To,area->Tagname);
      }

      Print4D(&MemMessage.OrigNode,FromFidoAddr);

      MSGID_RfcToFido(fields[UMSCODE_MsgID],MemMessage.MSGID);

      if(fields[UMSCODE_ReferID])
         MSGID_RfcToFido(fields[UMSCODE_ReferID],MemMessage.REPLY);

      /* If the address in MSGID/REPLY is your own, replace with a
         FidoNet address */

      if(cfg_Flags & CFG_CHANGEUMSMSGID)
      {
         UBYTE *MsgID,*ReferID;

         MsgID=fields[UMSCODE_MsgID];
         ReferID=fields[UMSCODE_ReferID];

         c=0;
         while(MsgID[c]!='@' && MsgID[c]!=0) c++;
         strncpy(buf,MsgID,c);
         buf[c]=0;
         if(MsgID[c]=='@') c++;

         if(stricmp(&MsgID[c],UMS_DomainAddress)==0)
            sprintf(MemMessage.MSGID,"%s %s",FromFidoAddr,buf);

         if(ReferID)
         {
            c=0;
            while(ReferID[c]!='@' && ReferID[c]!=0) c++;
            strncpy(buf,ReferID,c);
            buf[c]=0;
            if(ReferID[c]=='@') c++;

            if(stricmp(&ReferID[c],UMS_DomainAddress)==0)
               sprintf(MemMessage.REPLY,"%s %s",FromFidoAddr,buf);
         }
      }

      /* Use FidoID */

      if(fields[UMSCODE_FidoID] && MemMessage.MSGID[0]==0)
         strcpy(MemMessage.MSGID,fields[UMSCODE_FidoID]);

      if(ChainUp)
      {
         ULONG locres;
         UBYTE *FidoID;

         locres=ReadUMSMsgTags(UMSHandle,UMSTAG_RMsgNum,         ChainUp,
                                         UMSTAG_RFidoID,         &FidoID,
                                         TAG_DONE);

         if(locres)
         {
            if(FidoID)
               strcpy(MemMessage.REPLY,FidoID);

            FreeUMSMsg(UMSHandle,ChainUp);
         }
      }

      if(MemMessage.MSGID[0]!=0)
      {
         sprintf(buf,"\x01MSGID: %s\x0d",MemMessage.MSGID);
         strcat(chunk->Data,buf);
      }

      if(MemMessage.REPLY[0]!=0)
      {
         sprintf(buf,"\x01REPLY: %s\x0d",MemMessage.REPLY);
         strcat(chunk->Data,buf);
      }

      if(FromRfcAddr[0])
      {
         sprintf(buf,"\x01REPLYADDR %s\x0d",FromRfcAddr);
         strcat(chunk->Data,buf);

         if(cfg_UMSGatewayName[0])
         {
            sprintf(buf,"\x01REPLYTO %s %s\x0d",FromFidoAddr,cfg_UMSGatewayName);
            strcat(chunk->Data,buf);
         }
      }
   }

   if(area->ExportCHRS!=(UBYTE *)CHARSET_ASCII)
   {
      if(area->ExportCHRS==NULL)
         strcpy(buf,"\x01CHRS: LATIN-1 2\x0d");

      if(area->ExportCHRS==AmigaToMac)
         strcpy(buf,"\x01CHRS: MAC 2\x0d");

      if(area->ExportCHRS==AmigaToIbm)
         strcpy(buf,"\x01CHRS: IBMPC 2\x0d");

      if(area->ExportCHRS==AmigaToSF7)
         strcpy(buf,"\x01CHRS: SWEDISH 1\x0d");

      strcat(chunk->Data,buf);
   }

   if(!(area->Flags & AREA_NETMAIL) && (cfg_Flags & CFG_ADDTID) && !isrescanning)
   {
      if(Checksum11() != checksums[11])
      {
         strcat(chunk->Data,"\x01TID: CrashMail "TID_VERSION" Unreg\x0d");
      }
      else
      {
         sprintf(buf,"\x01TID: CrashMail "TID_VERSION" %lu\x0d",key.Serial);
         strcat(chunk->Data,buf);
      }
   }

   if(isrescanning)
   {
      UBYTE addr[40];

      Print4D(&area->Aka->Node,addr);
      sprintf(buf,"\x01RESCANNED %s\x0d",addr);
      strcat(chunk->Data,buf);
   }

   if(ToRfcAddr[0])
   {
      strcat(chunk->Data,"To: ");
      strcat(chunk->Data,ToRfcAddr);
      strcat(chunk->Data,"\x0d\x0d");
   }

   chunk->Length=strlen(chunk->Data);

   hasorigin=FALSE;

   MsgText=fields[UMSCODE_MsgText];

   if(MsgText)
   {
      AddChunkList(&MemMessage.TextChunks,MsgText,strlen(MsgText));

      if(MsgText[strlen(MsgText)-1]!=10)
         AddChunkList(&MemMessage.TextChunks,"\n",1);

      c=0;

      while(MsgText[c]!=0)
      {
         if(strncmp(&MsgText[c]," * Origin: ",11)==0)
            hasorigin=TRUE;

         while(MsgText[c]!=0 && MsgText[c]!=10) c++;
         if(MsgText[c]==10) c++;
      }
   }

   if(!(area->Flags & AREA_NETMAIL) && !hasorigin)
   {
      if(OwnMessage)
      {
         /* It is an Echomail message imported by CrashMail.
            Perhaps there is a tear line and a origin line in Comments? */

         ULONG c,d;
         UBYTE dest[100];
         UBYTE *comments;

         c=0;

         comments=fields[UMSCODE_Comments];

         while(comments[c]!=0)
         {
            d=0;

            while(d<89 && comments[c]!=10 && comments[c]!=0)
               dest[d++]=comments[c++];

            dest[d]=0;

            if(dest[0]!=0)
            {
               strcat(dest,"\x0d");

               if(strncmp(dest,"---",3)==0)
                  AddChunkList(&MemMessage.TextChunks,dest,strlen(dest));

               if(strncmp(dest," * Origin:",10)==0)
                  AddChunkList(&MemMessage.TextChunks,dest,strlen(dest));
            }

            while(comments[c]!=10 && comments[c]!=0) c++;
            if(comments[c]==10) c++;
         }
      }
      else
      {
         if(fields[UMSCODE_Newsreader])
            sprintf(buf,"--- %s\x0d",fields[UMSCODE_Newsreader]);

         else
            strcpy(buf,"---\x0d");

         AddChunkList(&MemMessage.TextChunks,buf,strlen(buf));

         if(fields[UMSCODE_Organization])
            sprintf(buf," * Origin: %.70s (%s)\x0d",fields[UMSCODE_Organization],FromFidoAddr);

         else
            sprintf(buf," * Origin: %.70s (%s)\x0d",cfg_DefaultOrigin,FromFidoAddr);

         AddChunkList(&MemMessage.TextChunks,buf,strlen(buf));
      }
   }

   if(area->ExportCHRS!=(UBYTE *)CHARSET_ASCII)
   {
      Xlat(MemMessage.To,area->ExportCHRS,strlen(MemMessage.To));
      Xlat(MemMessage.From,area->ExportCHRS,strlen(MemMessage.From));
      Xlat(MemMessage.Subject,area->ExportCHRS,strlen(MemMessage.Subject));
   }

   for(chunk=MemMessage.TextChunks.First;chunk;chunk=chunk->Next)
   {
      if(area->ExportCHRS!=(UBYTE *)CHARSET_ASCII)
         Xlat(chunk->Data,area->ExportCHRS,chunk->Length);

      for(c=0;c<chunk->Length;c++)
         if(chunk->Data[c]==10) chunk->Data[c]=13;
   }

   FreeUMSMsg(UMSHandle,num);

   if(!isrescanning)
      scan_num++;

   HandleMessage();

   CleanMemMessage();

   return(TRUE);
}


/*******************************************************************************

   UMSDateToStamp by Johan Billing

   This function was originally based on DateToMaus() by Ch. Rütgers '93
   which is based on DateToSeconds by Stefan Stuntz'92. Not much code from
   those functions are left anymore.

   This function can parse any date formats which use "HH:MM:SS" or "HH:MM" to
   store the time and "day-month-date" or "day month date" to store the date.
   It also supports Maus and Z-Netz dates.
   Known date formats:

    0         1         2         3
    0123456789012345678901234567890

   "22.08.1992 19:54"              Mausformat
   "JJMMTThhmm"                    Z-Netz

   The function also supports dates like these:

   "Wed 13 Jan 86 02:34"           Fido SEAdog
   "01 Jan 91  11:22:33"           Fido Standard
   "01 Jan 91  11:22"              Fido Standard ohne Sekunden
   "01-Jan-78 10:11:12"            AmigaDOS
   "Montag 04-Jan-93  17:52:16"    Amigados locale
   "Tuesday 18-Aug-92 17:52:33"    Amigados locale english
   "Mon, 28 Dec 1992 06:27:20 GMT" RFC mit Tag
   "Mon, 1 Jan 1992 06:27:20 GMT"  RFC mit Tag (einstellig)
   "28 Dec 1992 10:11:21 GMT"      RFC mit langer Jahreszahl
   "28 Dec 92 22:51:14 GMT"        RFC
   "8 Dec 92 22:51:14 GMT"         RFC mit einstelligem Tag

*******************************************************************************/

int countchar(UBYTE *str,UBYTE ch)
{
   int res=0,c;

   for(c=0;c<strlen(str);c++)
      if(str[c]==ch) res++;

   return(res);
}

BOOL strisnum(UBYTE *str)
{
   int i;

   for(i=0;str[i];i++)
      if(!isdigit(str[i])) return(FALSE);

   return(TRUE);
}


BOOL checkdate(UBYTE *str)
{
   int c=0;

   for(c=0;str[c]!=0;c++)
      if(str[c]!='-' && (str[c]<'0' || str[c]>'9')) return(FALSE);

   return(TRUE);
}

BOOL checktime(UBYTE *str)
{
   int c=0;

   for(c=0;str[c]!=0;c++)
      if(str[c]!=':' && (str[c]<'0' || str[c]>'9')) return(FALSE);

   return(TRUE);
}

BOOL UMSDateToStamp(UBYTE *M,struct DateStamp *ds)
{
   #define alpha(x)  (isalpha(M[x]))
   #define space(x)  (M[x]==' ')
   #define comma(x)  (M[x]==',')
   #define line(x)   (M[x]=='-')
   #define point(x)  (M[x]=='.')

   UBYTE buf[1100];
   UBYTE *words[10];

   struct DateTime dt;
   UBYTE date[40],time[40];
   int i,j,numwords;
   BOOL res;

   static char *mo[16] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                           "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
                           "Mär", "Mai","Okt", "Dez"};

   static char *num[17] = { "01","02", "03", "04", "05", "06",
                            "07","08", "09", "10", "11", "12",
                            "03", "05", "10", "12", "??" };


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

   if(strlen(M)==16 && point(2) && point(5) && space(10))
   {
      /* Maus "22.08.1992 19:54"  */

      sprintf(date,"%c%c-%c%c-%c%c",M[0],M[1],M[3],M[4],M[8],M[9]);
      sprintf(time,"%c%c:%c%c:00",M[11],M[12],M[14],M[15]);

      stripspace(date);
      stripspace(time);

      if(!checkdate(date) || !checktime(time))
         return(FALSE);

      res=StrToDate(&dt);
      CopyMem(&dt.dat_Stamp,ds,sizeof(struct DateStamp));
      return(res);
   }

   if(strlen(M)==10)
   {
      /* Z-Netz  "JJMMTThhmm" */

      sprintf(date,"%c%c-%c%c-%c%c",M[4],M[5],M[2],M[3],M[0],M[1]);
      sprintf(time,"%c%c:%c%c:00",M[6],M[7],M[8],M[9]);

      stripspace(date);
      stripspace(time);

      if(!checkdate(date) || !checktime(time))
         return(FALSE);

      res=StrToDate(&dt);
      CopyMem(&dt.dat_Stamp,ds,sizeof(struct DateStamp));
      return(res);
   }

   /* This should work with most other date formats */

   /* Copy string, remove spaces and change '-' to ' ' */

   strcpy(buf,M);

   for(i=0;buf[i];i++)
      if(buf[i]=='-') buf[i]=' ';

   /* Split into words */

   numwords=0;

   i=0;

   while(buf[i]==' ') i++;

   while(buf[i])
   {
      words[numwords++]=&buf[i];
      while(buf[i]!=' ' && buf[i]!=0) i++;
      if(buf[i]==' ') buf[i++]=0;
      while(buf[i]==' ') i++;
   }

   /* Find time */

   for(i=0;i<numwords;i++)
      if(strchr(words[i],':')) break;

   if(i>=numwords)
      return(FALSE);

   mystrncpy(time,words[i],40);

   if(countchar(time,':')==1)
      strcat(time,":00"); /* Add seconds if missing */

   /* Find date */

   for(i=0;i+2<numwords;i++)
      if(strisnum(words[i]) && !strisnum(words[i+1]) && strisnum(words[i+2])) break;

   if(i+2>=numwords)
      return(FALSE);

   if(strlen(words[i+2])==4)
      strcpy(words[i+2],&words[i+2][2]); /* Year is only two digits */

   /* Is it a month we know? */

   j=0;

   while(stricmp(words[i+1],mo[j]) && j<16)
      j++;

   if(j!=16)
   {
      /* Yes, we know it. */

      sprintf(date,"%.10s-%.10s-%.10s",words[i],num[j],words[i+2]);

      stripspace(date);
      stripspace(time);

      if(!checkdate(date) || !checktime(time))
         return(FALSE);

      res=StrToDate(&dt);
      CopyMem(&dt.dat_Stamp,ds,sizeof(struct DateStamp));
      return(res);
   }
   else
   {
      /* No, we don't know it... */

      dt.dat_Format=FORMAT_DOS;

      sprintf(date,"%.10s-%.10s-%.10s",words[i],words[i+1],words[i+2]);

      stripspace(date);
      stripspace(time);

      if(!checkdate(date) || !checktime(time))
         return(FALSE);

      res=StrToDate(&dt);
      CopyMem(&dt.dat_Stamp,ds,sizeof(struct DateStamp));
      return(res);
   }
}

/*************************************/
/*                                   */
/* Fido DateTime conversion routines */
/*                                   */
/*************************************/

BOOL FidoToStamp(UBYTE *date,struct DateStamp *ds)
{
   struct DateTime dt;
   UBYTE datestr[40],timestr[40];
   ULONG month,day,year;
   BOOL res;

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

   DateStamp(ds); /* Use today's date if we can't parse the fido date */

   dt.dat_Format=FORMAT_CDN;
   dt.dat_Flags=0;
   dt.dat_StrDay=NULL;
   dt.dat_StrDate=datestr;
   dt.dat_StrTime=timestr;

   if(date[2]==' ' && date[6]==' ')
   {
      /* Standard Fido                "01 Jan 91  11:22:33"   */

      /* Get month */

      for(month=0;month<12;month++)
         if(strnicmp(mo[month],&date[3],3)==0) break;

      if(month==12)
         return(FALSE);

      month++; /* 1-12, not 0-11 */

      day=atoi(date);
      year=atoi(&date[7]);

      sprintf(datestr,"%02lu-%02lu-%02lu",day,month,year);

      strcpy(timestr,&date[11]);

      if(!checkdate(datestr) || !checktime(timestr))
         return; /* Rumour says that StrToDate() can crash on corrupt dates. Some checking might help... */

      res=StrToDate(&dt);
      if(res) CopyMem(&dt.dat_Stamp,ds,sizeof(struct DateStamp));
      return(res);
   }
   else
   {
      /* SEAdog "Wed 13 Jan 86 02:34" */
      /* SEAdog "Wed  3 Jan 86 02:34" */

      /* Get month */

      for(month=0;month<12;month++)
         if(strnicmp(mo[month],&date[7],3)==0) break;

      if(month==12)
         return(FALSE);

      month++; /* 1-12, not 0-11 */

      if(date[4]==32)
         day=atoi(&date[5]);

      else
         day=atoi(&date[4]);

      year=atoi(&date[11]);

      sprintf(datestr,"%02lu-%02lu-%02lu",day,month,year);

      strcpy(timestr,&date[14]);
      strcat(timestr,":00");

      if(!checkdate(datestr) || !checktime(timestr))
         return;

      res=StrToDate(&dt);
      if(res) CopyMem(&dt.dat_Stamp,ds,sizeof(struct DateStamp));
      return(res);
   }
}

/*****************************************************/
/*                                                   */
/* MSGID Conversion routines according to Gatebau 95 */
/*                                                   */
/*****************************************************/

WORD FindHex(UBYTE chr)
{
   char *hextab="0123456789abcdef",ch,c;

   ch=chr|32;

   c=0;

   for(c=0;c<strlen(hextab);c++)
      if(hextab[c]==ch) return(c);

   return(-1);
}

void MSGID_RfcToFido(UBYTE *src,UBYTE *dest)
{
   ULONG crc;
   UWORD c;

   /* Created from a FidoNet message without MSGID */

   if(strncmp(src,"NOMSGID",7)==0)
   {
      dest[0]=0;
      return;
   }

   /* Convert back a converted FidoNet-MSGID */

   if(strncmp(src,"MSGID",5)==0)
   {
      UWORD d;

      d=0;

      for(c=6;src[c]!='@' && src[c]!=0;c++)
         if(d<79)
         {
            if(src[c]=='_')
            {
               dest[d++]=' ';
            }
            else if(src[c]=='=' && FindHex(src[c+1])!=-1 && FindHex(src[c+2])!=-1)
            {
               dest[d++]=FindHex(src[c+1])*16+FindHex(src[c+2]);
               c+=2;
            }
            else
            {
               dest[d++]=src[c];
            }
         }

      dest[d]=0;
      return;
   }

   /* Generic RFC MSGID */

   crc=0xFFFFFFFF;

   for(c=0;c<strlen(src);c++)
      crc=crc32add(crc,src[c]);

   for(c=0;c<strlen(MemMessage.Area);c++)
      crc=crc32add(crc,MemMessage.Area[c]);

   crc=~crc;

   sprintf(dest,"<%.65s> %08lx",src,crc);
}

void mimestring(UBYTE *src,UBYTE *dest,UWORD max)
{
   UWORD c,d;
   UBYTE *ctrlstr="()<>@,;:\\\"[]/=_";

   d=0;

   for(c=0;src[c]!=0;c++)
      if(d<max-1)
      {
         if(src[c]==' ')
         {
            dest[d++]=' ';
         }
         else if(strchr(ctrlstr,src[c]) || src[c]<32 || src[c]>127)
         {
            UBYTE mbuf[3];
            sprintf(mbuf,"%02lX",src[c]);
            dest[d++]='=';
            dest[d++]=mbuf[0];
            dest[d++]=mbuf[1];
         }
         else
         {
            dest[d++]=src[c];
         }
      }

   dest[d]=0;
}

void MSGID_FidoToRfc(UBYTE *src,UBYTE *dest,ULONG defaultzone,UBYTE *fido4dtxt)
{
   UBYTE first[100],second[100];
   UBYTE temp[100],temp2[100];
   struct Node5D n5d;
   ULONG zone;

   jbcpos=0;
   jbstrcpy(first,src,80);
   jbstrcpy(second,src,80);

   zone=-1;

   if(first[0])
      if(Parse5D(first,&n5d))
         zone=n5d.Zone;

   if(zone == -1) zone=defaultzone;

   if(UMS_MsgidConvertCache_Zone != zone || UMS_MsgidConvertCache_Domain[0]==0)
   {
      strcpy(UMS_MsgidConvertCache_Domain,"fidonet.org");
      UMS_MsgidConvertCache_Zone=zone;

      if(UMSBase && UMSHandle)
      {
         UBYTE *var;
         UBYTE cfgvar[50];

         sprintf(cfgvar,"crashmail.msgiddomain.%lu",zone);

         var=(UBYTE *)ReadUMSConfigTags(UMSHandle,UMSTAG_CfgName, cfgvar,
                                                  TAG_DONE);

         if(var)
         {
            if(var[0]=='@')
               mystrncpy(UMS_MsgidConvertCache_Domain,&var[1],100);

            else
               mystrncpy(UMS_MsgidConvertCache_Domain,var,100);

            FreeUMSConfig(UMSHandle,var);
         }
      }
   }

   /* No MSGID */

   if(src[0]==0)
   {
      UWORD month,c;
      ULONG crc;

      for(month=0;month<12;month++)
         if(strncmp(MonthNames[month],&MemMessage.DateTime[3],3)==0) break;

      if(month==12) month=0;
      else          month++;

      crc=0xFFFFFFFF;

      for(c=0;c<strlen(MemMessage.From);c++)
         crc=crc32add(crc,MemMessage.From[c]);

      for(c=0;c<strlen(MemMessage.To);c++)
         crc=crc32add(crc,MemMessage.To[c]);

      for(c=0;c<strlen(MemMessage.Subject);c++)
         crc=crc32add(crc,MemMessage.Subject[c]);

      crc=~crc;

      mimestring(fido4dtxt,temp2,30);

      sprintf(dest,"NOMSGID_%s_%c%c%02lu%c%c_%c%c%c%c%c%c_%08lx@%s",
         temp2,
         MemMessage.DateTime[7]==' ' ? '0' : MemMessage.DateTime[7],
         MemMessage.DateTime[8]==' ' ? '0' : MemMessage.DateTime[8],
         month,
         MemMessage.DateTime[0]==' ' ? '0' : MemMessage.DateTime[0],
         MemMessage.DateTime[1]==' ' ? '0' : MemMessage.DateTime[1],
         MemMessage.DateTime[11]==' ' ? '0' : MemMessage.DateTime[11],
         MemMessage.DateTime[12]==' ' ? '0' : MemMessage.DateTime[12],
         MemMessage.DateTime[14]==' ' ? '0' : MemMessage.DateTime[14],
         MemMessage.DateTime[15]==' ' ? '0' : MemMessage.DateTime[15],
         MemMessage.DateTime[17]==' ' ? '0' : MemMessage.DateTime[17],
         MemMessage.DateTime[18]==' ' ? '0' : MemMessage.DateTime[18],
         crc,
         UMS_MsgidConvertCache_Domain);

      return;
   }

   /* Standard RFC-Message-ID + serial */

   if(first[0]=='<' && first[strlen(first)-1]=='>' && countchar(first,'@')==1)
   {
      mystrncpy(dest,&first[1],80);
      dest[strlen(dest)-1]=0;
      return;
   }

   /* Generic */

   mimestring(first,temp,100);
   sprintf(dest,"MSGID_%s_%s@%s",temp,second,UMS_MsgidConvertCache_Domain);
}


/************************************/
/*                                  */
/* Copy memory and convert CR to LF */
/*                                  */
/************************************/

ULONG copymemcr(UBYTE *src,UBYTE *dest,ULONG len)
{
   ULONG c,d;

   d=0;

   for(c=0;c<len;c++)
   {
      if(src[c] == 13)        dest[d++]=10;
      else if(src[c] != 10)   dest[d++]=src[c];
   }

   return(d);
}

