1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
use bitflags::bitflags;
use milter_sys as sys;

bitflags! {
    /// Flags representing milter actions.
    ///
    /// # Examples
    ///
    /// ```
    /// # use milter::Actions;
    /// let header_actions = Actions::ADD_HEADER | Actions::REPLACE_HEADER;
    /// ```
    #[derive(Default)]
    pub struct Actions: u64 {
        /// Set requested macros.
        ///
        /// This flag enables the [`Context::set_requested_macros`] method.
        ///
        /// [`Context::set_requested_macros`]: struct.Context.html#method.set_requested_macros
        const SET_REQUESTED_MACROS = sys::SMFIF_SETSYMLIST;

        /// Replace the envelope sender (`MAIL FROM` address) of a message.
        ///
        /// This flag enables the [`ActionContext::replace_sender`] action.
        ///
        /// [`ActionContext::replace_sender`]: struct.ActionContext.html#method.replace_sender
        const REPLACE_SENDER = sys::SMFIF_CHGFROM;
        /// Add an envelope recipient (`RCPT TO` address) for a message.
        ///
        /// Together with [`ADD_RECIPIENT_EXT`], this flag enables the
        /// [`ActionContext::add_recipient`] action.
        ///
        /// [`ADD_RECIPIENT_EXT`]: #associatedconstant.ADD_RECIPIENT_EXT
        /// [`ActionContext::add_recipient`]: struct.ActionContext.html#method.add_recipient
        const ADD_RECIPIENT = sys::SMFIF_ADDRCPT;
        /// Add an envelope recipient (`RCPT TO` address) for a message,
        /// including ESMTP arguments.
        ///
        /// Together with [`ADD_RECIPIENT`], this flag enables the
        /// [`ActionContext::add_recipient`] action.
        ///
        /// [`ADD_RECIPIENT`]: #associatedconstant.ADD_RECIPIENT
        /// [`ActionContext::add_recipient`]: struct.ActionContext.html#method.add_recipient
        const ADD_RECIPIENT_EXT = sys::SMFIF_ADDRCPT_PAR;
        /// Remove an envelope recipient (`RCPT TO` address) from a message.
        ///
        /// This flag enables the [`ActionContext::remove_recipient`] action.
        ///
        /// [`ActionContext::remove_recipient`]: struct.ActionContext.html#method.remove_recipient
        const REMOVE_RECIPIENT = sys::SMFIF_DELRCPT;
        /// Add a header to a message.
        ///
        /// This flag enables the [`ActionContext::add_header`] and
        /// [`ActionContext::insert_header`] actions.
        ///
        /// [`ActionContext::add_header`]: struct.ActionContext.html#method.add_header
        /// [`ActionContext::insert_header`]: struct.ActionContext.html#method.insert_header
        const ADD_HEADER = sys::SMFIF_ADDHDRS;
        /// Replace a header of a message.
        ///
        /// This flag enables the [`ActionContext::replace_header`] action.
        ///
        /// [`ActionContext::replace_header`]: struct.ActionContext.html#method.replace_header
        const REPLACE_HEADER = sys::SMFIF_CHGHDRS;
        /// Replace the body of a message.
        ///
        /// This flag enables the [`ActionContext::append_body_chunk`] action.
        ///
        /// [`ActionContext::append_body_chunk`]: struct.ActionContext.html#method.append_body_chunk
        const REPLACE_BODY = sys::SMFIF_CHGBODY;
        /// Quarantine a message.
        ///
        /// This flag enables the [`ActionContext::quarantine`] action.
        ///
        /// [`ActionContext::quarantine`]: struct.ActionContext.html#method.quarantine
        const QUARANTINE = sys::SMFIF_QUARANTINE;
    }
}

bitflags! {
    /// Flags representing milter protocol options.
    ///
    /// These flags are used during [negotiation]. There are two facets to their
    /// meaning: `ProtocolOpts` flags denote either what the MTA can do (MTA
    /// advertises capabilities), or what the milter application wants to do
    /// (milter requests capabilities).
    ///
    /// [negotiation]: https://docs.rs/milter-callback/0.1.5/milter_callback/attr.on_negotiate.html
    #[derive(Default)]
    pub struct ProtocolOpts: u64 {
        /// Do not use the `connect` stage callback.
        const NO_CONNECT = sys::SMFIP_NOCONNECT;
        /// Do not use the `helo` stage callback.
        const NO_HELO = sys::SMFIP_NOHELO;
        /// Do not use the `mail` stage callback.
        const NO_MAIL = sys::SMFIP_NOMAIL;
        /// Do not use the `rcpt` stage callback.
        const NO_RCPT = sys::SMFIP_NORCPT;
        /// Do not use the `data` stage callback.
        const NO_DATA = sys::SMFIP_NODATA;
        /// Do not use the `header` stage callback.
        const NO_HEADER = sys::SMFIP_NOHDRS;
        /// Do not use the `eoh` stage callback.
        const NO_EOH = sys::SMFIP_NOEOH;
        /// Do not use the `body` stage callback.
        const NO_BODY = sys::SMFIP_NOBODY;
        /// Do not use the `unknown` stage callback.
        const NO_UNKNOWN = sys::SMFIP_NOUNKNOWN;

        /// Allow skipping further (repeated) calls to the same callback.
        const SKIP = sys::SMFIP_SKIP;

        /// Also send rejected envelope recipients.
        const REJECTED_RCPT = sys::SMFIP_RCPT_REJ;

        /// Respond with [`Noreply`] in the `connect` stage.
        ///
        /// [`Noreply`]: enum.Status.html#variant.Noreply
        const NOREPLY_CONNECT = sys::SMFIP_NR_CONN;
        /// Respond with [`Noreply`] in the `helo` stage.
        ///
        /// [`Noreply`]: enum.Status.html#variant.Noreply
        const NOREPLY_HELO = sys::SMFIP_NR_HELO;
        /// Respond with [`Noreply`] in the `mail` stage.
        ///
        /// [`Noreply`]: enum.Status.html#variant.Noreply
        const NOREPLY_MAIL = sys::SMFIP_NR_MAIL;
        /// Respond with [`Noreply`] in the `rcpt` stage.
        ///
        /// [`Noreply`]: enum.Status.html#variant.Noreply
        const NOREPLY_RCPT = sys::SMFIP_NR_RCPT;
        /// Respond with [`Noreply`] in the `data` stage.
        ///
        /// [`Noreply`]: enum.Status.html#variant.Noreply
        const NOREPLY_DATA = sys::SMFIP_NR_DATA;
        /// Respond with [`Noreply`] in the `header` stage.
        ///
        /// [`Noreply`]: enum.Status.html#variant.Noreply
        const NOREPLY_HEADER = sys::SMFIP_NR_HDR;
        /// Respond with [`Noreply`] in the `eoh` stage.
        ///
        /// [`Noreply`]: enum.Status.html#variant.Noreply
        const NOREPLY_EOH = sys::SMFIP_NR_EOH;
        /// Respond with [`Noreply`] in the `body` stage.
        ///
        /// [`Noreply`]: enum.Status.html#variant.Noreply
        const NOREPLY_BODY = sys::SMFIP_NR_BODY;
        /// Respond with [`Noreply`] in the `unknown` stage.
        ///
        /// [`Noreply`]: enum.Status.html#variant.Noreply
        const NOREPLY_UNKNOWN = sys::SMFIP_NR_UNKN;

        /// Neither trim nor add leading space in header values.
        ///
        /// Header lines in the canonical form `Name: Value` include leading
        /// whitespace in the header value, which is stripped by default (or
        /// added when [adding headers]). With this option that leading space is
        /// kept exactly as given.
        ///
        /// [adding headers]: struct.ActionContext.html#method.add_header
        const HEADER_LEADING_SPACE = sys::SMFIP_HDR_LEADSPC;
    }
}

/// Milter protocol stage.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Stage {
    /// The `connect` stage.
    Connect = 0,
    /// The `helo` stage.
    Helo = 1,
    /// The `mail` stage.
    Mail = 2,
    /// The `rcpt` stage.
    Rcpt = 3,
    /// The `data` stage.
    Data = 4,
    /// The `eoh` stage.
    Eoh = 6,
    /// The `eom` stage.
    Eom = 5,
}

/// Callback response status.
///
/// A response status is returned from all milter callbacks. It controls whether
/// and how processing of some entity is to proceed; ‘entity’ signifies either
/// connection, message, or recipient, according to which protocol stage the
/// status is returned from.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Status {
    /// Proceed to the next stage. This is the neutral, default response.
    Continue = 0,
    /// Reject the entity being processed.
    Reject = 1,
    /// Reject the entity being processed with a temporary failure (client may
    /// retry).
    Tempfail = 4,
    /// Accept the entity being processed but discard the message.
    Discard = 2,
    /// Accept the entity being processed.
    Accept = 3,
    /// Do not send a reply. When negotiated for a particular stage, this status
    /// must always be used.
    ///
    /// This status is only available if it has been [negotiated] beforehand.
    ///
    /// [negotiated]: struct.Milter.html#method.on_negotiate
    Noreply = 7,
    /// Skip further (repeated) calls to this callback. This is useful in the
    /// `body` stage, where potentially costly transmission of body content may
    /// be cut short once the milter has received enough data.
    ///
    /// This status is only available if it has been [negotiated] beforehand.
    ///
    /// [negotiated]: struct.Milter.html#method.on_negotiate
    Skip = 8,

    /// A special status indication used only in [negotiation]: enable all
    /// [`ProtocolOpts`] the MTA has to offer.
    ///
    /// [negotiation]: struct.Milter.html#method.on_negotiate
    /// [`ProtocolOpts`]: struct.ProtocolOpts.html
    AllOpts = 10,
}

impl Default for Status {
    fn default() -> Self {
        Self::Continue
    }
}