(* Copyright (c) 2000 Patrick Doane.
* For conditions of distribution and use, see copyright notice in LICENSE, *)
open Netchannels
open Printf
module U = Unix
let () =
Nettls_gnutls.init()
let bracket
(before : 'a -> 'b)
(after : 'b -> unit)
(f : 'b -> 'c)
(init : 'a) =
let x = before init in
let res =
try f x with exn -> after x; raise exn
in
after x;
res
let prompt ?(echo=true) s =
output_string stdout s;
flush stdout;
if echo then
input_line stdin
else
let fd = U.descr_of_in_channel stdin in
let tio = U.tcgetattr fd in
let old_echo = tio.U.c_echo in
bracket
(fun () ->
(* Modify terminal settings to turn echo off *)
tio.U.c_echo <- false;
U.tcsetattr fd U.TCSADRAIN tio)
(fun () ->
(* Restore terminal settings *)
tio.U.c_echo <- old_echo;
U.tcsetattr fd U.TCSADRAIN tio;
output_char stdout '\n';
flush stdout)
(fun _ ->
(* Get password from stdin *)
input_line stdin
) ()
let connect_to (server, port) =
let inet_addr = (U.gethostbyname server).U.h_addr_list.(0) in
let addr = U.ADDR_INET (inet_addr, port) in
U.open_connection addr
let close_connection (ic,oc) =
U.shutdown_connection ic;
close_out oc
let make_connection server port f =
bracket connect_to close_connection f (server,port)
let pop3_session =
bracket
(fun (ic,oc) -> new Netpop.client
(new input_channel ic) (new output_channel oc))
(fun sess ->
printf "Closing mailbox...\n"; flush stdout;
sess#quit ())
let main () =
let user = Netsaslprep.saslprep (prompt "User: ") in
let server = prompt "Hostname: " in
let passwd = Netsaslprep.saslprep (prompt ~echo:false "Password: ") in
let tls_config =
Netsys_tls.create_x509_config
~system_trust:true
~peer_auth:`Required (* try `None if TLS does not work *)
(Netsys_crypto.current_tls()) in
try
make_connection server Netpop.tcp_port (pop3_session
(fun sess ->
printf "Trying to start TLS...\n%!";
Netpop.authenticate
~tls_config
~tls_peer:server
sess;
if sess#tls_endpoint <> None then
printf "TLS succeeded\n%!"
else
printf "No TLS\n%!";
printf "Attempting authentication...\n%!";
( try
Netpop.authenticate
~sasl_mechs:[ (module Netmech_scram_sasl.SCRAM_SHA1);
(module Netmech_digest_sasl.DIGEST_MD5);
(module Netmech_crammd5_sasl.CRAM_MD5);
(module Netmech_plain_sasl.PLAIN);
]
~user
~creds:[ "password", passwd, [] ]
~sasl_params:[ "secure",
string_of_bool (sess#tls_endpoint = None),
true ]
(* i.e. if there is no TLS, disallow insecure SASL mechs *)
sess;
with
| Netpop.Authentication_error ->
printf "SASL failed, trying APOP\n%!";
( try
sess#apop user passwd;
with _ when sess#tls_endpoint <> None ->
printf "APOP failed, trying plaintext password.\n%!";
sess#user user;
sess#pass passwd;
)
);
printf "Successfully opened mailbox!\n%!";
let count,_,_ = sess#stat () in
printf "Mailbox has %d messages\n%!" count;
for i = 1 to count do
printf "message %d\n" i;
let hdr = sess#top i () in
let hdr = (string_of_in_obj_channel hdr) ^ "\n" in
let fields, _ =
Netmime_string.scan_header hdr 0 (String.length hdr)
in
List.iter (fun (name,body) ->
printf "%s: %s\n" name body;
flush stdout
) fields
done;
flush stdout;
)
)
with
| Not_found ->
printf "Error finding host %s\n%!" server
| Netpop.Authentication_error ->
printf "Cannot authenticate\n%!"
;;
(* Netpop.Debug.enable := true;; *)
U.handle_unix_error main ()