Make the email date header RFC822-compliant.
authorMichael Orlitzky <michael@orlitzky.com>
Fri, 15 Oct 2010 17:01:02 +0000 (13:01 -0400)
committerMichael Orlitzky <michael@orlitzky.com>
Fri, 15 Oct 2010 17:01:02 +0000 (13:01 -0400)
src/Mail.hs
src/Main.hs

index ba605f977673ae3a76694888131767bfd383e255..3304d7677dd501734b027bf43158876cc6672a6e 100644 (file)
@@ -9,6 +9,7 @@ import Control.Exception (evaluate)
 import Data.List (intercalate)
 import System.Exit
 import System.Process
+import System.Time (CalendarTime(..), ClockTime, getClockTime, Month, toCalendarTime)
 import System.IO
 
 type Header = String
@@ -24,7 +25,7 @@ data Message = Message { headers :: [Header],
 -- |Showing a message will print it in roughly RFC-compliant
 -- form. This form is sufficient for handing the message off to
 -- sendmail.
-instance Show Message where    
+instance Show Message where
     show m =
         concat [ if (length (headers m) == 0) then "" else (intercalate "\n" (headers m)) ++ "\n",
                  "Subject: " ++ (subject m) ++ "\n",
@@ -34,6 +35,73 @@ instance Show Message where
                  (body m) ]
 
 
+
+-- |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)
+
+
+
+-- |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
+
+
+
 -- |Takes a message as an argument, and passes it to the system's
 -- sendmail binary.
 sendmail :: Message -> IO (String, String, ExitCode)
index 53c3f905e863e9c98537e4b62d5307335b573939..7025b4bb1544c43fe4d54ebaa92df6a1c4920970 100644 (file)
@@ -4,7 +4,6 @@ where
 import Control.Concurrent (forkIO, threadDelay)
 import Control.Monad (forever, when)
 import System.Exit (ExitCode(..), exitWith)
-import System.Time (getClockTime)
 import System.IO (hPutStrLn, stderr)
 
 import CommandLine
@@ -66,8 +65,8 @@ recurse username latest_status_id maybe_message = do
              recurse username new_latest_status_id maybe_message
              return ()
           Just message -> do
-             date <- getClockTime
-             let messages = map (message_from_status message (show date)) new_statuses
+             date_header <- construct_date_header
+             let messages = map (message_from_status message (date_header)) new_statuses
              sendmail_results <- mapM sendmail messages
              mapM print_sendmail_result sendmail_results
              recurse username new_latest_status_id maybe_message