Fix the problem of corrupting binary attachments; changed to using Gerd S's
[cocanwiki.git] / scripts / contact.ml
index 436ee35..23dd68b 100644 (file)
@@ -1,7 +1,7 @@
 (* COCANWIKI - a wiki written in Objective CAML.
  * Written by Richard W.M. Jones <rich@merjis.com>.
  * Copyright (C) 2004 Merjis Ltd.
- * $Id: contact.ml,v 1.4 2004/09/25 12:53:55 rich Exp $
+ * $Id: contact.ml,v 1.12 2006/07/31 09:10:33 rich Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -30,12 +30,14 @@ open Cocanwiki
 open Cocanwiki_template
 open Cocanwiki_ok
 
-let run r (q : cgi) (dbh : Dbi.connection) hostid {hostname = hostname} user =
+let subj_rex = Pcre.regexp "\\$\\w+"
+
+let run r (q : cgi) dbh hostid {hostname = hostname} user =
   let template = get_template dbh hostid "contact.txt" in
 
   let fail msg =
     error ~back_button:true ~title:"Bad form"
-      q (msg ^ "  Please contact the owner of the site by email.");
+      dbh hostid q (msg ^ "  Please contact the owner of the site by email.");
     return ()
   in
 
@@ -43,29 +45,25 @@ let run r (q : cgi) (dbh : Dbi.connection) hostid {hostname = hostname} user =
   let name =
     try q#param "id"
     with
-       Not_found -> fail "The 'name' field is missing in that form." in
+       Not_found ->
+         fail "The 'name' field is missing in that form." in
 
   (* Get the contacts / emails from the database. *)
-  let sth = dbh#prepare_cached "select id, subject from contacts
-                                 where hostid = ? and name = ?" in
-  sth#execute [`Int hostid; `String name];
+  let rows = PGSQL(dbh)
+    "select id, subject from contacts
+      where hostid = $hostid and name = $name" in
 
   let id, subject =
-    try
-      (match sth#fetch1 () with
-          [ `Int id; `String subject ] -> id, subject
-        | _ -> assert false
-      )
-    with Not_found -> fail "There is no such contact form in the database." in
-
-  let sth = dbh#prepare_cached "select email from contact_emails
-                                 where contactid = ?" in
-  sth#execute [`Int id];
+    match rows with
+    | [row] -> row
+    | [] -> fail "There is no such contact form in the database."
+    | _ -> assert false in
 
-  let emails = sth#map (function [`String email] -> email
-                              | _ -> assert false) in
+  let to_addrs =
+    PGSQL(dbh) "select email from contact_emails where contactid = $id" in
+  let to_addrs = List.map (fun email -> "", email) to_addrs in
 
-  if emails = [] then
+  if to_addrs = [] then
     fail "There are no email addresses associated with that contact id.";
 
   (* Now process the strings passed as parameters to the script.  Any
@@ -102,6 +100,20 @@ let run r (q : cgi) (dbh : Dbi.connection) hostid {hostname = hostname} user =
     let not_empty name = (q#upload name).upload_value <> "" in
     List.filter not_empty uploads in
 
+  (* Substitute any $Field fields in the subject line.  The substitution
+   * is very simple-minded.
+   *)
+  let subst pat =
+    let n = String.length pat in
+    assert (n > 0 && pat.[0] = '$');
+    let fieldname = String.sub pat 1 (n-1) in
+    if List.mem fieldname names then
+      q#param fieldname
+    else
+      pat
+  in
+  let subject = Pcre.substitute ~rex:subj_rex ~subst subject in
+
   (* Get the IP address for logging purposes. *)
   let ip =
     try Connection.remote_ip (Request.connection r) with Not_found -> "" in
@@ -116,8 +128,8 @@ let run r (q : cgi) (dbh : Dbi.connection) hostid {hostname = hostname} user =
   let username =
     match user with
        Anonymous -> "anonymous"
-      | User (userid, username, _) ->
-         sprintf "%s (%d)" username userid in
+      | User (userid, username, _, _) ->
+         sprintf "%s (%ld)" username userid in
 
   template#set "ip" ip;
   template#set "ua" ua;
@@ -137,23 +149,24 @@ let run r (q : cgi) (dbh : Dbi.connection) hostid {hostname = hostname} user =
 
   (* Send the initial email. *)
   let body = template#to_string in
-  Sendmail.send_mail ~subject ~to_addr:emails ~body ();
+  let msg = Netsendmail.compose ~to_addrs ~subject body in
+  Netsendmail.sendmail msg;
 
   (* Send the following uploads by email. *)
   List.iter (fun name ->
               let upload = q#upload name in
               let subject = upload.upload_filename in
-              (* XXX This is insecure. *)
-              let content_type = upload.upload_content_type in
+              let content_type = upload.upload_content_type, [] in
               let body = upload.upload_value in
 
-              Sendmail.send_mail ~subject ~to_addr:emails ~content_type
-                ~body ())
+              let msg =
+                Netsendmail.compose ~to_addrs ~subject ~content_type body in
+              Netsendmail.sendmail msg)
     uploads;
 
   (* Confirm. *)
   ok ~title:"Thank you for your contact" ~buttons:[ok_button "/"]
-    q "An email was sent and you should receive a reply shortly."
+    dbh hostid q "An email was sent and you should receive a reply shortly."
 
 let () =
-  register_script run
+  register_script ~restrict:[CanView] run