1 (* mailvisa-check - Read a message, send it to mailvisad, and judge if it's ham or spam *)
10 let default_confdir = (getenv
"HOME") ^
"/settings/mailvisa2"
11 let default_sockpath = "mailvisad.sock"
12 let default_blocksize = 16384
13 let default_threshold = 0.5
14 let default_passthrough = true (** output message *)
15 let default_header = true (** output X-Spam headers *)
16 let default_errorcodes = false (** suppress error codes if true *)
17 let default_input = Pervasives.stdin
18 let default_output = Pervasives.stdout
25 let usage = "USAGE: mailvisa [options]"
26 let help = "Valid options are:
28 -c <path> Look for files in <path> (default: $HOME/settings/mailvisa)
29 -q Do not output message or X-Spam headers
30 -e Do not use exit status to indicate spam
31 -b <num> Read <num> bytes at a time (default: 16384)
32 -t <num> Threshold for flagging messages as spam (default: 0.5)
33 -m <command> Pipe output to <command>
34 -s <path> Use <path> to connect to mailvisad (default: mailvisad.sock)"
38 (** Parse command options from args into hash table. *)
39 let parse_options args
=
40 let options = Hashtbl.create
8 in
42 let add_flag name
= Hashtbl.add
options name
"true" in
43 let add_option name
= increment
i; Hashtbl.add
options name args
.(!i) in
44 while !i < (Array.length args
) do
50 | "-b" -> add_option "blocksize"
51 | "-c" -> add_option "confdir"
52 | "-e" -> add_flag "errorcodes"
53 | "-m" -> add_option "mda"
54 | "-q" -> add_flag "quiet"
55 | "-t" -> add_option "threshold"
56 | "-s" -> add_option "sockpath"
58 output_string
Pervasives.stderr
("Invalid option: " ^
option ^
"\n");
66 let options = parse_options argv
67 let confdir = get_option_with_default
options "confdir" default_confdir
69 (** Create an absolute path from a path, by prepending confdir if the path does not contain a slash. *)
70 let absolute_path path
=
71 if String.contains path '
/'
then path
72 else (confdir ^
"/" ^ path
)
74 (* Set constants from command line options *)
75 let sockpath = absolute_path (hash_get
options "sockpath" ~default
:default_sockpath)
76 let blocksize = hash_get_int
options "blocksize" ~default
:default_blocksize
77 let threshold = hash_get_float
options "threshold" ~default
:default_threshold
78 let quiet = hash_get_bool
options "quiet" ~default
:false
79 let passthrough = if quiet then false else default_passthrough
80 let header = if quiet then false else default_header
81 let errorcodes = hash_get_bool
options "errorcodes" ~default
:default_errorcodes
82 let input_channel = default_input
85 (match hash_get_maybe
options "mda" with
86 | None
-> default_output
87 | Some command
-> open_process_out command
)
92 let msg = String.create
blocksize in
93 let bytes_read = input
input_channel msg 0 blocksize in
97 (* If we didn't get any bytes, raise End_of_file *)
98 if bytes_read = 0 then raise End_of_file
;
99 (* We read n bytes; send them on to the daemon. *)
102 unix_connect
sockpath
104 failwith
("Cannot connect to " ^
sockpath)
106 let bytes_written = write
conn msg 0 bytes_read in
107 ignore
bytes_written;
108 shutdown
conn SHUTDOWN_SEND
;
109 (* Read response from daemon. *)
110 let response = input_line
(in_channel_of_descr
conn) in
111 let score = (float_of_string
response) in
112 if score > threshold then status := spam_status
118 | Unix_error
(errno
, funname
, _) ->
119 prerr_endline
(funname ^
": " ^
(error_message errno
))
121 prerr_endline
(Printexc.to_string error
)
124 (* Output X-Spam: header if requested *)
125 if header && (!status = 0 || !status = spam_status) then
126 output_string
output_channel ("X-Spam: " ^
127 (if !status = spam_status
132 (* Pass through message if requested *)
133 if passthrough then begin
136 output
output_channel msg 0 n
;
137 aux (input
input_channel msg 0 blocksize)
143 exit
(if errorcodes then 0 else !status)