{$IFDEF WtrGate}{$IFDEF UseOvr}{$O+,F+}{$ENDIF}{$ENDIF}
UNIT Mappers;

{$i platform.inc}

{ universal message redirector }

INTERFACE

{$IFDEF WtrConf}
PROCEDURE EditMappers;
{$ENDIF}

PROCEDURE Mappers_Detect (IsOutbound : BOOLEAN);
PROCEDURE Mappers_SaveMessage;


IMPLEMENTATION

USES Ramon,
     Database,
     Fido,
     Cfg,
     Msgs,
     FlexCfg,
     Logs,
     Dos,
     Address,
     Globals;

{$I WTRHLP.INC}

VAR Mapper : FilterRecord;

{--------------------------------------------------------------------------}
{ MapAddrDesc                                                              }
{                                                                          }
FUNCTION MapAddrDesc : STRING;
BEGIN
     CASE Mapper.AddrType OF
          madFTN:
              MapAddrDesc:='"'+Mapper.ToName+'" at '+Fido2Str (Mapper.ToAka);

          madRFC:
              MapAddrDesc:=Mapper.ToEmail;

          madRemoteGW:
              MapAddrDesc:=Mapper.ToEmail+' via "'+Mapper.ToName+'" at '+Fido2Str (Mapper.ToAka);

          ELSE
              MapAddrDesc:='**ERROR**';
     END; { case }
END;


{----------------------------------------------------------------------}
{ MapDesc                                                              }
{                                                                      }
{ This routine builds and returns a description for the mapper now in  }
{ Mapper.                                                              }
{                                                                      }
FUNCTION MapDesc : STRING;

VAR Desc : STRING;
    Msgs : STRING[50];

BEGIN
     IF (Mapper.Limit = 0) THEN
     BEGIN
          MapDesc:='disabled';
          Exit;
     END;

     Desc:='';

     (*
     Desc:='if '''+Mapper.Search+''' in ';

     CASE Mapper.Where OF
          mwtBody :
              Desc:=Desc+' body of ';

          mwtHeader :
              Desc:=Desc+' headers of ';

          mwtFrom :
              Desc:=Desc+' sender addresses of ';

          mwtTo :
              Desc:=Desc+' recipient addresses of ';

          mwtSubject :
              Desc:=Desc+' subject of ';
     END; { case }
     *)

     (*
     Msgs:='';

     IF ((Mapper.Limit AND mltNetmail) <> 0) THEN
        Msgs:=Msgs+'/netmail';

     IF ((Mapper.Limit AND mltEchomail) <> 0) THEN
        Msgs:=Msgs+'/echomail';

     IF ((Mapper.Limit AND mltEmail) <> 0) THEN
        Msgs:=Msgs+'/email';

     IF ((Mapper.Limit AND mltNews) <> 0) THEN
        Msgs:=Msgs+'/news';

     Desc:=Desc+Copy (Msgs,2,255)+' then ';
     *)

     CASE Mapper.Action OF
          matMove:
              Desc:=Desc+'Move to area '+Mapper.Argument;

          matCopy:
              Desc:=Desc+'Copy to area '+Mapper.Argument;

          matDelete:
              Desc:=Desc+'Delete message';

          matForward:
              Desc:=Desc+'Forward to '+MapAddrDesc;

          matCC:
              Desc:=Desc+'CC to '+MapAddrDesc;

          matBounce:
              Desc:=Desc+'Bounce back';

          matBounceAddr:
              Desc:=Desc+'Bounce to <to do>';

          matSave:
              Desc:=Desc+'Save to '+Mapper.Argument;

          matToFile:
              Desc:=Desc+'Redirect to '+Mapper.Argument;

          ELSE
              Desc:=Desc+'**ERROR**';
     END;

     Desc:=Desc+' (';

     CASE Mapper.InOut OF
          1 : Desc:=Desc+'Inbound, ';
          2 : Desc:=Desc+'Outbound, ';
          {3: both, do not mention }
     END;

     Desc:=Desc+''''+Mapper.Search+'''';

     CASE Mapper.Where OF
          mwtBody:
              Desc:=Desc+' in Body';

          mwtHeader:
              Desc:=Desc+' in Header';

          mwtFrom:
              Desc:=Desc+' in From';

          mwtTo:
              Desc:=Desc+' in To';

          mwtSubject:
              Desc:=Desc+' in Subject';
     END; { case }

     Desc:=Desc+')';

     MapDesc:=Desc;
END;

{$IFDEF WtrConf}

CONST ActionStrings : ARRAY[matMove..matSave] OF STRING[26] =
(
      'Move to area',
      'Copy to area',
      'Delete message',
      'Forward to user',
      'Carbon Copy to user',
      'Bounce back to sender',
      'Bounce to specific address',
      'Redirect to file',
      'Save to file'
);

VAR SearchStr : STRING[40];
    ActionStr : STRING[40];
    DispArea,
    AreaName  : STRING[60];

{--------------------------------------------------------------------------}
{ BuildSearchStr                                                           }
{                                                                          }
PROCEDURE BuildSearchStr;
BEGIN
     SearchStr:='';

     IF ((Mapper.Limit AND mltNetmail) > 0) THEN
        SearchStr:=SearchStr+', Netmail';

     IF ((Mapper.Limit AND mltEchomail) > 0) THEN
        SearchStr:=SearchStr+', Echomail';

     IF ((Mapper.Limit AND mltEmail) > 0) THEN
        SearchStr:=SearchStr+', E-mail';

     IF ((Mapper.Limit AND mltNews) > 0) THEN
        SearchStr:=SearchStr+', News';

     IF (SearchStr = '') THEN
        SearchStr:='Nowhere (disabled)'
     ELSE
         Delete (SearchStr,1,2);

     SearchStr:=AddUpWithSpaces (40,SearchStr);
END;


{--------------------------------------------------------------------------}
{ BuildActionStr                                                           }
{                                                                          }
PROCEDURE BuildActionStr;
BEGIN
     IF (Mapper.Action IN [matMove..matSave]) THEN
        ActionStr:=ActionStrings[Mapper.Action]
     ELSE
         ActionStr:='**ERROR**';

     ActionStr:=AddUpWithSpaces (40,ActionStr);
END;


{--------------------------------------------------------------------------}
{ EditSearchLimit                                                          }
{                                                                          }
PROCEDURE EditSearchLimit; FAR;

CONST Xb = 40;
      Yb = 7;
      Xl = 30;
      Yl = 6;

      Xb2 = Xb+12;

VAR DoNet,
    DoEcho,
    DoMail,
    DoNews : BYTE;

    FieldY : XYType;

BEGIN
     FieldPushAll;
     WindowPush (Xb,Yb,Xl,Yl);
     BoxDraw (Double,Xb,Yb,Xl,Yl);

     DoNet:=(Mapper.Limit AND 1);
     DoEcho:=((Mapper.Limit SHR 1) AND 1);
     DoMail:=((Mapper.Limit SHR 2) AND 1);
     DoNews:=((Mapper.Limit SHR 3) AND 1);

     FieldInit;

     FieldY:=Yb+1;

     WriteXY (Xb+2,FieldY,'Netmail');
     FieldAutoDefineToggles (Xb2,FieldY,DoNet,'no|yes',0);
     FieldSetHelp (0,htr_Filter_SearchLimit);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Echomail');
     FieldAutoDefineToggles (Xb2,FieldY,DoEcho,'no|yes',0);
     FieldSetHelp (0,htr_Filter_SearchLimit);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'E-mail');
     FieldAutoDefineToggles (Xb2,FieldY,DoMail,'no|yes',0);
     FieldSetHelp (0,htr_Filter_SearchLimit);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'News');
     FieldAutoDefineToggles (Xb2,FieldY,DoNews,'no|yes',0);
     FieldSetHelp (0,htr_Filter_SearchLimit);

     FieldEdit;

     Mapper.Limit:=DoNet OR (DoEcho SHL 1) OR (DoMail SHL 2) OR (DoNews SHL 3);

     BuildSearchStr;

     WindowPop;
     FieldPopAll;
END;


{--------------------------------------------------------------------------}
{ CheckMapperToAka                                                         }
{                                                                          }
FUNCTION CheckMapperToAka (BufferPtr : StringPtr) : BOOLEAN; FAR;
BEGIN
     FidoSplit (DeleteFrontAndBackSpaces (BufferPtr^),Mapper.ToAka);
     BufferPtr^:=AddUpWithSpaces (MaxLenFidoAddrString,Fido2Str (Mapper.ToAka));
     CheckMapperToAka:=TRUE;
END;


{--------------------------------------------------------------------------}
{ GrayAddressFields                                                        }
{                                                                          }
PROCEDURE GrayAddressFields; FAR;
BEGIN
     CASE Mapper.AddrType OF
          madFTN :
              BEGIN
                   FieldEnableField (8);
                   FieldEnableField (9);
                   FieldDisableField (10);
              END;

          madRFC :
              BEGIN
                   FieldDisableField (8);
                   FieldDisableField (9);
                   FieldEnableField (10);
              END;

          madRemoteGW :
              BEGIN
                   FieldEnableField (8);
                   FieldEnableField (9);
                   FieldEnableField (10);
              END;
     END; { case }

     FieldUpdateOneField (8);
     FieldUpdateOneField (9);
     FieldUpdateOneField (10);
END;


{--------------------------------------------------------------------------}
{ GrayActionFields                                                         }
{                                                                          }
PROCEDURE GrayActionFields; FAR;

VAR Lp : BYTE;

BEGIN
     FOR Lp:=6 TO 13 DO
         FieldDisableField (Lp);

     IF (Mapper.Action IN [matMove,matCopy,matForward,matCC,matSave,matToFile]) THEN
        FieldEnableField (6); { Add note }

     IF (Mapper.Action IN [matForward,matCC]) THEN
     BEGIN
          FieldEnableField (7); { AddrType }
          GrayAddressFields;
     END;

     IF (Mapper.Action = matBounceAddr) THEN
        FieldEnableField (10); { e-mail }

     IF (Mapper.Action IN [matMove,matCopy]) THEN
        FieldEnableField (11); { Area name }

     IF (Mapper.Action IN [matBounce,matBounceAddr]) THEN
        FieldEnableField (12); { Reason }

     IF (Mapper.Action IN [matToFile,matSave]) THEN
        FieldEnableField (13); { Path }

     FOR Lp:=6 TO 13 DO
         FieldUpdateOneField (Lp);
END;


{--------------------------------------------------------------------------}
{ SelectMapperAreaName                                                     }
{                                                                          }
PROCEDURE SelectMapperAreaName; FAR;

VAR Lp       : WORD;
    CursorLp : WORD;
    AreaData : AreaBaseRecord;

BEGIN
     ListDefine (3,3,39,Video.Rows-4,Default,
                 'Configured Areas',
                 htr_Filter_SelectArea);

     Message ('Please wait...');

     CursorLp:=1;

     FOR Lp:=1 TO AreaBaseRecCount DO
     BEGIN
          ReadAreaBaseRecord (Lp,AreaData);
          IF (NOT AreaData.Deleted) THEN
          BEGIN
               ListAddItem (AreaData.AreaName_F,Lp,Bottom);
               IF (AreaName = AddUpWithSpaces (MaxLenAreaName,AreaData.AreaName_F)) THEN
                  CursorLp:=Lp;
          END;
     END; { for }

     WindowPop;

     ListSortNow;
     ListSetCursorOnItem (CursorLp);
     Lp:=ListSelect (NoTag,[]);
     ListErase;

     IF (Key <> kEsc{thus kF10 or kRet}) THEN
     BEGIN
          ReadAreaBaseRecord (Lp,AreaData);
          AreaName:=AddUpWithSpaces (60,AreaData.AreaName_F);
          DispArea:=Copy (AreaName,1,50);
     END;
END;


{--------------------------------------------------------------------------}
{ EditMapperAction                                                         }
{                                                                          }
{ This List function is called when the user want sto select another       }
{ Action for the Filter Definition that is being editted.                  }
{                                                                          }
PROCEDURE EditMapperAction; FAR;

VAR Lp : MapActionType;

BEGIN
     MenuDefine (25,10,'Action list');
     FOR Lp:=matMove TO matSave DO
         MenuAddItem (ActionStrings[Lp]);
     MenuSetFirst (Ord (Mapper.Action)-Ord (matMove)+1);
     MenuSetHelp (htr_Filter_SelectAction);
     MenuShow;
     MenuSelect;
     MenuErase;

     IF (Key IN [mOpt01..mOpt20]) THEN
        Mapper.Action:=MapActionType (Ord (Key)-Ord (mOpt01)+Ord (matMove));

     BuildActionStr;
     GrayActionFields;
END;


{--------------------------------------------------------------------------}
{ EditMapper                                                               }
{                                                                          }
{ This routine opens up the editor for a map record.                       }
{                                                                          }
PROCEDURE EditMapper;

CONST Xb = 7;
      Yb = 7;
      Xl = 67;
      Yl = 17;

      Xb2 = Xb+15;

VAR FieldY    : XYType;
    ToAkaStr  : STRING[MaxLenFidoAddrString];
    Reason,
    Path      : STRING[80];

BEGIN
     WindowPush (Xb,Yb,Xl,Yl);
     BoxDraw (Double,Xb,Yb,Xl,Yl);

     Mapper.Search:=AddUpWithSpaces (80,Mapper.Search);
     Mapper.ToName:=AddUpWithSpaces (MaxLenUserName,Mapper.ToName);
     Mapper.ToEMail:=AddUpWithSpaces (MaxLenDomain,Mapper.ToEMail);

     ToAkaStr:=AddUpWithSpaces (MaxLenFidoAddrString,Fido2Str (Mapper.ToAka));

     AreaName:=Spaces (MaxLenAreaName);
     Reason:=Spaces (80);
     Path:=Spaces (80);

     CASE Mapper.Action OF
          matSave,
          matToFile :
              Path:=AddUpWithSpaces (80,Mapper.Argument);

          matBounce,
          matBounceAddr :
              Reason:=AddUpWithSpaces (80,Mapper.Argument);

          matMove,
          matCopy :
              AreaName:=AddUpWithSpaces (60,Mapper.Argument);
     END; { case }

     DispArea:=Copy (AreaName,1,50);

     BuildSearchStr;
     BuildActionStr;

     FieldY:=Yb+1;

     FieldInit;

     WriteXY (Xb+2,FieldY,'Search');
     FieldAutoDefineList (Xb2,FieldY,@SearchStr,EditSearchLimit);
     FieldSetHelp (0,htr_EditFilter_Search);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'In/Out');
     FieldAutoDefineToggles (Xb2,FieldY,Mapper.InOut,'inbound|outbound|both',1);
     FieldSetHelp (0,htr_EditFilter_InOut);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Parts');
     FieldAutoDefineToggles (Xb2,FieldY,Mapper.Where,'all|body|header|from|to|subject',0);
     FieldSetHelp (0,htr_EditFilter_Parts);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Search for');
     FieldAutoDefineLongOne (Xb2,FieldY,Xl-Xb2+Xb-2,@Mapper.Search,RepChar (80,'$'));
     FieldSetHelp (0,htr_Editfilter_SearchFor);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Action');
     FieldAutoDefineList (Xb2,FieldY,@ActionStr,EditMapperAction);
     FieldSetHelp (0,htr_EditFilter_Action);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Add note');
     FieldAutoDefineToggles (Xb2,FieldY,Mapper.Note,'no|yes',0);
     FieldSetHelp (0,htr_EditFilter_AddNote);

     Inc (FieldY);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Address type');
     FieldAutoDefineTogglesCall (Xb2,FieldY,Mapper.AddrType,'ftn|rfc|remote gateway',0,GrayAddressFields);
     FieldSetHelp (0,htr_EditFilter_AddressType);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Name');
     FieldAutoDefineOne (Xb2,FieldY,@Mapper.ToName,RepChar (MaxLenUserName,'$'));
     FieldSetHelp (0,htr_EditFilter_Name);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'AKA');
     FieldAutoDefineCheckOne (Xb2,FieldY,@ToAKAStr,RepChar (MaxLenFidoAddrString,'$'),CheckMapperToAka);
     FieldSetHelp (0,htr_EditFilter_AKA);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'E-mail');
     FieldAutoDefineOne (Xb2,FieldY,@Mapper.ToEmail,RepChar (MaxLenDomain,'$'));
     FieldSetHelp (0,htr_EditFilter_Email);

     Inc (FieldY);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Area name');
     FieldAutoDefineList (Xb2,FieldY,@DispArea,SelectMapperAreaName);
     FieldSetHelp (0,htr_EditFilter_AreaName);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Reason');
     FieldAutoDefineLongOne (Xb2,FieldY,Xl-Xb2+Xb-2,@Reason,RepChar (80,'$'));
     FieldSetHelp (0,htr_EditFilter_Reason);

     Inc (FieldY);
     WriteXY (Xb+2,FieldY,'Path');
     FieldAutoDefineFileMgr (Xb2,FieldY,Xl-Xb2+Xb-2,@Path,PathFileMgr,FALSE);
     FieldSetHelp (0,htr_EditFilter_Path);

     GrayActionFields;

     FieldEdit;

     Mapper.Search:=DeleteFrontAndBackSpaces (Mapper.Search);
     Mapper.ToName:=DeleteFrontAndBackSpaces (Mapper.ToName);
     Mapper.ToEmail:=DeleteFrontAndBackSpaces (Mapper.ToEmail);

     FidoSplit (DeleteBackSpaces (ToAkaStr),Mapper.ToAka);

     CASE Mapper.Action OF
          matSave,
          matToFile :
              Mapper.Argument:=DeleteFrontAndBackSpaces (Path);

          matBounce,
          matBounceAddr :
              Mapper.Argument:=DeleteFrontAndBackSpaces (Reason);

          matMove,
          matCopy :
              Mapper.Argument:=DeleteFrontAndBackSpaces (AreaName);
     END; { case }

     IF (Mapper.Search = '') THEN
        Error ('The Text field must not be empty');

     IF (Mapper.Action IN [matBounce,matBounceAddr]) AND
        (Mapper.InOut <> mioInbound) THEN
     BEGIN
          Error ('You might want to limit bounce filters to inbound messages');
     END;

     WindowPop;
END;


{--------------------------------------------------------------------------}
{ EditMappers                                                              }
{                                                                          }
PROCEDURE EditMappers;

{EditMappers}
VAR Keuze  : WORD;
    Quit   : BOOLEAN;
    Pos    : LONGINT;
    Hulp   : STRING;

BEGIN
     ListDefine (3,3,75,Video.Rows-4,TopLeft,
                 'Filter definitions',
                 htr_Filter_Definitions);

     IF Flex_Filter_ReadFirst (Mapper,Pos) THEN
        REPEAT
              Keuze:=ListItemCount;
              ListAddItem (MapDesc,Keuze,Sorted);
              ListSetItemRef (Keuze,Pos);
        UNTIL (NOT Flex_Filter_ReadNext (Mapper,Pos));

     Quit:=FALSE;
     REPEAT
           IF (ListItemCount = 0) THEN
              ListAddItem ('<no filters defined>',65535,Bottom);

           Keuze:=ListSelect (DoTag,[kIns,kDel,kF4]);

           ListRemoveItem (65535);

           CASE Key OF
                kEsc :
                    Quit:=TRUE;

                kIns :
                    BEGIN
                         Flex_Filter_New (Pos,Mapper);
                         EditMapper;
                         Flex_Filter_Write (Pos,Mapper);

                         Keuze:=ListItemCount;
                         ListAddItem (MapDesc,Keuze,Sorted);
                         ListSetItemRef (Keuze,Pos);
                         ListSetCursorOnItem (Keuze);
                    END;

                kRet :
                    IF (ListTagCount = 0) THEN
                    BEGIN
                         Pos:=ListGetItemRef (Keuze);
                         Flex_Filter_Read (Pos,Mapper);

                         Hulp:=MapDesc;

                         EditMapper;
                         Flex_Filter_Write (Pos,Mapper);

                         IF (MapDesc <> Hulp) THEN
                         BEGIN
                              ListRemoveItem (Keuze);
                              ListAddItem (MapDesc,Keuze,Sorted);
                              ListSetItemRef (Keuze,Pos); { !! }
                              ListSetCursorOnItem (Keuze);
                         END;
                    END;

                kDel :
                    IF (ListTagCount > 0) THEN
                    BEGIN
                         MenuDefine (30,10,'Delete all these definitions');
                         MenuAddItem ('Yes');
                         MenuAddItem ('No');
                         MenuShow;
                         MenuSelect;
                         MenuErase;

                         IF (Key = mOpt01) THEN
                            WHILE (ListTagCount > 0) DO
                            BEGIN
                                 Keuze:=ListGetTaggedItemNr (1);
                                 Pos:=ListGetItemRef (Keuze);
                                 Flex_Filter_Erase (Pos);
                                 ListRemoveItem (Keuze);
                            END;
                    END ELSE
                        IF (Keuze <> 65535) THEN
                        BEGIN
                             MenuDefine (30,10,'Are you sure?');
                             MenuAddItem ('Yes, delete this entry');
                             MenuAddItem ('No, keep this entry');
                             MenuShow;
                             MenuSelect;
                             MenuErase;

                             IF (Key = mOpt01) THEN
                             BEGIN
                                  Pos:=ListGetItemRef (Keuze);
                                  Flex_Filter_Erase (Pos);
                                  ListRemoveItem (Keuze);
                             END;
                        END;

                kF4 :
                    BEGIN
                         { copy }
                    END;

           END; { case }

     UNTIL Quit;

     ListErase;
END;

{$ENDIF (WtrConf)}

VAR UpSearch : STRING[80];
    Found    : BOOLEAN;

{--------------------------------------------------------------------------}
{ Mapper_CheckDestRecords                                                  }
{                                                                          }
{ This routine checks all the DestRecords for the search string that now   }
{ in UpSearch (in all upper case) and sets Found to TRUE if there is a     }
{ (partial) match. Both FTN and RFC destinations are checked.              }
{                                                                          }
PROCEDURE Mapper_CheckDestRecords (DoFTN,DoRFC : BOOLEAN);

VAR FindPtr : DestRecordPtr;

BEGIN
     IF Found THEN
        Exit;

     FindPtr:=Msg.FirstDest;
     WHILE (FindPtr <> NIL) DO
     BEGIN
          IF DoFTN THEN
          BEGIN
               IF (Pos (UpSearch,UpCaseString (FindPtr^.ToUser_F)) > 0) OR
                  (Pos (UpSearch,UpCaseString (Fido2Str (FindPtr^.ToAddr_F))) > 0) THEN
               BEGIN
                    Found:=TRUE;
                    Exit;          { ## EXIT ## }
               END;
          END;

          IF DoRFC AND (Pos (UpSearch,UpCaseString (FindPtr^.To_U)) > 0) THEN
          BEGIN
               Found:=TRUE;
               Exit;               { ## EXIT ## }
          END;

          FindPtr:=FindPtr^.NextDest;
     END; { while }
END;


{--------------------------------------------------------------------------}
{ Mapper_Check                                                             }
{                                                                          }
{ This routine is called for each line in either the header, body or       }
{ footer of a message and checks for the instance of Mapper.Search in this }
{ line, case insensitive.                                                  }
{                                                                          }
FUNCTION Mapper_Check (VAR Regel : STRING) : BOOLEAN; FAR;
BEGIN
     IF (Pos (UpSearch,UpCaseString (Regel)) > 0) THEN
        {## add logging? (have to remove #13 from Regel) }
        Found:=TRUE;

     Mapper_Check:=Found;       { abort when found }
END;


{--------------------------------------------------------------------------}
{ AddMapperDest                                                            }
{                                                                          }
{ This routine adds a destination based on the settings in the Mapper      }
{ record. This can be a Netmail, Email or Remote Gateway target.           }
{                                                                          }
PROCEDURE AddMapperDest;
BEGIN
     CASE Mapper.AddrType OF
          madFTN:
              Address_AddFTN (Mapper.ToName,Mapper.ToAka,Mapper.Note,{ByFilter:}TRUE);

          madRFC:
              BEGIN
                   Address_AddRFCRaw (Mapper.ToEmail,destTo,Mapper.Note,{ByFilter:}TRUE);
                   Address_CheckRFCRaw; { get rid of the raw state at once }
              END;

          madRemoteGW:
              Address_AddRemoteGW (Mapper.ToName,Mapper.ToAka,Mapper.ToEmail,Mapper.Note,{ByFilter:}TRUE);
     END;
END;


{--------------------------------------------------------------------------}
{ RemoveAllDestinations                                                    }
{                                                                          }
{ This routine removes all destinations the message is set for and all the }
{ areas it would have been distributed in (so the move/copy area filter    }
{ doesn't trigger in 1000 areas).                                          }
{                                                                          }
PROCEDURE RemoveAllDestinations;

VAR Lp : BYTE;

BEGIN
     MsgsFreeAllDestRecords ({Silent:}FALSE);

     FOR Lp:=1 TO MAX_AREA_CROSS_POSTS DO
     BEGIN
          Msg.AreaRecNrs[Lp]:=NILRecordNr;
          Msg.AreaMsgIds[Lp]:='';
     END;
END;


{--------------------------------------------------------------------------}
{ Mappers_Detect                                                           }
{                                                                          }
{ This routine takes care of finding out which mappers to apply to certain }
{ messages. It currently logs it and things need to change drasticallly so }
{ we can add all possible actions and destinations in one go.              }
{ The Msg structure must contain the message. Only the mappers applicable  }
{ to the current type are checked. Already checked types are not checked   }
{ again after gating.                                                      }
{ This routine is called from MsgsExport and can be called after gating.   }
{ It only checks mappings for a certain format once.                       }
{ Currently, only linear delivery mappers are executed. Duplication        }
{ mappers like CC and Copy are not.                                        }
{                                                                          }
{ The input boolean is to avoid triggering on bounce reasons when bouncing }
{ a message or destroying bounce message because of Delete, Move, Save or  }
{ Forward filters.                                                         }
{                                                                          }
PROCEDURE Mappers_Detect (IsOutbound : BOOLEAN);

VAR DoRFC  : BOOLEAN;
    DoFTN  : BOOLEAN;

    PROCEDURE CheckHeader;
    BEGIN
         IF DoRFC THEN
            MsgsForEach (Msg.HeaderTop_U,Mapper_Check);

         IF DoFTN THEN
         BEGIN
              MsgsForEach (Msg.HeaderTop_F,Mapper_Check);
              {MsgsForEach (Msg.CopiedHeadersTop_F,Mapper_Check);}

              { RAWI981220: not allowing to trigger on AREA: kludge contents for echomail }
              IF (Msg.Ready_F IN [Echomail,Local_Echomail]) THEN
                 Mapper_Check (Msg.Area_F);
         END;

         Mapper_CheckDestRecords (DoFTN,DoRFC);
    END;

{Mappers_Detect}

VAR Limit   : BYTE;
    InOut   : BYTE;
    Pos     : LONGINT;
    Hulp    : STRING[80];
    Stop    : BOOLEAN;
    Lp      : 1..MAX_BODY_PARTS;
    DestPtr : DestRecordPtr;

BEGIN
     Limit:=0;

     IF (Msg.Ready_F IN [Netmail,Local_Netmail]) THEN
        Limit:=mltNetmail
     ELSE
         IF (Msg.Ready_F IN [Echomail,Local_Echomail]) THEN
            Limit:=mltEchomail
         ELSE
             IF (Msg.Ready_U = Mail) THEN
                Limit:=mltEmail
             ELSE
                 IF (Msg.Ready_U = News) THEN
                    Limit:=mltNews;

     IF (Limit = 0) THEN
     BEGIN
          LogMessage (liReport,'[Mappers] Failed to define Limit from '+
                      Byte2String (Byte (Msg.Ready_F))+','+
                      Byte2String (Byte (Msg.Ready_U)));
          Exit;
     END;

     IF IsOutbound THEN
        InOut:=mioOutbound
     ELSE
         InOut:=mioInbound;

     { check if we already checked for this type }
     IF ((Msg.MappersDone AND Limit) = Limit) THEN
        Exit; { already done this type }

     { add to done list }
     Msg.MappersDone:=Msg.MappersDone OR Limit;

     { two boolean for quick decision making on what headers to check }
     DoFTN:=((Limit AND mltFTN) <> 0) AND (Msg.Ready_F <> NotReady);
     DoRFC:=((Limit AND mltRFC) <> 0) AND (Msg.Ready_U <> NotReady);

     { Stop is set to TRUE when an end-point mapper triggers }
     { (delete, save, forward, move)                         }
     Stop:=FALSE;

     { browse the mappers }
     IF (NOT Flex_Filter_ReadFirst (Mapper,Pos)) THEN
        Exit;

     REPEAT
           IF ((Mapper.Limit AND Limit) <> 0) AND (Mapper.Search <> '') THEN
           BEGIN
                UpSearch:=UpCaseString (DeleteFrontAndBackSpaces (Mapper.Search));
                Found:=FALSE;

                IF ((Mapper.InOut AND InOut) <> 0) THEN
                BEGIN
                     { process this mapper }
                     CASE Mapper.Where OF
                          mwtAll: { header, body, footer }
                              BEGIN
                                   FOR Lp:=1 TO MAX_BODY_PARTS DO
                                       MsgsForEach (Msg.BodyParts[Lp],Mapper_Check);

                                   CheckHeader;

                                   IF ((Limit AND mltFTN) <> 0) AND (Msg.Ready_F <> NotReady) THEN
                                      MsgsForEach (Msg.FooterTop_F,Mapper_Check);
                              END;

                          mwtBody: { all body lines }
                              FOR Lp:=1 TO MAX_BODY_PARTS DO
                                  MsgsForEach (Msg.BodyParts[Lp],Mapper_Check);

                          mwtHeader: { all header lines }
                              CheckHeader;

                          mwtFrom: { sender addresses }
                              BEGIN
                                   IF DoRFC THEN
                                   BEGIN
                                        Mapper_Check (Msg.FromUser_U);
                                        Mapper_Check (Msg.Sender_U);
                                        Mapper_Check (Msg.ReplyTo_U);
                                        Mapper_Check (Msg.ApparentlyFrom);
                                   END;

                                   IF DoFTN THEN
                                   BEGIN
                                        Mapper_Check (Msg.FromUser_F);
                                        Hulp:=Fido2Str (Msg.FromAddr_F);
                                        Mapper_Check (Hulp);
                                   END;
                              END;

                          mwtTo: { recipient addresses }
                              BEGIN
                                   Mapper_CheckDestRecords (DoFTN,DoRFC);

                                   IF DoRFC THEN
                                      Mapper_Check (Msg.ApparentlyTo);

                                   IF (Msg.Ready_F = Echomail) THEN
                                      Mapper_Check (Msg.ToUser_F);
                              END;

                          mwtSubject: { subject field only }
                              BEGIN
                                   IF DoRFC THEN
                                      Mapper_Check (Msg.Subj_U);

                                   IF DoFTN THEN
                                      Mapper_Check (Msg.Subj_F);
                              END;
                     END; { case }

                END; { mio check }

                IF Found AND Msg.IsBounceMsg AND (Mapper.Action IN [matBounceAddr,matBounce]) THEN
                   Found:=FALSE;

                IF Found THEN
                BEGIN
                     IF (Msg.ExportAreaRecNr <> NILRecordNr) AND
                        (Msg.ExportAreaRecNr = GetAreaBaseRecordNrByAreaName (Mapper.Argument)) THEN
                           LogMessage (liDebug, 'Skipping Filter (is ExportArea): '+MapDesc)
                     ELSE BEGIN                     
                        LogMessage (liTrivial,'Applying Filter: '+MapDesc);
   
                        Msg.FilterUsed := Mapper.Action;
   
                        CASE Mapper.Action OF
                             matMove:
                                 BEGIN
                                      { remove all other destinations }
                                      RemoveAllDestinations;
   
                                      { add one destination }
                                      Address_AddMoveAreaDest (Mapper.Argument,Mapper.Note);
   
                                      Stop:=TRUE;
                                 END;
   
                             matCopy:
                                 Address_AddCopyAreaDest (Mapper.Argument,Mapper.Note);
   
                             matForward:
                                 BEGIN
                                      { remove all destinations }
                                      RemoveAllDestinations;
   
                                      { add one new destination }
                                      AddMapperDest;
   
                                      Stop:=TRUE;
                                 END;
   
                             matCC:
                                 AddMapperDest;

                             matBounceAddr,
                             matBounce,
                             matDelete,
                             matSave,
                             matToFile :
                                 BEGIN
                                      { handled outside of this function }
                                      Msg.MapperAction:=Mapper.Action;
                                      Msg.MapperPos:=Pos;
                                      Stop:=TRUE;
                                 END;
                        END; { case }
                     END; {exportarearecnr check}
                END;

           END; { if valid mapper }

     UNTIL Stop OR (NOT Flex_Filter_ReadNext (Mapper,Pos));
END;


VAR SaveFile : TEXT;

{--------------------------------------------------------------------------}
{ SaveOneLine                                                              }
{                                                                          }
{ This routine is called for each line that has to be saved to disk.       }
{                                                                          }
FUNCTION SaveOneLine (VAR OrigRegel : STRING) : BOOLEAN; FAR;

VAR Regel : STRING;

BEGIN
     SaveOneLine:=FALSE; { continue }

     Regel:=OrigRegel;

     REPEAT
           IF (Pos (#13,Regel) = 0) THEN
           BEGIN
                Write (SaveFile,Regel);
                Regel:='';
           END ELSE
           BEGIN
                WriteLn (SaveFile,Copy (Regel,1,Pos (#13,Regel)-1));
                Delete (Regel,1,Pos (#13,Regel));
           END;
     UNTIL (Regel = '');
END;


{--------------------------------------------------------------------------}
{ Mappers_SaveMessage                                                      }
{                                                                          }
{ This routine saves a message to disk. This used to be UsenetSaveMessage. }
{                                                                          }
PROCEDURE Mappers_SaveMessage;

VAR Filename : STRING;
    Search   : SearchRec;
    IORes    : BYTE;
    Lp       : 1..MAX_BODY_PARTS;

BEGIN
     Flex_Filter_Read (Msg.MapperPos,Mapper);

     {$IFDEF WtrTest}
     LogMessage (liGeneral,'Target: SAVE to '+Mapper.Argument);
     Exit;
     {$ELSE}

     { schrijf dit bericht nu weg naar een nieuw aan te maken file, }
     { met volgnummers. Probeer een naam en als die al bestaat,     }
     { probeer dan gewoon een andere naam, etc. etc.                }
     REPEAT
           Filename:=Mapper.Argument+GetFidoPktName;
           FindFirst (Filename,saJustFiles,Search);
     UNTIL (DosError <> 0);

     Assign (SaveFile,Filename);
     {$I-} ReWrite (SaveFile); {$I+} IORes:=IOResult;
     IF (IORes <> 0) THEN
     BEGIN
          LogDiskIOError (IORes,'Cannot create SAVE file '+Filename);
          Exit;
     END;

     {$IFDEF LogFileIO}PostOpenT (SaveFile);{$ENDIF}

     LogMessage (liTrivial,'Saving message in '+Filename);

     { aangezien dit alleen vanuit UsenetRouteMail aangeroepen wordt, }
     { hoeven we alleen de Header_U en de Body te dumpen.             }

     IF (Msg.Ready_U <> NotReady) THEN
     BEGIN
          { RFC }
          MsgsForEach (Msg.HeaderTop_U,SaveOneLine);
          FOR Lp:=1 TO MAX_BODY_PARTS DO
              MsgsForEach (Msg.BodyParts[Lp],SaveOneLine);
     END ELSE
     BEGIN
          { FTN }
          MsgsForEach (Msg.HeaderTop_F,SaveOneLine);
          MsgsForEach (Msg.CopiedHeadersTop_F,SaveOneLine);
          FOR Lp:=1 TO MAX_BODY_PARTS DO
              MsgsForEach (Msg.BodyParts[Lp],SaveOneLine);
          MsgsForEach (Msg.FooterTop_F,SaveOneLine);
     END;

     {$IFDEF LogFileIO}PreCloseT (SaveFile);{$ENDIF}
     Close (SaveFile);
     {$ENDIF}
END;


END.
