diff options
| -rw-r--r-- | milter_api-set_reply.adb | 1467 | ||||
| -rw-r--r-- | milter_api.adb | 498 | ||||
| -rw-r--r-- | milter_api.ads | 326 | ||||
| -rw-r--r-- | sockaddr_functions.c | 68 | 
4 files changed, 2229 insertions, 130 deletions
| diff --git a/milter_api-set_reply.adb b/milter_api-set_reply.adb new file mode 100644 index 0000000..066c971 --- /dev/null +++ b/milter_api-set_reply.adb @@ -0,0 +1,1467 @@ +-- Ada Milter API, a binding to Libmilter, the Sendmail mail filtering API +-- Copyright 2009 B. Persson, Bjorn@Rombobeorn.se +-- +-- This library is free software: you can redistribute it and/or modify it +-- under the terms of the GNU General Public License version 3, as published +-- by the Free Software Foundation. + + +separate(Milter_API) +procedure Set_Reply +   (Context       : SMFICTX_Pointer; +    Reply_Code    : String_Of_Three; +    Extended_Code : String := ""; +    Message       : Reply_Lines) +is + +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       line_10 : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       line_10 : chars_ptr; +       line_11 : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       line_10 : chars_ptr; +       line_11 : chars_ptr; +       line_12 : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       line_10 : chars_ptr; +       line_11 : chars_ptr; +       line_12 : chars_ptr; +       line_13 : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       line_10 : chars_ptr; +       line_11 : chars_ptr; +       line_12 : chars_ptr; +       line_13 : chars_ptr; +       line_14 : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       line_10 : chars_ptr; +       line_11 : chars_ptr; +       line_12 : chars_ptr; +       line_13 : chars_ptr; +       line_14 : chars_ptr; +       line_15 : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       line_10 : chars_ptr; +       line_11 : chars_ptr; +       line_12 : chars_ptr; +       line_13 : chars_ptr; +       line_14 : chars_ptr; +       line_15 : chars_ptr; +       line_16 : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       line_10 : chars_ptr; +       line_11 : chars_ptr; +       line_12 : chars_ptr; +       line_13 : chars_ptr; +       line_14 : chars_ptr; +       line_15 : chars_ptr; +       line_16 : chars_ptr; +       line_17 : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       line_10 : chars_ptr; +       line_11 : chars_ptr; +       line_12 : chars_ptr; +       line_13 : chars_ptr; +       line_14 : chars_ptr; +       line_15 : chars_ptr; +       line_16 : chars_ptr; +       line_17 : chars_ptr; +       line_18 : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       line_10 : chars_ptr; +       line_11 : chars_ptr; +       line_12 : chars_ptr; +       line_13 : chars_ptr; +       line_14 : chars_ptr; +       line_15 : chars_ptr; +       line_16 : chars_ptr; +       line_17 : chars_ptr; +       line_18 : chars_ptr; +       line_19 : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       line_10 : chars_ptr; +       line_11 : chars_ptr; +       line_12 : chars_ptr; +       line_13 : chars_ptr; +       line_14 : chars_ptr; +       line_15 : chars_ptr; +       line_16 : chars_ptr; +       line_17 : chars_ptr; +       line_18 : chars_ptr; +       line_19 : chars_ptr; +       line_20 : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       line_10 : chars_ptr; +       line_11 : chars_ptr; +       line_12 : chars_ptr; +       line_13 : chars_ptr; +       line_14 : chars_ptr; +       line_15 : chars_ptr; +       line_16 : chars_ptr; +       line_17 : chars_ptr; +       line_18 : chars_ptr; +       line_19 : chars_ptr; +       line_20 : chars_ptr; +       line_21 : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       line_10 : chars_ptr; +       line_11 : chars_ptr; +       line_12 : chars_ptr; +       line_13 : chars_ptr; +       line_14 : chars_ptr; +       line_15 : chars_ptr; +       line_16 : chars_ptr; +       line_17 : chars_ptr; +       line_18 : chars_ptr; +       line_19 : chars_ptr; +       line_20 : chars_ptr; +       line_21 : chars_ptr; +       line_22 : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       line_10 : chars_ptr; +       line_11 : chars_ptr; +       line_12 : chars_ptr; +       line_13 : chars_ptr; +       line_14 : chars_ptr; +       line_15 : chars_ptr; +       line_16 : chars_ptr; +       line_17 : chars_ptr; +       line_18 : chars_ptr; +       line_19 : chars_ptr; +       line_20 : chars_ptr; +       line_21 : chars_ptr; +       line_22 : chars_ptr; +       line_23 : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       line_10 : chars_ptr; +       line_11 : chars_ptr; +       line_12 : chars_ptr; +       line_13 : chars_ptr; +       line_14 : chars_ptr; +       line_15 : chars_ptr; +       line_16 : chars_ptr; +       line_17 : chars_ptr; +       line_18 : chars_ptr; +       line_19 : chars_ptr; +       line_20 : chars_ptr; +       line_21 : chars_ptr; +       line_22 : chars_ptr; +       line_23 : chars_ptr; +       line_24 : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       line_10 : chars_ptr; +       line_11 : chars_ptr; +       line_12 : chars_ptr; +       line_13 : chars_ptr; +       line_14 : chars_ptr; +       line_15 : chars_ptr; +       line_16 : chars_ptr; +       line_17 : chars_ptr; +       line_18 : chars_ptr; +       line_19 : chars_ptr; +       line_20 : chars_ptr; +       line_21 : chars_ptr; +       line_22 : chars_ptr; +       line_23 : chars_ptr; +       line_24 : chars_ptr; +       line_25 : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       line_10 : chars_ptr; +       line_11 : chars_ptr; +       line_12 : chars_ptr; +       line_13 : chars_ptr; +       line_14 : chars_ptr; +       line_15 : chars_ptr; +       line_16 : chars_ptr; +       line_17 : chars_ptr; +       line_18 : chars_ptr; +       line_19 : chars_ptr; +       line_20 : chars_ptr; +       line_21 : chars_ptr; +       line_22 : chars_ptr; +       line_23 : chars_ptr; +       line_24 : chars_ptr; +       line_25 : chars_ptr; +       line_26 : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       line_10 : chars_ptr; +       line_11 : chars_ptr; +       line_12 : chars_ptr; +       line_13 : chars_ptr; +       line_14 : chars_ptr; +       line_15 : chars_ptr; +       line_16 : chars_ptr; +       line_17 : chars_ptr; +       line_18 : chars_ptr; +       line_19 : chars_ptr; +       line_20 : chars_ptr; +       line_21 : chars_ptr; +       line_22 : chars_ptr; +       line_23 : chars_ptr; +       line_24 : chars_ptr; +       line_25 : chars_ptr; +       line_26 : chars_ptr; +       line_27 : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       line_10 : chars_ptr; +       line_11 : chars_ptr; +       line_12 : chars_ptr; +       line_13 : chars_ptr; +       line_14 : chars_ptr; +       line_15 : chars_ptr; +       line_16 : chars_ptr; +       line_17 : chars_ptr; +       line_18 : chars_ptr; +       line_19 : chars_ptr; +       line_20 : chars_ptr; +       line_21 : chars_ptr; +       line_22 : chars_ptr; +       line_23 : chars_ptr; +       line_24 : chars_ptr; +       line_25 : chars_ptr; +       line_26 : chars_ptr; +       line_27 : chars_ptr; +       line_28 : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       line_10 : chars_ptr; +       line_11 : chars_ptr; +       line_12 : chars_ptr; +       line_13 : chars_ptr; +       line_14 : chars_ptr; +       line_15 : chars_ptr; +       line_16 : chars_ptr; +       line_17 : chars_ptr; +       line_18 : chars_ptr; +       line_19 : chars_ptr; +       line_20 : chars_ptr; +       line_21 : chars_ptr; +       line_22 : chars_ptr; +       line_23 : chars_ptr; +       line_24 : chars_ptr; +       line_25 : chars_ptr; +       line_26 : chars_ptr; +       line_27 : chars_ptr; +       line_28 : chars_ptr; +       line_29 : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       line_10 : chars_ptr; +       line_11 : chars_ptr; +       line_12 : chars_ptr; +       line_13 : chars_ptr; +       line_14 : chars_ptr; +       line_15 : chars_ptr; +       line_16 : chars_ptr; +       line_17 : chars_ptr; +       line_18 : chars_ptr; +       line_19 : chars_ptr; +       line_20 : chars_ptr; +       line_21 : chars_ptr; +       line_22 : chars_ptr; +       line_23 : chars_ptr; +       line_24 : chars_ptr; +       line_25 : chars_ptr; +       line_26 : chars_ptr; +       line_27 : chars_ptr; +       line_28 : chars_ptr; +       line_29 : chars_ptr; +       line_30 : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       line_10 : chars_ptr; +       line_11 : chars_ptr; +       line_12 : chars_ptr; +       line_13 : chars_ptr; +       line_14 : chars_ptr; +       line_15 : chars_ptr; +       line_16 : chars_ptr; +       line_17 : chars_ptr; +       line_18 : chars_ptr; +       line_19 : chars_ptr; +       line_20 : chars_ptr; +       line_21 : chars_ptr; +       line_22 : chars_ptr; +       line_23 : chars_ptr; +       line_24 : chars_ptr; +       line_25 : chars_ptr; +       line_26 : chars_ptr; +       line_27 : chars_ptr; +       line_28 : chars_ptr; +       line_29 : chars_ptr; +       line_30 : chars_ptr; +       line_31 : chars_ptr; +       stop    : chars_ptr) +      return int; +   function smfi_setmlreply +      (ctx     : SMFICTX_Pointer; +       rcode   : char_array; +       xcode   : chars_ptr; +       line_1  : chars_ptr; +       line_2  : chars_ptr; +       line_3  : chars_ptr; +       line_4  : chars_ptr; +       line_5  : chars_ptr; +       line_6  : chars_ptr; +       line_7  : chars_ptr; +       line_8  : chars_ptr; +       line_9  : chars_ptr; +       line_10 : chars_ptr; +       line_11 : chars_ptr; +       line_12 : chars_ptr; +       line_13 : chars_ptr; +       line_14 : chars_ptr; +       line_15 : chars_ptr; +       line_16 : chars_ptr; +       line_17 : chars_ptr; +       line_18 : chars_ptr; +       line_19 : chars_ptr; +       line_20 : chars_ptr; +       line_21 : chars_ptr; +       line_22 : chars_ptr; +       line_23 : chars_ptr; +       line_24 : chars_ptr; +       line_25 : chars_ptr; +       line_26 : chars_ptr; +       line_27 : chars_ptr; +       line_28 : chars_ptr; +       line_29 : chars_ptr; +       line_30 : chars_ptr; +       line_31 : chars_ptr; +       line_32 : chars_ptr; +       stop    : chars_ptr) +      return int; +   pragma import(C, smfi_setmlreply); + +   C_Reply_Code      : aliased char_array := To_C(Reply_Code); +   C_Extended_Code   : aliased char_array := To_C(Extended_Code); +   Extended_Code_Ptr : chars_ptr := Null_Ptr; + +   subtype Reply_Line_Count is Natural range 0 .. Reply_Line_Index'Last; +   Line_Count : constant Reply_Line_Count := Message'Last - Message'First + 1; +   C_Message  : array(1 .. Line_Count) of chars_ptr; + +   Result : int; + +begin + +   if Extended_Code'Length > 0 then +      Extended_Code_Ptr := To_Chars_Ptr(C_Extended_Code'Unchecked_Access); +   end if; + +   for Index in C_Message'Range loop +      C_Message(Index) := New_String(To_String(Message(Message'First + Index - 1))); +   end loop; + +   case Line_Count is +      when 0 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   Null_Ptr); +      when 1 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   Null_Ptr); +      when 2 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   Null_Ptr); +      when 3 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   Null_Ptr); +      when 4 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   Null_Ptr); +      when 5 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   Null_Ptr); +      when 6 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   Null_Ptr); +      when 7 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   Null_Ptr); +      when 8 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   Null_Ptr); +      when 9 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   Null_Ptr); +      when 10 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   C_Message(10), +                                   Null_Ptr); +      when 11 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   C_Message(10), +                                   C_Message(11), +                                   Null_Ptr); +      when 12 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   C_Message(10), +                                   C_Message(11), +                                   C_Message(12), +                                   Null_Ptr); +      when 13 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   C_Message(10), +                                   C_Message(11), +                                   C_Message(12), +                                   C_Message(13), +                                   Null_Ptr); +      when 14 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   C_Message(10), +                                   C_Message(11), +                                   C_Message(12), +                                   C_Message(13), +                                   C_Message(14), +                                   Null_Ptr); +      when 15 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   C_Message(10), +                                   C_Message(11), +                                   C_Message(12), +                                   C_Message(13), +                                   C_Message(14), +                                   C_Message(15), +                                   Null_Ptr); +      when 16 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   C_Message(10), +                                   C_Message(11), +                                   C_Message(12), +                                   C_Message(13), +                                   C_Message(14), +                                   C_Message(15), +                                   C_Message(16), +                                   Null_Ptr); +      when 17 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   C_Message(10), +                                   C_Message(11), +                                   C_Message(12), +                                   C_Message(13), +                                   C_Message(14), +                                   C_Message(15), +                                   C_Message(16), +                                   C_Message(17), +                                   Null_Ptr); +      when 18 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   C_Message(10), +                                   C_Message(11), +                                   C_Message(12), +                                   C_Message(13), +                                   C_Message(14), +                                   C_Message(15), +                                   C_Message(16), +                                   C_Message(17), +                                   C_Message(18), +                                   Null_Ptr); +      when 19 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   C_Message(10), +                                   C_Message(11), +                                   C_Message(12), +                                   C_Message(13), +                                   C_Message(14), +                                   C_Message(15), +                                   C_Message(16), +                                   C_Message(17), +                                   C_Message(18), +                                   C_Message(19), +                                   Null_Ptr); +      when 20 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   C_Message(10), +                                   C_Message(11), +                                   C_Message(12), +                                   C_Message(13), +                                   C_Message(14), +                                   C_Message(15), +                                   C_Message(16), +                                   C_Message(17), +                                   C_Message(18), +                                   C_Message(19), +                                   C_Message(20), +                                   Null_Ptr); +      when 21 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   C_Message(10), +                                   C_Message(11), +                                   C_Message(12), +                                   C_Message(13), +                                   C_Message(14), +                                   C_Message(15), +                                   C_Message(16), +                                   C_Message(17), +                                   C_Message(18), +                                   C_Message(19), +                                   C_Message(20), +                                   C_Message(21), +                                   Null_Ptr); +      when 22 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   C_Message(10), +                                   C_Message(11), +                                   C_Message(12), +                                   C_Message(13), +                                   C_Message(14), +                                   C_Message(15), +                                   C_Message(16), +                                   C_Message(17), +                                   C_Message(18), +                                   C_Message(19), +                                   C_Message(20), +                                   C_Message(21), +                                   C_Message(22), +                                   Null_Ptr); +      when 23 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   C_Message(10), +                                   C_Message(11), +                                   C_Message(12), +                                   C_Message(13), +                                   C_Message(14), +                                   C_Message(15), +                                   C_Message(16), +                                   C_Message(17), +                                   C_Message(18), +                                   C_Message(19), +                                   C_Message(20), +                                   C_Message(21), +                                   C_Message(22), +                                   C_Message(23), +                                   Null_Ptr); +      when 24 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   C_Message(10), +                                   C_Message(11), +                                   C_Message(12), +                                   C_Message(13), +                                   C_Message(14), +                                   C_Message(15), +                                   C_Message(16), +                                   C_Message(17), +                                   C_Message(18), +                                   C_Message(19), +                                   C_Message(20), +                                   C_Message(21), +                                   C_Message(22), +                                   C_Message(23), +                                   C_Message(24), +                                   Null_Ptr); +      when 25 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   C_Message(10), +                                   C_Message(11), +                                   C_Message(12), +                                   C_Message(13), +                                   C_Message(14), +                                   C_Message(15), +                                   C_Message(16), +                                   C_Message(17), +                                   C_Message(18), +                                   C_Message(19), +                                   C_Message(20), +                                   C_Message(21), +                                   C_Message(22), +                                   C_Message(23), +                                   C_Message(24), +                                   C_Message(25), +                                   Null_Ptr); +      when 26 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   C_Message(10), +                                   C_Message(11), +                                   C_Message(12), +                                   C_Message(13), +                                   C_Message(14), +                                   C_Message(15), +                                   C_Message(16), +                                   C_Message(17), +                                   C_Message(18), +                                   C_Message(19), +                                   C_Message(20), +                                   C_Message(21), +                                   C_Message(22), +                                   C_Message(23), +                                   C_Message(24), +                                   C_Message(25), +                                   C_Message(26), +                                   Null_Ptr); +      when 27 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   C_Message(10), +                                   C_Message(11), +                                   C_Message(12), +                                   C_Message(13), +                                   C_Message(14), +                                   C_Message(15), +                                   C_Message(16), +                                   C_Message(17), +                                   C_Message(18), +                                   C_Message(19), +                                   C_Message(20), +                                   C_Message(21), +                                   C_Message(22), +                                   C_Message(23), +                                   C_Message(24), +                                   C_Message(25), +                                   C_Message(26), +                                   C_Message(27), +                                   Null_Ptr); +      when 28 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   C_Message(10), +                                   C_Message(11), +                                   C_Message(12), +                                   C_Message(13), +                                   C_Message(14), +                                   C_Message(15), +                                   C_Message(16), +                                   C_Message(17), +                                   C_Message(18), +                                   C_Message(19), +                                   C_Message(20), +                                   C_Message(21), +                                   C_Message(22), +                                   C_Message(23), +                                   C_Message(24), +                                   C_Message(25), +                                   C_Message(26), +                                   C_Message(27), +                                   C_Message(28), +                                   Null_Ptr); +      when 29 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   C_Message(10), +                                   C_Message(11), +                                   C_Message(12), +                                   C_Message(13), +                                   C_Message(14), +                                   C_Message(15), +                                   C_Message(16), +                                   C_Message(17), +                                   C_Message(18), +                                   C_Message(19), +                                   C_Message(20), +                                   C_Message(21), +                                   C_Message(22), +                                   C_Message(23), +                                   C_Message(24), +                                   C_Message(25), +                                   C_Message(26), +                                   C_Message(27), +                                   C_Message(28), +                                   C_Message(29), +                                   Null_Ptr); +      when 30 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   C_Message(10), +                                   C_Message(11), +                                   C_Message(12), +                                   C_Message(13), +                                   C_Message(14), +                                   C_Message(15), +                                   C_Message(16), +                                   C_Message(17), +                                   C_Message(18), +                                   C_Message(19), +                                   C_Message(20), +                                   C_Message(21), +                                   C_Message(22), +                                   C_Message(23), +                                   C_Message(24), +                                   C_Message(25), +                                   C_Message(26), +                                   C_Message(27), +                                   C_Message(28), +                                   C_Message(29), +                                   C_Message(30), +                                   Null_Ptr); +      when 31 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   C_Message(10), +                                   C_Message(11), +                                   C_Message(12), +                                   C_Message(13), +                                   C_Message(14), +                                   C_Message(15), +                                   C_Message(16), +                                   C_Message(17), +                                   C_Message(18), +                                   C_Message(19), +                                   C_Message(20), +                                   C_Message(21), +                                   C_Message(22), +                                   C_Message(23), +                                   C_Message(24), +                                   C_Message(25), +                                   C_Message(26), +                                   C_Message(27), +                                   C_Message(28), +                                   C_Message(29), +                                   C_Message(30), +                                   C_Message(31), +                                   Null_Ptr); +      when 32 => +         Result := smfi_setmlreply(Context, +                                   C_Reply_Code, +                                   Extended_Code_Ptr, +                                   C_Message(1), +                                   C_Message(2), +                                   C_Message(3), +                                   C_Message(4), +                                   C_Message(5), +                                   C_Message(6), +                                   C_Message(7), +                                   C_Message(8), +                                   C_Message(9), +                                   C_Message(10), +                                   C_Message(11), +                                   C_Message(12), +                                   C_Message(13), +                                   C_Message(14), +                                   C_Message(15), +                                   C_Message(16), +                                   C_Message(17), +                                   C_Message(18), +                                   C_Message(19), +                                   C_Message(20), +                                   C_Message(21), +                                   C_Message(22), +                                   C_Message(23), +                                   C_Message(24), +                                   C_Message(25), +                                   C_Message(26), +                                   C_Message(27), +                                   C_Message(28), +                                   C_Message(29), +                                   C_Message(30), +                                   C_Message(31), +                                   C_Message(32), +                                   Null_Ptr); +   end case; + +   for Index in C_Message'Range loop +      Free(C_Message(Index)); +   end loop; + +   Check_For_Error("smfi_setmlreply", Result); + +end Set_Reply; diff --git a/milter_api.adb b/milter_api.adb index 68f9bcb..e8f02d3 100644 --- a/milter_api.adb +++ b/milter_api.adb @@ -1,5 +1,5 @@ --- Milter API for Ada, a binding to Libmilter, the Sendmail mail filtering API --- Copyright 2009 B. Persson, Bjorn@Rombobeorn.se +-- Ada Milter API, a binding to Libmilter, the Sendmail mail filtering API +-- Copyright 2009 - 2012 B. Persson, Bjorn@Rombobeorn.se  --  -- This library is free software: you can redistribute it and/or modify it  -- under the terms of the GNU General Public License version 3, as published @@ -7,19 +7,17 @@  with Ada.Exceptions; use Ada.Exceptions; -with Ada.Strings.Fixed;  with System_Log; use System_Log; +with Ada.Strings.Fixed;  package body Milter_API is -   pragma Linker_Options("-lmilter"); -   pragma Linker_Options("-lpthread"); -     use Ada.Strings.Unbounded;     use type String_Arrays.Pointer; +   use Interfaces; -   Version : constant Binding_Version_Type := (1, 2, 1); +   Version : constant Binding_Version_Type := (2, 1, 1);     function Binding_Version return Binding_Version_Type is     begin @@ -34,23 +32,88 @@ package body Milter_API is               Trim(Version.Implementation'Img, Left);     end Binding_Version_String; -   Target_Version : constant int := 2; -   -- Target_Version is the value of SMFI_VERSION in the version of Libmilter -   -- that this version of Milter_API is intended to match. +   function Libmilter_Version return Libmilter_Version_Type is +      procedure smfi_version +         (pmajor : out unsigned; +          pminor : out unsigned; +          ppl    : out unsigned); +      pragma import(C, smfi_version); +      Major       : unsigned; +      Minor       : unsigned; +      Patch_Level : unsigned; +   begin +      smfi_version(Major, Minor, Patch_Level); +      return (Natural(Major), Natural(Minor), Natural(Patch_Level)); +   end Libmilter_Version; +   function Libmilter_Version_String return String is +      Version : constant Libmilter_Version_Type := Libmilter_Version; +      use Ada.Strings, Ada.Strings.Fixed; +   begin +      return Trim(Version.Major'Img, Left) & '.' & +             Trim(Version.Minor'Img, Left) & '.' & +             Trim(Version.Patch_Level'Img, Left); +   end Libmilter_Version_String; -   Real_Connect_Handler            : Connect_Handler; -   Real_Helo_Handler               : Helo_Handler; -   Real_Sender_Handler             : Sender_Handler; -   Real_Recipient_Handler          : Recipient_Handler; -   Real_Header_Handler             : Header_Handler; -   Real_End_Of_Headers_Handler     : End_Of_Headers_Handler; -   Real_Body_Handler               : Body_Handler; -   Real_End_Of_Message_Handler     : End_Of_Message_Handler; -   Real_Abort_Handler              : Abort_Handler; -   Real_Close_Handler              : Close_Handler; -   Real_Unknown_Command_Handler    : Unknown_Command_Handler; -   Real_Data_Handler               : Data_Handler; + +   function Flag(B : Boolean) return unsigned_long is +   begin +      if B then +         return 1; +      else +         return 0; +      end if; +   end Flag; +   pragma Inline(Flag); + + +   -- Option flags: +   SMFIF_ADDHDRS     : constant := 16#1#;       -- add headers +   SMFIF_CHGBODY     : constant := 16#2#;       -- replace body +   SMFIF_ADDRCPT     : constant := 16#4#;       -- add envelope recipients +   SMFIF_DELRCPT     : constant := 16#8#;       -- delete envelope recipients +   SMFIF_CHGHDRS     : constant := 16#10#;      -- change/delete headers +   SMFIF_QUARANTINE  : constant := 16#20#;      -- quarantine envelope +   SMFIF_CHGFROM     : constant := 16#40#;      -- change envelope sender +   SMFIF_ADDRCPT_PAR : constant := 16#80#;      -- add recipients with args +   SMFIF_SETSYMLIST  : constant := 16#100#;     -- request set of symbols +   SMFIP_NOCONNECT   : constant := 16#1#;       -- don't send connect info +   SMFIP_NOHELO      : constant := 16#2#;       -- don't send HELO info +   SMFIP_NOMAIL      : constant := 16#4#;       -- don't send MAIL info +   SMFIP_NORCPT      : constant := 16#8#;       -- don't send RCPT info +   SMFIP_NOBODY      : constant := 16#10#;      -- don't send body +   SMFIP_NOHDRS      : constant := 16#20#;      -- don't send headers +   SMFIP_NOEOH       : constant := 16#40#;      -- don't send EOH +   SMFIP_NR_HDR      : constant := 16#80#;      -- No reply for headers +   SMFIP_NOUNKNOWN   : constant := 16#100#;     -- don't send unknown commands +   SMFIP_NODATA      : constant := 16#200#;     -- don't send DATA +   SMFIP_SKIP        : constant := 16#400#;     -- MTA understands SMFIS_SKIP +   SMFIP_RCPT_REJ    : constant := 16#800#;     -- also send rejected RCPTs +   SMFIP_NR_CONN     : constant := 16#1000#;    -- No reply for connect +   SMFIP_NR_HELO     : constant := 16#2000#;    -- No reply for HELO +   SMFIP_NR_MAIL     : constant := 16#4000#;    -- No reply for MAIL +   SMFIP_NR_RCPT     : constant := 16#8000#;    -- No reply for RCPT +   SMFIP_NR_DATA     : constant := 16#10000#;   -- No reply for DATA +   SMFIP_NR_UNKN     : constant := 16#20000#;   -- No reply for UNKN +   SMFIP_NR_EOH      : constant := 16#40000#;   -- No reply for eoh +   SMFIP_NR_BODY     : constant := 16#80000#;   -- No reply for body chunk +   SMFIP_HDR_LEADSPC : constant := 16#100000#;  -- header value leading space + + +   -- Callback pointers: +   Real_Negotiator              : Negotiator; +   Real_Connect_Handler         : Connect_Handler; +   Real_Helo_Handler            : Helo_Handler; +   Real_Sender_Handler          : Sender_Handler; +   Real_Recipient_Handler       : Recipient_Handler; +   Real_Data_Handler            : Data_Handler; +   Real_Unknown_Command_Handler : Unknown_Command_Handler; +   Real_Header_Handler          : Header_Handler; +   Real_End_Of_Headers_Handler  : End_Of_Headers_Handler; +   Real_Body_Handler            : Body_Handler; +   Real_End_Of_Message_Handler  : End_Of_Message_Handler; +   Real_Abort_Handler           : Abort_Handler; +   Real_Close_Handler           : Close_Handler;     type sfsistat is new int; @@ -58,7 +121,8 @@ package body Milter_API is     procedure Oops(E : Exception_Occurrence) is     begin -      Log(Error, Exception_Information(E)); +      Log(Error, +          "Milter_API: Error in callback routine: " & Exception_Information(E));        Stop;     end Oops; @@ -69,29 +133,143 @@ package body Milter_API is     end Oops; +   type C_Negotiator is access function +      (ctx : SMFICTX_Pointer; +       f0  : unsigned_long; +       f1  : unsigned_long; +       f2  : unsigned_long; +       f3  : unsigned_long; +       pf0 : access unsigned_long; +       pf1 : access unsigned_long; +       pf2 : access unsigned_long; +       pf3 : access unsigned_long) +      return sfsistat; +   pragma convention(C, C_Negotiator); + +   function Negotiator_Relay +      (ctx : SMFICTX_Pointer; +       f0  : unsigned_long; +       f1  : unsigned_long; +       f2  : unsigned_long; +       f3  : unsigned_long; +       pf0 : access unsigned_long; +       pf1 : access unsigned_long; +       pf2 : access unsigned_long; +       pf3 : access unsigned_long) +      return sfsistat; +   pragma convention(C, Negotiator_Relay); + +   function Negotiator_Relay +      (ctx : SMFICTX_Pointer; +       f0  : unsigned_long; +       f1  : unsigned_long; +       f2  : unsigned_long; +       f3  : unsigned_long; +       pf0 : access unsigned_long; +       pf1 : access unsigned_long; +       pf2 : access unsigned_long; +       pf3 : access unsigned_long) +      return sfsistat +   is +      Offered   : constant Options := +         (Add_Headers                 => (f0 and SMFIF_ADDHDRS)     /= 0, +          Change_Or_Delete_Headers    => (f0 and SMFIF_CHGHDRS)     /= 0, +          Replace_Body                => (f0 and SMFIF_CHGBODY)     /= 0, +          Add_Recipients              => (f0 and SMFIF_ADDRCPT_PAR) /= 0, +          Remove_Recipients           => (f0 and SMFIF_DELRCPT)     /= 0, +          Quarantine                  => (f0 and SMFIF_QUARANTINE)  /= 0, +          Change_Sender               => (f0 and SMFIF_CHGFROM)     /= 0, +          Request_Symbols             => (f0 and SMFIF_SETSYMLIST)  /= 0, +          Show_Rejected_Recipients    => (f1 and SMFIP_RCPT_REJ)    /= 0, +          Skip_Further_Callbacks      => (f1 and SMFIP_SKIP)        /= 0, +          Headers_With_Leading_Space  => (f1 and SMFIP_HDR_LEADSPC) /= 0, +          Suppress_Connected          => (f1 and SMFIP_NOCONNECT)   /= 0, +          Suppress_Helo               => (f1 and SMFIP_NOHELO)      /= 0, +          Suppress_Sender             => (f1 and SMFIP_NOMAIL)      /= 0, +          Suppress_Recipient          => (f1 and SMFIP_NORCPT)      /= 0, +          Suppress_Data               => (f1 and SMFIP_NODATA)      /= 0, +          Suppress_Unknown_Command    => (f1 and SMFIP_NOUNKNOWN)   /= 0, +          Suppress_Header             => (f1 and SMFIP_NOHDRS)      /= 0, +          Suppress_End_Of_Headers     => (f1 and SMFIP_NOEOH)       /= 0, +          Suppress_Body_Chunk         => (f1 and SMFIP_NOBODY)      /= 0, +          No_Reply_To_Connected       => (f1 and SMFIP_NR_CONN)     /= 0, +          No_Reply_To_Helo            => (f1 and SMFIP_NR_HELO)     /= 0, +          No_Reply_To_Sender          => (f1 and SMFIP_NR_MAIL)     /= 0, +          No_Reply_To_Recipient       => (f1 and SMFIP_NR_RCPT)     /= 0, +          No_Reply_To_Data            => (f1 and SMFIP_NR_DATA)     /= 0, +          No_Reply_To_Unknown_Command => (f1 and SMFIP_NR_UNKN)     /= 0, +          No_Reply_To_Header          => (f1 and SMFIP_NR_HDR)      /= 0, +          No_Reply_To_End_Of_Headers  => (f1 and SMFIP_NR_EOH)      /= 0, +          No_Reply_To_Body_Chunk      => (f1 and SMFIP_NR_BODY)     /= 0); +      Result    : Negotiation_Result; +      Requested : Options; +   begin +      Real_Negotiator(ctx, Offered, Result, Requested); +      if Result = These_Options then +         pf0.all := +            SMFIF_ADDHDRS     * Flag(Requested.Add_Headers) + +            SMFIF_CHGHDRS     * Flag(Requested.Change_Or_Delete_Headers) + +            SMFIF_CHGBODY     * Flag(Requested.Replace_Body) + +            SMFIF_ADDRCPT_PAR * Flag(Requested.Add_Recipients) + +            SMFIF_ADDRCPT     * Flag(False) +  -- not using smfi_addrcpt +            SMFIF_DELRCPT     * Flag(Requested.Remove_Recipients) + +            SMFIF_QUARANTINE  * Flag(Requested.Quarantine) + +            SMFIF_CHGFROM     * Flag(Requested.Change_Sender) + +            SMFIF_SETSYMLIST  * Flag(Requested.Request_Symbols); +         pf1.all := +            SMFIP_RCPT_REJ    * Flag(Requested.Show_Rejected_Recipients) + +            SMFIP_SKIP        * Flag(Requested.Skip_Further_Callbacks) + +            SMFIP_HDR_LEADSPC * Flag(Requested.Headers_With_Leading_Space) + +            SMFIP_NOCONNECT   * Flag(Requested.Suppress_Connected) + +            SMFIP_NOHELO      * Flag(Requested.Suppress_Helo) + +            SMFIP_NOMAIL      * Flag(Requested.Suppress_Sender) + +            SMFIP_NORCPT      * Flag(Requested.Suppress_Recipient) + +            SMFIP_NODATA      * Flag(Requested.Suppress_Data) + +            SMFIP_NOUNKNOWN   * Flag(Requested.Suppress_Unknown_Command) + +            SMFIP_NOHDRS      * Flag(Requested.Suppress_Header) + +            SMFIP_NOEOH       * Flag(Requested.Suppress_End_Of_Headers) + +            SMFIP_NOBODY      * Flag(Requested.Suppress_Body_Chunk) + +            SMFIP_NR_CONN     * Flag(Requested.No_Reply_To_Connected) + +            SMFIP_NR_HELO     * Flag(Requested.No_Reply_To_Helo) + +            SMFIP_NR_MAIL     * Flag(Requested.No_Reply_To_Sender) + +            SMFIP_NR_RCPT     * Flag(Requested.No_Reply_To_Recipient) + +            SMFIP_NR_DATA     * Flag(Requested.No_Reply_To_Data) + +            SMFIP_NR_UNKN     * Flag(Requested.No_Reply_To_Unknown_Command) + +            SMFIP_NR_HDR      * Flag(Requested.No_Reply_To_Header) + +            SMFIP_NR_EOH      * Flag(Requested.No_Reply_To_End_Of_Headers) + +            SMFIP_NR_BODY     * Flag(Requested.No_Reply_To_Body_Chunk); +         pf2.all := 0; +         pf3.all := 0; +      end if; +      return sfsistat(Result); +   exception +      when E : others => +         Oops(E); +         return sfsistat(Reject); +   end Negotiator_Relay; +     type C_Connect_Handler is access function        (ctx      : SMFICTX_Pointer;         hostname : chars_ptr; -       hostaddr : access Dummy_Type) +       hostaddr : Sockaddr)        return sfsistat;     pragma convention(C, C_Connect_Handler);     function Connect_Relay        (ctx      : SMFICTX_Pointer;         hostname : chars_ptr; -       hostaddr : access Dummy_Type) +       hostaddr : Sockaddr)        return sfsistat;     pragma convention(C, Connect_Relay);     function Connect_Relay        (ctx      : SMFICTX_Pointer;         hostname : chars_ptr; -       hostaddr : access Dummy_Type) +       hostaddr : Sockaddr)        return sfsistat     is -      Dummy : Sockaddr;     begin -      return sfsistat(Real_Connect_Handler(ctx, Value(hostname), Dummy)); +      return sfsistat(Real_Connect_Handler(ctx, Value(hostname), hostaddr));     exception        when E : others =>           return Oops(E); @@ -375,65 +553,56 @@ package body Milter_API is     procedure Register -      (Name                              : String; -       Connected                         : Connect_Handler            := null; -       Helo                              : Helo_Handler               := null; -       Sender                            : Sender_Handler             := null; -       Recipient                         : Recipient_Handler          := null; -       Data                              : Data_Handler               := null; -       Unknown_Command                   : Unknown_Command_Handler    := null; -       Header                            : Header_Handler             := null; -       End_Of_Headers                    : End_Of_Headers_Handler     := null; -       Body_Chunk                        : Body_Handler               := null; -       End_Of_Message                    : End_Of_Message_Handler     := null; -       Aborted                           : Abort_Handler              := null; -       Closed                            : Close_Handler              := null; -       May_Add_Headers                   : Boolean                    := False; -       May_Change_Or_Delete_Headers      : Boolean                    := False; -       May_Replace_Body                  : Boolean                    := False; -       May_Add_Recipients                : Boolean                    := False; -       May_Remove_Recipients             : Boolean                    := False; -       May_Quarantine                    : Boolean                    := False) +      (Name                         : String; +       Negotiate                    : Negotiator              := null; +       Connected                    : Connect_Handler         := null; +       Helo                         : Helo_Handler            := null; +       Sender                       : Sender_Handler          := null; +       Recipient                    : Recipient_Handler       := null; +       Data                         : Data_Handler            := null; +       Unknown_Command              : Unknown_Command_Handler := null; +       Header                       : Header_Handler          := null; +       End_Of_Headers               : End_Of_Headers_Handler  := null; +       Body_Chunk                   : Body_Handler            := null; +       End_Of_Message               : End_Of_Message_Handler  := null; +       Aborted                      : Abort_Handler           := null; +       Closed                       : Close_Handler           := null; +       May_Add_Headers              : Boolean                 := False; +       May_Change_Or_Delete_Headers : Boolean                 := False; +       May_Replace_Body             : Boolean                 := False; +       May_Add_Recipients           : Boolean                 := False; +       May_Remove_Recipients        : Boolean                 := False; +       May_Quarantine               : Boolean                 := False; +       May_Change_Sender            : Boolean                 := False; +       May_Request_Symbols          : Boolean                 := False)     is -      SMFIF_ADDHDRS     : constant := 16#1#;    -- add headers -      SMFIF_CHGBODY     : constant := 16#2#;    -- replace body -      SMFIF_ADDRCPT     : constant := 16#4#;    -- add envelope recipients -      SMFIF_DELRCPT     : constant := 16#8#;    -- delete envelope recipients -      SMFIF_CHGHDRS     : constant := 16#10#;   -- change/delete headers -      SMFIF_QUARANTINE  : constant := 16#20#;   -- quarantine envelope - -      function BI(B : Boolean) return unsigned_long is -      begin -         if B then -            return 1; -         else -            return 0; -         end if; -      end BI; -        type smfiDesc is record -         xxfi_name      : chars_ptr     := New_String(Name); -         xxfi_version   : int           := Target_Version; +         xxfi_name      : chars_ptr := New_String(Name); +         xxfi_version   : int;           xxfi_flags     : unsigned_long := -            SMFIF_ADDHDRS     * BI(May_Add_Headers) + -            SMFIF_CHGHDRS     * BI(May_Change_Or_Delete_Headers) + -            SMFIF_CHGBODY     * BI(May_Replace_Body) + -            SMFIF_ADDRCPT     * BI(May_Add_Recipients) + -            SMFIF_DELRCPT     * BI(May_Remove_Recipients) + -            SMFIF_QUARANTINE  * BI(May_Quarantine); -         xxfi_connect   : C_Connect_Handler            := null; -         xxfi_helo      : C_Helo_Handler               := null; -         xxfi_envfrom   : C_Sender_Handler             := null; -         xxfi_envrcpt   : C_Recipient_Handler          := null; -         xxfi_header    : C_Header_Handler             := null; -         xxfi_eoh       : C_End_Of_Headers_Handler     := null; -         xxfi_body      : C_Body_Handler               := null; -         xxfi_eom       : C_End_Of_Message_Handler     := null; -         xxfi_abort     : C_Abort_Handler              := null; -         xxfi_close     : C_Close_Handler              := null; -         xxfi_unknown   : C_Unknown_Command_Handler    := null; -         xxfi_data      : C_Data_Handler               := null; +            SMFIF_ADDHDRS     * Flag(May_Add_Headers) + +            SMFIF_CHGHDRS     * Flag(May_Change_Or_Delete_Headers) + +            SMFIF_CHGBODY     * Flag(May_Replace_Body) + +            SMFIF_ADDRCPT_PAR * Flag(May_Add_Recipients) + +            SMFIF_ADDRCPT     * Flag(False) +  -- not using smfi_addrcpt +            SMFIF_DELRCPT     * Flag(May_Remove_Recipients) + +            SMFIF_QUARANTINE  * Flag(May_Quarantine) + +            SMFIF_CHGFROM     * Flag(May_Change_Sender) + +            SMFIF_SETSYMLIST  * Flag(May_Request_Symbols); +         xxfi_connect   : C_Connect_Handler         := null; +         xxfi_helo      : C_Helo_Handler            := null; +         xxfi_envfrom   : C_Sender_Handler          := null; +         xxfi_envrcpt   : C_Recipient_Handler       := null; +         xxfi_header    : C_Header_Handler          := null; +         xxfi_eoh       : C_End_Of_Headers_Handler  := null; +         xxfi_body      : C_Body_Handler            := null; +         xxfi_eom       : C_End_Of_Message_Handler  := null; +         xxfi_abort     : C_Abort_Handler           := null; +         xxfi_close     : C_Close_Handler           := null; +         xxfi_unknown   : C_Unknown_Command_Handler := null; +         xxfi_data      : C_Data_Handler            := null; +         xxfi_negotiate : C_Negotiator              := null;        end record;        pragma convention(C_Pass_By_Copy, smfiDesc);        Definition : smfiDesc; @@ -441,8 +610,20 @@ package body Milter_API is        function smfi_register(descr : smfiDesc) return int;        pragma import(C, smfi_register); +      Version : constant Libmilter_Version_Type := Libmilter_Version; +     begin  -- Register +      -- The purpose of xxfi_version appears to be to check that the version of +      -- Libmilter that the milter is dynamically linked with is compatible +      -- with the version of the C header files that it was compiled against. +      -- Such a check is meaningless for this binding, which is independent of +      -- the C header files. Short-circuit the check by retrieving the version +      -- of the dynamically linked library and feeding it back to the library. +      Definition.xxfi_version := int(Version.Major * 2 ** 24 + +                                     Version.Minor * 2 ** 8 + +                                     Version.Patch_Level); +        if Connected /= null then           Real_Connect_Handler := Connected;           Definition.xxfi_connect := Connect_Relay'Access; @@ -491,6 +672,10 @@ package body Milter_API is           Real_Data_Handler := Data;           Definition.xxfi_data := Data_Relay'Access;        end if; +      if Negotiate /= null then +         Real_Negotiator := Negotiate; +         Definition.xxfi_negotiate := Negotiator_Relay'Access; +      end if;        Check_For_Error("smfi_register", smfi_register(Definition)); @@ -520,7 +705,8 @@ package body Milter_API is     procedure Open_Socket(Remove_Old_Socket : Boolean) is        function smfi_opensocket(rmsocket : int) return int; -      -- rmsocket is declared as bool. I hope a bool is always an int. +      -- rmsocket is declared as bool, but bool is defined as int in mfapi.h, +      -- subject to a lot of ifs.        pragma import(C, smfi_opensocket);        function I(B : Boolean) return int is        begin if B then return 1; else return 0; end if; end I; @@ -549,6 +735,23 @@ package body Milter_API is        smfi_stop;     end Stop; +   procedure Request_Symbols +      (Context : SMFICTX_Pointer; +       Stage   : Protocol_Stage; +       Names   : String) +   is +      function smfi_setsymlist +         (ctx    : SMFICTX_Pointer; +          stage  : int; +          macros : char_array) +         return int; +      pragma import(C, smfi_setsymlist); +   begin +      Check_For_Error("smfi_setsymlist", smfi_setsymlist(Context, +                                                         int(Stage), +                                                         To_C(Names))); +   end Request_Symbols; +     function Arguments(Handle : Arguments_Handle) return Unbounded_Strings is        Ustrings : Unbounded_Strings                   (1 .. Natural(String_Arrays.Virtual_Length(Handle.Pointer))); @@ -642,6 +845,91 @@ package body Milter_API is                                      Message_Ptr));     end Set_Reply; +   procedure Set_Reply +      (Context       : SMFICTX_Pointer; +       Reply_Code    : String_Of_Three; +       Extended_Code : String := ""; +       Message       : Reply_Lines) +   is separate; + +   milter_api_address_type_ipv4    : constant Unsigned_8 := 1; +   milter_api_address_type_ipv6    : constant Unsigned_8 := 2; +   milter_api_address_type_unknown : constant Unsigned_8 := 255; +   pragma export(C, milter_api_address_type_ipv4); +   pragma export(C, milter_api_address_type_ipv6); +   pragma export(C, milter_api_address_type_unknown); + +   function Address(Endpoint : Sockaddr) return IP_Address is +      type Unsigned_8_Pointer is access Unsigned_8; +      function milter_api_address_type(endpoint : Sockaddr) return Unsigned_8; +      procedure milter_api_ipv4_address(endpoint : in  Sockaddr; +                                        buffer   : out Byte_Array); +      procedure milter_api_ipv6_address(endpoint : in  Sockaddr; +                                        buffer   : out Byte_Array); +      pragma import(C, milter_api_address_type); +      pragma import(C, milter_api_ipv4_address); +      pragma import(C, milter_api_ipv6_address); +      Address_Type : Unsigned_8; +   begin +      if Endpoint = Null_Address then +         raise No_Address; +      else +         Address_Type := milter_api_address_type(Endpoint); +         case Address_Type is +            when milter_api_address_type_ipv4 => +               declare +                  Address : IP_Address(IPv4); +               begin +                  milter_api_ipv4_address(Endpoint, Address.IPv4_Address); +                  return Address; +               end; +            when milter_api_address_type_ipv6 => +               declare +                  Address : IP_Address(IPv6); +               begin +                  milter_api_ipv6_address(Endpoint, Address.IPv6_Address); +                  return Address; +               end; +            when others => +               raise Unknown_Address_Type; +         end case; +      end if; +   end Address; + +   function Address(Endpoint : Sockaddr) return String is +      procedure milter_api_address_string(endpoint : in  Sockaddr; +                                          buffer   : out char_array; +                                          size     : in  Unsigned_8); +      pragma import(C, milter_api_address_string); +      Buffer : char_array(1..46); +      -- An IPv4-mapped IPv6 address in hybrid notation requires at most 45 +      -- characters plus a nul character. +   begin +      if Endpoint = Null_Address then +         return "(address unavailable)"; +      else +         milter_api_address_string(Endpoint, Buffer, Buffer'Length); +         return To_Ada(Buffer); +      end if; +   end Address; + +   function Port(Endpoint : Sockaddr) return Unsigned_16 is +      function milter_api_address_type(endpoint : Sockaddr) return Unsigned_8; +      function milter_api_port(endpoint : Sockaddr) return Unsigned_16; +      pragma import(C, milter_api_address_type); +      pragma import(C, milter_api_port); +   begin +      if Endpoint = Null_Address then +         raise No_Address; +      else +         case milter_api_address_type(Endpoint) is +            when milter_api_address_type_ipv4 | milter_api_address_type_ipv6 => +               return milter_api_port(Endpoint); +            when others => +               raise Unknown_Address_Type; +         end case; +      end if; +   end Port;     procedure Add_Header        (Context : SMFICTX_Pointer; @@ -721,14 +1009,46 @@ package body Milter_API is                                       To_C(Value)));     end Insert_Header; -   procedure Add_Recipient(Context : SMFICTX_Pointer; Address : String) is -      function smfi_addrcpt +   procedure Change_Sender +      (Context    : SMFICTX_Pointer; +       Address    : String; +       Parameters : String := "") +   is +      function smfi_chgfrom           (ctx  : SMFICTX_Pointer; -          rcpt : char_array) +          mail : char_array; +          args : chars_ptr)           return int; -      pragma import(C, smfi_addrcpt); +      pragma import(C, smfi_chgfrom); +      C_Parameters   : aliased char_array := To_C(Parameters); +      Parameters_Ptr : chars_ptr := Null_Ptr;     begin -      Check_For_Error("smfi_addrcpt", smfi_addrcpt(Context, To_C(Address))); +      if Parameters'Length > 0 then +         Parameters_Ptr := To_Chars_Ptr(C_Parameters'Unchecked_Access); +      end if; +      Check_For_Error("smfi_chgfrom", +                      smfi_chgfrom(Context, To_C(Address), Parameters_Ptr)); +   end Change_Sender; + +   procedure Add_Recipient +      (Context    : SMFICTX_Pointer; +       Address    : String; +       Parameters : String := "") +   is +      function smfi_addrcpt_par +         (ctx  : SMFICTX_Pointer; +          rcpt : char_array; +          args : chars_ptr) +         return int; +      pragma import(C, smfi_addrcpt_par); +      C_Parameters   : aliased char_array := To_C(Parameters); +      Parameters_Ptr : chars_ptr := Null_Ptr; +   begin +      if Parameters'Length > 0 then +         Parameters_Ptr := To_Chars_Ptr(C_Parameters'Unchecked_Access); +      end if; +      Check_For_Error("smfi_addrcpt_par", +                      smfi_addrcpt_par(Context, To_C(Address), Parameters_Ptr));     end Add_Recipient;     procedure Delete_Recipient(Context : SMFICTX_Pointer; Address : String) is diff --git a/milter_api.ads b/milter_api.ads index 8a4facf..9097e69 100644 --- a/milter_api.ads +++ b/milter_api.ads @@ -1,5 +1,5 @@ --- Milter API for Ada, a binding to Libmilter, the Sendmail mail filtering API --- Copyright 2009 B. Persson, Bjorn@Rombobeorn.se +-- Ada Milter API, a binding to Libmilter, the Sendmail mail filtering API +-- Copyright 2009 - 2012 B. Persson, Bjorn@Rombobeorn.se  --  -- This library is free software: you can redistribute it and/or modify it  -- under the terms of the GNU General Public License version 3, as published @@ -9,6 +9,7 @@  with Ada.Strings.Unbounded;  with Interfaces.C.Strings;  with Interfaces.C.Pointers; +with System;  package Milter_API is @@ -39,11 +40,100 @@ package Milter_API is     -- Binding_Version_String returns the same version information as     -- Binding_Version, but in string form. +   type Libmilter_Version_Type is record +      Major       : Natural; +      Minor       : Natural; +      Patch_Level : Natural; +   end record; + +   function Libmilter_Version return Libmilter_Version_Type; +   -- Libmilter_Version returns the version of Libmilter that Milter_API is +   -- linked with (calls smfi_version). If it is dynamically linked, then this +   -- is the version that is loaded at run time. + +   function Libmilter_Version_String return String; +   -- Libmilter_Version_String returns the same version information as +   -- Libmilter_Version, but in string form. +     --     -- Data types and constants     -- +   type Options is record +      Add_Headers                 : Boolean := False; +      -- The milter may add header fields to messages (call Add_Header). +      Change_Or_Delete_Headers    : Boolean := False; +      -- The milter may change and/or delete header fields in messages (call +      -- Change_Header and/or Delete_Header). +      Replace_Body                : Boolean := False; +      -- The milter may replace message bodies (call Replace_Body). +      Add_Recipients              : Boolean := False; +      -- The milter may add recipients to the SMTP envelope (with or without +      -- ESMTP extension parameters attached) (call Add_Recipient). +      Remove_Recipients           : Boolean := False; +      -- The milter may remove recipients from the SMTP envelope (call +      -- Delete_Recipient). +      Quarantine                  : Boolean := False; +      -- The milter may quarantine messages (call Quarantine_Message). +      Change_Sender               : Boolean := False; +      -- The milter may change the sender in the SMTP envelope (call +      -- Change_Sender). +      Request_Symbols             : Boolean := False; +      -- The milter may specify a set of symbols ("macros") that it wants (call +      -- Request_Symbols). +      Show_Rejected_Recipients    : Boolean := False; +      -- Call the Recipient_Handler also for RCPT commands that the MTA rejects +      -- because the user is unknown or similar reasons. RCPT commands that are +      -- rejected because of syntax errors or suchlike will still not be shown +      -- to the milter. If the symbol {rcpt_mailer} has the value "error", then +      -- the recipient will be rejected by the MTA. In that case the symbols +      -- {rcpt_host} and {rcpt_addr} will usually contain an enhanced status +      -- code and an error text, respectively. +      Skip_Further_Callbacks      : Boolean := False; +      -- Callback routines may return Skip. +      Headers_With_Leading_Space  : Boolean := False; +      -- Pass header values to the Header_Handler with leading space intact, +      -- and do not add a leading space to headers when they are added, +      -- inserted or changed. +      Suppress_Connected          : Boolean := False; +      -- Don't call the Connect_Handler. +      Suppress_Helo               : Boolean := False; +      -- Don't call the Helo_Handler. +      Suppress_Sender             : Boolean := False; +      -- Don't call the Sender_Handler. +      Suppress_Recipient          : Boolean := False; +      -- Don't call the Recipient_Handler +      Suppress_Data               : Boolean := False; +      -- Don't call the Data_Handler. +      Suppress_Unknown_Command    : Boolean := False; +      -- Don't call the Unknown_Command_Handler. +      Suppress_Header             : Boolean := False; +      -- Don't call the Header_Handler. +      Suppress_End_Of_Headers     : Boolean := False; +      -- Don't call the End_Of_Headers_Handler. +      Suppress_Body_Chunk         : Boolean := False; +      -- Don't call the Body_Handler. +      No_Reply_To_Connected       : Boolean := False; +      -- The Connect_Handler will return No_Reply. +      No_Reply_To_Helo            : Boolean := False; +      -- The Helo_Handler will return No_Reply. +      No_Reply_To_Sender          : Boolean := False; +      -- The Sender_Handler will return No_Reply. +      No_Reply_To_Recipient       : Boolean := False; +      -- The Recipient_Handler will return No_Reply. +      No_Reply_To_Data            : Boolean := False; +      -- The Data_Handler will return No_Reply. +      No_Reply_To_Unknown_Command : Boolean := False; +      -- The Unknown_Command_Handler will return No_Reply. +      No_Reply_To_Header          : Boolean := False; +      -- The Header_Handler will return No_Reply. +      No_Reply_To_End_Of_Headers  : Boolean := False; +      -- The End_Of_Headers_Handler will return No_Reply. +      No_Reply_To_Body_Chunk      : Boolean := False; +      -- The Body_Handler will return No_Reply. +   end record; +     type SMFICTX_Pointer is private;     -- SMFICTX_Pointer is the type of the opaque context pointers that Libmilter     -- passes to the callback routines, and that these in turn must pass to the @@ -57,6 +147,33 @@ package Milter_API is     -- each SMTP session. The pointer to that object must be stored with     -- Set_Private_Data and retrieved with Private_Data. +   type Protocol_Stage is private; +   -- A Protocol_Stage is passed to Request_Symbols to specify which callback +   -- routines want the requested symbols. + +   At_Connect        : constant Protocol_Stage; +   At_Helo           : constant Protocol_Stage; +   At_Sender         : constant Protocol_Stage; +   At_Recipient      : constant Protocol_Stage; +   At_Data           : constant Protocol_Stage; +   At_End_Of_Headers : constant Protocol_Stage; +   At_End_Of_Message : constant Protocol_Stage; + +   type Negotiation_Result is private; +   -- Negotiation_Result is returned by the callback routine Negotiate. + +   All_Options : constant Negotiation_Result; +   -- Use all available protocol steps and actions. +   -- (SMFIS_ALL_OPTS) + +   These_Options : constant Negotiation_Result; +   -- Use the selected protocol steps and actions. +   -- (SMFIS_CONTINUE) + +   Failed : constant Negotiation_Result; +   -- The milter failed to start up. +   -- (SMFIS_REJECT) +     type Action is private;     -- Action is returned by callback routines. The value is an instruction to     -- the MTA on how to proceed with the message or connection. @@ -95,18 +212,79 @@ package Milter_API is     -- recipient) processing of the message will continue.     -- (SMFIS_TEMPFAIL) +   No_Reply : constant Action; +   -- Do not send a reply to the MTA. +   -- (SMFIS_NOREPLY) + +   Skip : constant Action; +   -- Skip over rest of same callbacks, e.g., body. +   -- (SMFIS_SKIP) +     type Sockaddr is private; +   -- A Sockaddr is an opaque handle that points to a TCP endpoint address +   -- (that is a combination of an IP address and a TCP port). The functions +   -- Address and Port may be used to retrieve the address data. + +   type Address_Family is (IPv4, IPv6); + +   type Byte_Array is array(Positive range <>) of Interfaces.Unsigned_8; +   for Byte_Array'Component_Size use 8; + +   type IP_Address(Family : Address_Family := IPv4) is record +      case Family is +         when IPv4 => +            IPv4_Address : Byte_Array(1..4); +         when IPv6 => +            IPv6_Address : Byte_Array(1..16); +      end case; +   end record;     type Arguments_Handle is private; +   -- An Arguments_Handle holds ESMTP arguments to a MAIL or RCPT command. The +   -- function Arguments may be used to retrieve the arguments.     type Unbounded_Strings is        array(Positive range <>) of Ada.Strings.Unbounded.Unbounded_String; +   subtype String_Of_Three is String(1..3); +   -- three-digit (RFC 2821) reply code + +   subtype Reply_Line_Index is Positive range 1 .. 32; +   type Reply_Lines is +      array(Reply_Line_Index range <>) of Ada.Strings.Unbounded.Unbounded_String; +     --     -- Callback types     -- +   type Negotiator is access procedure +      (Context   : in  SMFICTX_Pointer;     -- the opaque context handle +       Offered   : in  Options;             -- options the MTA can provide +       Result    : out Negotiation_Result;  -- how to proceed +       Requested : out Options);            -- options the milter wants to use +   -- called at the start of each SMTP connection +   -- A Negotiator enables a milter to determine which options are available +   -- and dynamically select those which it needs and which are offered. If +   -- some options are not available, the milter may fall back to a less +   -- optimized way of working, operate with reduced functionality, or abort +   -- the session and ask the user to upgrade. +   -- corresponds to xxfi_negotiate +   -- The possible values of Result are: +   -- * All_Options: Use all available protocol steps and actions. The value of +   --   Requested will be ignored. +   -- * These_Options: Use those protocol steps and actions that are specified +   --   in Requested. +   -- * Failed: The milter failed to start up. It will not be contacted again +   --   for the current connection. +   -- More options may be added in future versions of Milter_API. If so, they +   -- will be off by default so that milters that are unaware of them will +   -- continue working the same way as before. To ensure that your Negotiator +   -- will be compatible with future extensions, do not assign an aggregate to +   -- Requested listing all the components. Either declare an Options variable +   -- and assign to individual components, or use an aggregate with named +   -- component associations and an "others => <>" association. +     type Connect_Handler is access function        (Context        : SMFICTX_Pointer;  -- the opaque context handle         Client_Name    : String;           -- the name of the client @@ -129,18 +307,19 @@ package Milter_API is     type Sender_Handler is access function        (Context   : SMFICTX_Pointer;   -- the opaque context handle -       Sender    : String;            -- the envelope sender address +       Sender    : String;            -- the SMTP envelope sender address         Arguments : Arguments_Handle)  -- ESMTP arguments to the MAIL command        return Action; -   -- called once at the beginning of each message +   -- called once at the beginning of each message, when the client sends the +   -- MAIL command     -- corresponds to xxfi_envfrom     type Recipient_Handler is access function        (Context   : SMFICTX_Pointer;   -- the opaque context handle -       Recipient : String;            -- an envelope recipient address +       Recipient : String;            -- an SMTP envelope recipient address         Arguments : Arguments_Handle)  -- ESMTP arguments to the RCPT command        return Action; -   -- called once per recipient +   -- called once per recipient, when the client sends an RCPT command     -- corresponds to xxfi_envrcpt     type Data_Handler is access function @@ -208,31 +387,42 @@ package Milter_API is     Unknown_Error : exception;     -- A C function returned an undocumented result code. +   No_Address : exception; +   -- A Sockaddr handle that didn't point to anything was passed to Address or +   -- Port. + +   Unknown_Address_Type : exception; +   -- A Sockaddr handle that pointed to something other than an IPv4 or IPv6 +   -- address was passed to Address or Port. +     --     -- Library control procedures     --     procedure Register -      (Name                              : String; -       Connected                         : Connect_Handler            := null; -       Helo                              : Helo_Handler               := null; -       Sender                            : Sender_Handler             := null; -       Recipient                         : Recipient_Handler          := null; -       Data                              : Data_Handler               := null; -       Unknown_Command                   : Unknown_Command_Handler    := null; -       Header                            : Header_Handler             := null; -       End_Of_Headers                    : End_Of_Headers_Handler     := null; -       Body_Chunk                        : Body_Handler               := null; -       End_Of_Message                    : End_Of_Message_Handler     := null; -       Aborted                           : Abort_Handler              := null; -       Closed                            : Close_Handler              := null; -       May_Add_Headers                   : Boolean                    := False; -       May_Change_Or_Delete_Headers      : Boolean                    := False; -       May_Replace_Body                  : Boolean                    := False; -       May_Add_Recipients                : Boolean                    := False; -       May_Remove_Recipients             : Boolean                    := False; -       May_Quarantine                    : Boolean                    := False); +      (Name                         : String; +       Negotiate                    : Negotiator              := null; +       Connected                    : Connect_Handler         := null; +       Helo                         : Helo_Handler            := null; +       Sender                       : Sender_Handler          := null; +       Recipient                    : Recipient_Handler       := null; +       Data                         : Data_Handler            := null; +       Unknown_Command              : Unknown_Command_Handler := null; +       Header                       : Header_Handler          := null; +       End_Of_Headers               : End_Of_Headers_Handler  := null; +       Body_Chunk                   : Body_Handler            := null; +       End_Of_Message               : End_Of_Message_Handler  := null; +       Aborted                      : Abort_Handler           := null; +       Closed                       : Close_Handler           := null; +       May_Add_Headers              : Boolean                 := False; +       May_Change_Or_Delete_Headers : Boolean                 := False; +       May_Replace_Body             : Boolean                 := False; +       May_Add_Recipients           : Boolean                 := False; +       May_Remove_Recipients        : Boolean                 := False; +       May_Quarantine               : Boolean                 := False; +       May_Change_Sender            : Boolean                 := False; +       May_Request_Symbols          : Boolean                 := False);     -- Register must be called exactly once before Main. It registers the     -- callbacks and properties of the milter (calls smfi_register). @@ -276,6 +466,18 @@ package Milter_API is     -- +   -- Protocol negotiation procedure +   -- + +   procedure Request_Symbols +      (Context : SMFICTX_Pointer;  -- the opaque context handle +       Stage   : Protocol_Stage;   -- when the symbols are wanted +       Names   : String);          -- space-separated list of wanted symbols +   -- Defines the set of symbols ("macros") that the milter wants to receive +   -- from the MTA at the specified protocol stage (calls smfi_setsymlist). + + +   --     -- Data access subprograms     -- @@ -288,8 +490,8 @@ package Milter_API is         Name    : in  String;           -- the name of the requested symbol         Defined : out Boolean;          -- whether the requested symbol exists         Value   : out Ada.Strings.Unbounded.Unbounded_String); -   -- Requests the value of a symbol ("macro") from the MTA. Value is -   -- meaningful only if Defined is True. +   -- Requests the value of a symbol ("macro") from the MTA (calls +   -- smfi_getsymval). Value is meaningful only if Defined is True.     procedure Set_Private_Data        (Context : SMFICTX_Pointer;       -- the opaque context handle @@ -303,7 +505,6 @@ package Milter_API is     -- Retrieves the private data pointer previously stored with Set_Private_Data     -- for this connection (calls smfi_getpriv). -   subtype String_Of_Three is String(1..3);     procedure Set_Reply        (Context       : SMFICTX_Pointer;  -- the opaque context handle         Reply_Code    : String_Of_Three;  -- three-digit (RFC 2821) reply code @@ -311,7 +512,27 @@ package Milter_API is         Message       : String := "");    -- the text part of the reply     -- Sets the reply codes and message to be used in subsequent SMTP error     -- replies caused by the milter (calls smfi_setreply). -   -- There is no interface to smfi_setmlreply yet. + +   procedure Set_Reply +      (Context       : SMFICTX_Pointer;  -- the opaque context handle +       Reply_Code    : String_Of_Three;  -- three-digit (RFC 2821) reply code +       Extended_Code : String := "";     -- extended (RFC 2034) reply code +       Message       : Reply_Lines);     -- the text part of the reply +   -- Sets the reply codes and multiple-line message to be used in subsequent +   -- SMTP error replies caused by the milter (calls smfi_setmlreply). + +   function Address(Endpoint : Sockaddr) return IP_Address; +   -- Returns the IP address from a Sockaddr handle, or raises No_Address if +   -- the handle doesn't point to anything. + +   function Address(Endpoint : Sockaddr) return String; +   -- Returns the textual representation of the IP address from a Sockaddr +   -- handle, or returns "(address unavailable)" if the handle doesn't point to +   -- anything. + +   function Port(Endpoint : Sockaddr) return Interfaces.Unsigned_16; +   -- Returns the TCP port from a Sockaddr handle, or raises No_Address if the +   -- handle doesn't point to anything.     -- @@ -351,17 +572,26 @@ package Milter_API is     -- (calls smfi_insheader). Index specifies where in the list of headers it     -- shall be inserted. 1 makes it the first header, 2 the second and so on. +   procedure Change_Sender +      (Context    : SMFICTX_Pointer;  -- the opaque context handle +       Address    : String;           -- the new sender address +       Parameters : String := "");    -- extension parameters +   -- Changes the sender address of the SMTP envelope of the current message, +   -- optionally with ESMTP extension parameters attached (calls smfi_chgfrom). +     procedure Add_Recipient -      (Context : SMFICTX_Pointer;  -- the opaque context handle -       Address : String);          -- the new recipient's address -   -- Adds a recipient address to the envelope of the current message (calls -   -- smfi_addrcpt). +      (Context    : SMFICTX_Pointer;  -- the opaque context handle +       Address    : String;           -- the new recipient address +       Parameters : String := "");    -- extension parameters +   -- Adds a recipient address to the SMTP envelope of the current message, +   -- optionally with ESMTP extension parameters attached (calls +   -- smfi_addrcpt_par).     procedure Delete_Recipient        (Context : SMFICTX_Pointer;  -- the opaque context handle         Address : String);          -- the recipient address to be removed -   -- Removes the specified recipient address from the envelope of the current -   -- message (calls smfi_delrcpt). +   -- Removes the specified recipient address from the SMTP envelope of the +   -- current message (calls smfi_delrcpt).     procedure Replace_Body        (Context : SMFICTX_Pointer;  -- the opaque context handle @@ -394,18 +624,32 @@ private     pragma convention(C, Dummy_Type);     pragma convention(C, SMFICTX_Pointer); -   type Action is range 0 .. 10; +   type Protocol_Stage is range 0 .. 6; +   At_Connect        : constant Protocol_Stage := 0; +   At_Helo           : constant Protocol_Stage := 1; +   At_Sender         : constant Protocol_Stage := 2; +   At_Recipient      : constant Protocol_Stage := 3; +   At_Data           : constant Protocol_Stage := 4; +   At_End_Of_Message : constant Protocol_Stage := 5; +   At_End_Of_Headers : constant Protocol_Stage := 6; + +   type Negotiation_Result is range 0 .. 10; +   These_Options : constant Negotiation_Result := 0; +   Failed        : constant Negotiation_Result := 1; +   All_Options   : constant Negotiation_Result := 10; + +   type Action is range 0 .. 8;     Continue          : constant Action := 0;     Reject            : constant Action := 1;     Discard           : constant Action := 2;     Accept_Definitely : constant Action := 3;     Fail_Temporarily  : constant Action := 4; -   All_Options       : constant Action := 10; +   No_Reply          : constant Action := 7; +   Skip              : constant Action := 8; + +   type Sockaddr is new System.Address; -   type Sockaddr is null record; -   -- Accessing socket addresses isn't implemented. The type is declared just -   -- so that there's a chance that the API will be compatible if this gets -   -- implemented in the future. +   Null_Address : constant Sockaddr := Sockaddr(System.Null_Address);     use Interfaces.C;     use Interfaces.C.Strings; diff --git a/sockaddr_functions.c b/sockaddr_functions.c new file mode 100644 index 0000000..6148414 --- /dev/null +++ b/sockaddr_functions.c @@ -0,0 +1,68 @@ +#include <stdint.h> +#include <string.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + + +extern const uint8_t milter_api_address_type_ipv4; +extern const uint8_t milter_api_address_type_ipv6; +extern const uint8_t milter_api_address_type_unknown; + + +uint8_t milter_api_address_type(struct sockaddr const* const endpoint) { +   if(endpoint->sa_family == AF_INET) { +      return milter_api_address_type_ipv4; +   } else if(endpoint->sa_family == AF_INET6) { +      return milter_api_address_type_ipv6; +   } else { +      return milter_api_address_type_unknown; +   } +} + + +void milter_api_ipv4_address(struct sockaddr_in const* const endpoint,  // in +                             uint8_t* const                  buffer)    // out +{ +   memcpy(buffer, &endpoint->sin_addr, 4); +} + + +void milter_api_ipv6_address(struct sockaddr_in6 const* const endpoint,  // in +                             uint8_t* const                   buffer)    // out +{ +   memcpy(buffer, &endpoint->sin6_addr, 16); +} + + +void milter_api_address_string(struct sockaddr const* const endpoint,  // in +                               char* const                  buffer,    // out +                               const uint8_t                size)      // in +{ +   char const* result = NULL; + +   if(endpoint->sa_family == AF_INET) { +      result = inet_ntop(endpoint->sa_family, +                         &((struct sockaddr_in const*)endpoint)->sin_addr, +                         buffer, size); +   } else if(endpoint->sa_family == AF_INET6) { +      result = inet_ntop(endpoint->sa_family, +                         &((struct sockaddr_in6 const*)endpoint)->sin6_addr, +                         buffer, size); +   } +   if(result == NULL) { +      strncpy(buffer, "(error in address conversion)", size); +      buffer[size - 1] = '\0'; +   } +} + + +uint16_t milter_api_port(struct sockaddr const* const endpoint) { +   if(endpoint->sa_family == AF_INET) { +      return ntohs(((struct sockaddr_in const*)endpoint)->sin_port); +   } else if(endpoint->sa_family == AF_INET6) { +      return ntohs(((struct sockaddr_in6 const*)endpoint)->sin6_port); +   } else { +      return 0; +   } +} |