]> gitweb.michael.orlitzky.com - dead/halcyon.git/blobdiff - src/Mail.hs
Fix a few hlint suggestions.
[dead/halcyon.git] / src / Mail.hs
index 7f0fd8ba805049aa51371e0a0440fc12fb2523b5..8c1f25c89874eae68547f8323387b6116223419e 100644 (file)
@@ -6,14 +6,16 @@ where
 import Control.Concurrent
 import Control.Exception (evaluate)
 import Data.List (intercalate)
+import Data.Time (formatTime, getZonedTime)
 import System.Exit
+import System.Locale (defaultTimeLocale, rfc822DateFormat)
 import System.Process
-import System.Time (CalendarTime(..), ClockTime, getClockTime, Month, toCalendarTime)
-import System.IO
+import System.IO (hClose, hGetContents, hPutStr)
+
 
 type Header = String
 
--- |A crude model of an RFC821 email message.
+-- | A crude model of an RFC821 email message.
 data Message = Message { headers :: [Header],
                          subject :: String,
                          body    :: String,
@@ -21,99 +23,61 @@ data Message = Message { headers :: [Header],
                          to      :: String }
              deriving (Eq)
 
+-- | The default headers attached to each message.  The MIME junk is
+--   needed for UTF-8 to work properly. Note that your mail server
+--   should support the 8BITMIME extension.
 default_headers :: [Header]
 default_headers = ["MIME-Version: 1.0",
-                   "Content-type: text/plain; charset=UTF-8"]
+                   "Content-Type: text/plain; charset=UTF-8",
+                   "Content-Transfer-Encoding: 8bit"]
 
--- |Showing a message will print it in roughly RFC-compliant
--- form. This form is sufficient for handing the message off to
--- sendmail.
+-- | Showing a message will print it in roughly RFC-compliant
+--   form. This form is sufficient for handing the message off to
+--   sendmail (or compatible).
 instance Show Message where
-    show m =
-        concat [ if (length (headers m) == 0) then "" else (intercalate "\n" (headers m)) ++ "\n",
-                 "Subject: " ++ (subject m) ++ "\n",
-                 "From: " ++ (from m) ++ "\n",
-                 "To: " ++ (to m) ++ "\n",
-                 "\n",
-                 (body m) ]
-
+  show m =
+    concat [ formatted_headers,
+             "Subject: " ++ (subject m) ++ "\n",
+             "From: " ++ (from m) ++ "\n",
+             "To: " ++ (to m) ++ "\n",
+             "\n",
+             (body m) ]
+    where
+      formatted_headers =
+        if null (headers m)
+        then ""
+        else (intercalate "\n" (headers m)) ++ "\n"
 
 
 -- |Pad a string on the left with zeros until the entire string has
 -- length n.
 pad_left :: String -> Int -> String
 pad_left str n
        | n < (length str) = str
        | otherwise = (replicate num_zeros '0') ++ str
-    where num_zeros = n - (length str)
+ | n < (length str) = str
+ | otherwise = (replicate num_zeros '0') ++ str
+   where num_zeros = n - (length str)
 
 
 
--- |Formats a month name according to RFC822.
-format_month :: Month -> String
-format_month month = take 3 (show month)
-
-
--- |Takes an offset from UTC (in seconds) and returns the four-digit
--- offset as a 'String' in +hhmm format.
-format_timezone :: Int -> String
-format_timezone seconds =
-    sign ++ pad_hh ++ pad_mm
-    where
-      seconds_norm = abs seconds
-      hh = seconds_norm `div` 3600
-      mm = (seconds_norm - (hh*3600)) `div` 60
-      pad_hh = pad_left (show hh) 2
-      pad_mm = pad_left (show mm) 2
-      sign = if seconds < 0 then "-" else "+"
-
-
--- |Takes a 'ClockTime' as an argument, and formats it as an RFC822 Date header.
---
--- See,
---
---   <http://cr.yp.to/immhf/date.html>
---
--- for information.
-format_clocktime :: ClockTime -> IO String
-format_clocktime ct = do
-  caltime <- (toCalendarTime ct)
-
-  let days = pad_left (show (ctDay caltime)) 2
-  let month = format_month (ctMonth caltime)
-  let year = show $ ctYear caltime
-  let hours = pad_left (show (ctHour caltime)) 2
-  let minutes = pad_left (show (ctMin caltime)) 2
-  let seconds = pad_left (show (ctSec caltime)) 2
-  let timezone = format_timezone (ctTZ caltime)
-
-  return $ concat [(show $ ctWDay caltime) ++ ", ",
-                   days ++ " ",
-                   month ++ " ",
-                   year ++ " ",
-                   hours ++ ":",
-                   minutes ++ ":",
-                   seconds ++ " ",
-                   timezone]
-
-
--- |Constructs an RFC822 Date header with the current date/time.
-construct_date_header :: IO String
-construct_date_header = do
-  date <- getClockTime
-  format_clocktime date
+-- | Constructs a 'String' in RFC822 date format for the current
+--   date/time.
+rfc822_now :: IO String
+rfc822_now = do
+  date <- getZonedTime
+  return $ formatTime defaultTimeLocale rfc822DateFormat date
 
 
 
 -- |Takes a message as an argument, and passes it to the system's
--- sendmail binary.
-sendmail :: Message -> IO (String, String, ExitCode)
-sendmail message = do
+-- sendmail (or compatible) binary.
+sendmail :: FilePath -> Message -> IO (String, String, ExitCode)
+sendmail sendmail_path message = do
   let sendmail_args = ["-f",
-                       (from message)]
+                       (from message),
+                       (to message)]
 
   (inh, outh, errh, ph) <-
-      runInteractiveProcess "/usr/bin/sendmail" sendmail_args Nothing Nothing
+      runInteractiveProcess sendmail_path sendmail_args Nothing Nothing
 
   outm <- newEmptyMVar
   outs <- hGetContents outh
@@ -137,8 +101,8 @@ sendmail message = do
 -- three-tuples.
 print_sendmail_result :: (String, String, ExitCode) -> IO ()
 print_sendmail_result (outs, errs, ec) = do
-    case ec of
-      ExitSuccess -> return ()
-      _ -> putStrLn $ concat ["Output: " ++ outs,
-                              "\nErrors: " ++ errs,
-                              "\nExit Code: " ++ (show ec)]
+  case ec of
+    ExitSuccess -> return ()
+    _ -> putStrLn $ concat ["Output: " ++ outs,
+                            "\nErrors: " ++ errs,
+                            "\nExit Code: " ++ (show ec)]