DEFINITION MODULE SMTPData;

        (********************************************************)
        (*                                                      *)
        (*      Part of the SMTP server - files the mail        *)
        (*                                                      *)
        (*  Programmer:         P. Moylan                       *)
        (*  Started:            27 April 1998                   *)
        (*  Last edited:        25 April 2023                   *)
        (*  Status:             OK                              *)
        (*                                                      *)
        (********************************************************)


FROM SBuffers IMPORT
    (* type *)  SBuffer;

FROM Watchdog IMPORT
    (* type *)  WatchdogID;

FROM TransLog IMPORT
    (* type *)  TransactionLogID;

FROM Domains IMPORT
    (* type *)  Domain;

FROM Sockets IMPORT
    (* type *)  Socket;

FROM Names IMPORT
    (* type *)  UserName, HostName, FilenameString;

(************************************************************************)

TYPE ItemDescriptor;      (* is private *)

(************************************************************************)

PROCEDURE LoadSMTPINIData;

    (* Initial load of configuration data for this module. *)

PROCEDURE UpdateINIData;

    (* Re-reads our INI file to get the options that can be changed     *)
    (* while Weasel is still running.                                   *)

PROCEDURE CreateItemDescriptor (SB: SBuffer;  ClientIPAddress: CARDINAL;
                                 ID: TransactionLogID;  watchID: WatchdogID;
                                  MayRelay, OnWhitelist: BOOLEAN): ItemDescriptor;

    (* Creates a descriptor for a new mail item.  Returns NIL if we     *)
    (* want to reject the client because of an rDNS failure.            *)

PROCEDURE SetAuthenticated (desc: ItemDescriptor;  authenticated: BOOLEAN);

    (* Sets or clears the authenticated flag. *)

PROCEDURE ResetItemDescriptor (desc: ItemDescriptor;
                               ReturnPath: ARRAY OF CHAR);

    (* Discards information related to sender and receivers, deletes    *)
    (* message file if one has been created, and sets a new return path.*)

PROCEDURE ResetReturnPath (desc: ItemDescriptor);

    (* Resets the sender e-mail address, i.e. the address supplied in   *)
    (* the MAIL FROM command.                                           *)

PROCEDURE SetClaimedSendingHost (desc: ItemDescriptor;
                                 VAR (*IN*) ClaimedName: HostName): BOOLEAN;

    (* ClaimedName is the sending host's name as supplied in the HELO   *)
    (* command.  Returns TRUE if name is acceptable.                    *)

PROCEDURE ProcessRCPTAddress (desc: ItemDescriptor;
                                 VAR (*IN*) ToAddress: ARRAY OF CHAR;
                                 VAR (*OUT*) user: UserName;
                                 VAR (*OUT*) domainname: HostName);

    (* Takes note of the destination address as supplied in a RCTP TO:  *)
    (* command, also decomposes it into user and domain components.     *)

PROCEDURE FromAddressAcceptable (desc: ItemDescriptor;  S: Socket;
                               VAR (*OUT*) TempFailure: BOOLEAN): BOOLEAN;

    (* Returns TRUE if we're satisfied with the sender's address as     *)
    (* supplied in MAIL FROM.  If we're not satisfied, we clear that    *)
    (* address as well as returning FALSE.  A result of FALSE with      *)
    (* TempFailure also FALSE means a soft failure, such that the       *)
    (* address might become acceptable on a future attempt.             *)

PROCEDURE SenderNotSpecified (desc: ItemDescriptor): BOOLEAN;

    (* Returns TRUE iff the reverse path is empty. *)

PROCEDURE NoRecipients (desc: ItemDescriptor): BOOLEAN;

    (* Returns TRUE iff the list of recipients is empty. *)

PROCEDURE AddLocalRecipient (desc: ItemDescriptor;  D: Domain;
                           VAR (*IN*) name, host: ARRAY OF CHAR): BOOLEAN;

    (* Adds one local recipient to the list of recipients. *)
    (* Returns FALSE if it's not possible.                 *)

PROCEDURE AddRelayRecipient (desc: ItemDescriptor;
                             VAR (*IN*) name: ARRAY OF CHAR);

    (* Adds one non-local recipient to the list of recipients. *)

PROCEDURE NoChunksYet (desc: ItemDescriptor): BOOLEAN;

    (* Returns TRUE if there is not yet any chunked data. *)

PROCEDURE AcceptChunk (SB: SBuffer;  itemdata: ItemDescriptor;
                         chunksize: CARDINAL;
                         lastchunk: BOOLEAN;
                         VAR (*OUT*) FailureReason: ARRAY OF CHAR): BOOLEAN;

    (* Receives one chunk of an incoming message.  The message is       *)
    (* stored in a temporary file whose name is recorded in itemdata.   *)
    (* We periodically kick the watchdog to confirm that the reception  *)
    (* has not timed out.                                               *)

PROCEDURE IgnoreChunk (SB: SBuffer;  size: CARDINAL);

    (* Reads 'size' bytes from the input channel without storing them.  *)
    (* This is for the case where there has been an error but the       *)
    (* sender does not yet know that anything is wrong.                 *)

PROCEDURE AcceptMessage (SB: SBuffer;  itemdata: ItemDescriptor;
                         VAR (*OUT*) FailureReason: ARRAY OF CHAR): BOOLEAN;

    (* Receives an incoming message, stores it in a temporary file      *)
    (* whose name is recorded in itemdata.  We periodically signal on   *)
    (* sem to confirm that the reception has not timed out.             *)

PROCEDURE LimitOnMessageSize(): CARDINAL;

    (* Max allowable number of bytes in a message. *)

    (********************************************************************)
    (*                         FILTER RULES                             *)
    (*                                                                  *)
    (* The filter procedures below may be invoked at several stages:    *)
    (*                                                                  *)
    (*    0    on initial connection                                    *)
    (*    1    after the HELO or EHLO command                           *)
    (*    2    after the MAIL FROM command                              *)
    (*    3    when the DATA command has been received, but before the  *)
    (*           message has been transmitted.                          *)
    (*    4    after a mail item has been received but before it has    *)
    (*           been distributed to the addressees.                    *)
    (*                                                                  *)
    (* A filter is allowed to return the following codes:               *)
    (*                                                                  *)
    (*    0    continue processing normally, i.e. deliver mail          *)
    (*    1    like 0, but the filter has modified the list of          *)
    (*         recipients.                                              *)
    (*    2    item has now been dealt with, report success to sender   *)
    (*    3    reject the message                                       *)
    (*    4    like 3, but the filter has placed a failure message into *)
    (*           the first line of the 'recipients' file.               *)
    (*  5-15   unused, reserved for future use.                         *)
    (*   16    like 0, but in addition future filtering steps will be   *)
    (*           bypassed for this item of mail.                        *)
    (*                                                                  *)
    (* As a guard against errors in the filters, unused codes are       *)
    (* converted to 0.                                                  *)
    (*                                                                  *)
    (* Note that cases 1, 4, and 16 are dealt with internally in        *)
    (* this procedure, so this procedure will only ever return a        *)
    (* result of 0, 2, or 3.  Furthermore, code 2 should never occur    *)
    (* at stage 0, 1, 2, or 3.                                          *)
    (*                                                                  *)
    (* In case 3, FailureMessage holds the reply (starting with a       *)
    (* three-digit code) to be returned to the sender.                  *)
    (********************************************************************)

PROCEDURE RunFilter03 (stage: CARDINAL;  itemdata: ItemDescriptor;
                     VAR (*OUT*) FailureMessage: ARRAY OF CHAR): CARDINAL;

    (* The filters for stages 0 to 3. *)

PROCEDURE FilterAndDistribute (itemdata: ItemDescriptor;  SB: SBuffer): BOOLEAN;

    (* Runs the final (stage 4) filter on this message, and then        *)
    (* delivers it unless the filter says not to.  Returns FALSE if the *)
    (* filter has rejected the message for all recipients.              *)

PROCEDURE DiscardItemDescriptor (VAR (*INOUT*) desc: ItemDescriptor);

    (* Destroys the descriptor, and deletes the message file if one     *)
    (* has been created.                                                *)

END SMTPData.

