diff --git a/PastePipe.cabal b/PastePipe.cabal
--- a/PastePipe.cabal
+++ b/PastePipe.cabal
@@ -1,24 +1,28 @@
--- cabal configure --prefix=$HOME --user
--- cabal build
 name:                PastePipe
-version:             1.3
-synopsis:            CLI for pasting to hpaste.org
-description:         PastePipe reads from standard in and posts to hpaste.org.
-                     It will auto-detect your username, but that can be 
-                     overridden with command line options (-u username)
+version:             1.5
+synopsis:            CLI for pasting to lpaste.net
+description:         PastePipe reads from standard in and posts to <lpaste.net>.
+                     It will auto-detect your username, but that can be
+                     overridden with command line options (--user)
                      Titles are set with -t, language with -l.
 category:            Utils
 license:             GPL
 License-file:        LICENSE
-homepage:            http://pastepipe.googlecode.com/
-bug-reports:         http://code.google.com/p/pastepipe/issues/list
+homepage:            http://github.com/creswick/pastepipe
+bug-reports:         http://github.com/creswick/pastepipe/issues
 author:              Rogan Creswick
 maintainer:          creswick@gmail.com
-Cabal-Version:       >=1.2	 
+Cabal-Version:       >=1.2
 build-type:          Simple
 
 
 Executable pastepipe
-  Main-is:           pastepipe.hs
+  hs-source-dirs:    src
+  Main-is:           Main.hs
   Build-Depends:     base >= 4 && < 5, HTTP, network, cmdargs
   ghc-options:       -Wall
+
+library
+  hs-source-dirs:    src
+  exposed-modules:   Utils.PastePipe
+  Build-Depends:     base >= 4 && < 5, HTTP, network, cmdargs
diff --git a/pastepipe.hs b/pastepipe.hs
deleted file mode 100644
--- a/pastepipe.hs
+++ /dev/null
@@ -1,114 +0,0 @@
-{-# LANGUAGE DeriveDataTypeable #-}
--- pastepipe.hs
--- 
--- A CLI for Hpaste.org.
---
---  Authored by Rogan Creswick (creswick_at_googles_mail_service.)
---
--- Pastepipe reads from stdin, posting to hpaste, and prints out the 
--- resulting url (the last line of output).  Parameters control various 
--- hpaste form fields:
---
---   -u username  (defaults to $USER)
---   -l language  (defaults to haskell, of course)
---   -t title     (defaults to the empty string)
---
--- It will auto-detect your local username, but -u overrides this detection.
--- 
--- compile with: 
--- ghci --make -package HTTP pastepipe.hs -o pastepipe
-
-module Main where
-
-import Network.HTTP.Base
-import Network.URI
-import Network.Browser
-import Data.Maybe
-import System.Environment (getEnv)
-import System.Console.CmdArgs
-
-main :: IO () 
-main = do
-  realUser <- getEnv "USER"
-  conf <- cmdArgs "PastePipe v1.3, (C) Rogan Creswick 2009" [config realUser]
-  content <- getContents
-  let postFn = if test conf then fakePost else post
-  resultUrl <- postFn conf content
-  putStrLn $ show resultUrl
-  
--- | Configuration type for PastePipe:
-data Config = Config { userName :: String
-                     , language :: String
-                     , title :: String
-                     , uri :: String
-                     , test :: Bool }
-              deriving (Show, Data, Typeable)
-
--- | Default config.
--- The string passed in is the current user's username.
-config :: String -> Mode Config
-config realUser = mode $ Config { 
-                    userName = realUser &= text 
-                      "Your user name"
-                      & typ "USER"
-                      & explicit & flag "user" & flag "u"
-                  , language = "haskell" &= text 
-                      "The language used for syntax highlighting"
-                      & typ "LANGUAGE"
-                  , title = "" &= text 
-                      "The title of the snippet"
-                      & typ "TITLE"
-                      & explicit & flag "title" & flag "t"
-                  , uri = defaultUri &= text 
-                      "The URI of the hpaste instance to post to"
-                      & typ "URL"
-                  , test = False &= text 
-                      "Prevents PastePipe from actually posting content, just echos the configuration and input"
-                  }
-
-
--- | Define an output handler based on the user-specified verbosity.
-outHandler :: String -> IO ()
-outHandler str = do
-  loud <- isLoud -- are we running in verbose mode?
-  if loud then (putStr str) else (const (return()) str)
-
--- | The "root" uri for hpaste.org
-defaultUri :: String 
-defaultUri = "http://hpaste.org/fastcgi/hpaste.fcgi/"
-
--- | The URI for posting new pastes to hpaste.
--- This isn't guaranteed to trigger a failure on all execution paths, as-is.
-saveUri :: String -> URI
-saveUri coreUri = buildURI coreUri "save"
-
--- | composes the core uri and a string to create a usable URI
-buildURI :: String -> String -> URI
-buildURI coreUri str = fromJust $ parseURI $ coreUri ++ str
-
--- | Posts the given content to hpaste.org, returning the new uri.
-post :: Config -> String -> IO URI
-post conf str = do 
-  (url, _) <- Network.Browser.browse $ do
-                  setOutHandler outHandler
-                  setAllowRedirects True -- handle HTTP redirects
-                  request $ buildRequest conf str
-  return url
-
--- | Creates the request to post a chunk of content.
-buildRequest :: Config -> String -> Request String
-buildRequest conf str = formToRequest $ Form POST (saveUri $ uri conf)
-                             [ ("title", title conf)
-                             , ("author", userName conf)
-                             , ("content", str)
-                             , ("language", language conf)
-                             , ("channel", "")]
-
-fakePost ::  Config -> String -> IO URI
-fakePost conf str = do 
-  putStrLn $ "uri: "++uri conf
-  putStrLn $ "user: "++userName conf
-  putStrLn $ "lang: "++language conf
-  putStrLn $ "title: "++title conf
-  putStrLn $ "content: "++str
-  return $ fromJust $ parseURI $ uri conf
diff --git a/src/Main.hs b/src/Main.hs
new file mode 100644
--- /dev/null
+++ b/src/Main.hs
@@ -0,0 +1,39 @@
+-- |
+-- Module      :  Main
+-- Copyright   :  (c) Ragon Creswick, 2009-2012
+--                    Mateusz Kowalczyk, 2014
+-- License     :  GPL-3
+--
+-- Entry point for the executable, using "Utils.PastePipe".
+--
+-- A CLI for lpaste.org.
+--
+--  Authored by Rogan Creswick (creswick_at_googles_mail_service.)
+--
+-- Pastepipe reads from stdin, posting to lpaste, and prints out the
+-- resulting url (the last line of output).  Parameters control various
+-- lpaste form fields:
+--
+--   --user         (defaults to $USER)
+--   -l --language  (defaults to haskell, of course)
+--   -t --title     (defaults to the empty string)
+--   -u --uri       (defaults to <http://lpaste.net>)
+--
+-- It will auto-detect your local username, but --user overrides this detection.
+--
+-- Use @cabal install@ to install this. The executable will be called
+-- @pastepipe@.
+module Main where
+
+import System.Console.CmdArgs
+import System.Environment (getEnv)
+import Utils.PastePipe
+
+main :: IO ()
+main = do
+  realUser <- getEnv "USER"
+  conf <- cmdArgs $ config realUser
+  content <- getContents
+  let postFn = if test conf then fakePost else post
+  resultUrl <- postFn conf content
+  print resultUrl
diff --git a/src/Utils/PastePipe.hs b/src/Utils/PastePipe.hs
new file mode 100644
--- /dev/null
+++ b/src/Utils/PastePipe.hs
@@ -0,0 +1,102 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+-- |
+-- Module      :  Utils.PastePipe
+-- Copyright   :  (c) Ragon Creswick, 2009-2012
+--                    Mateusz Kowalczyk, 2014
+-- License     :  GPL-3
+--
+-- Configuration and communication with lpaste.net
+module Utils.PastePipe where
+
+import Control.Monad (when)
+import Data.Maybe
+import Network.Browser
+import Network.HTTP.Base
+import Network.URI
+import System.Console.CmdArgs
+import System.Environment (getEnv)
+
+-- | Configuration type for PastePipe:
+data Config = Config { userName :: String
+                     , language :: String
+                     , title :: String
+                     , uri :: String
+                     , test :: Bool }
+              deriving (Show, Data, Typeable)
+
+config :: String -> Config
+config realUser = Config { userName = realUser
+                                &= help "Your user name"
+                                &= typ "USER"
+                                &= explicit
+                                &= name "user"
+                         , language = "haskell"
+                                &= help "The language used for syntax highlighting"
+                                &= typ "LANGUAGE"
+                         , title = ""
+                                &= help "The title of the snippet"
+                                &= typ "TITLE"
+                                &= explicit
+                                &= name "title"
+                                &= name "t"
+                         , uri = defaultUri
+                                &= help "The URI of the lpaste instance to post to"
+                                &= typ "URL"
+                         , test = False
+                                &= help "Prevents PastePipe from actually posting content, just echos the configuration and input"
+                         }
+                         &= summary "PastePipe v1.3, (C) Rogan Creswick 2009"
+                         &= program "pastepipe"
+
+-- | Takes a string to post to the default and returns the URI.
+-- Client code is expected to catch any exceptions.
+postWithDefaults :: String -> IO URI
+postWithDefaults s = getEnv "USER" >>= \u -> post (config u) s
+
+-- | Define an output handler based on the user-specified verbosity.
+outHandler :: String -> IO ()
+outHandler str = do
+  loud <- isLoud -- are we running in verbose mode?
+  when loud $ putStr str
+
+-- | The "root" uri for lpaste.net
+defaultUri :: String
+defaultUri = "http://lpaste.net/"
+
+-- | The URI for posting new pastes to lpaste.
+-- This isn't guaranteed to trigger a failure on all execution paths, as-is.
+saveUri :: String -> URI
+saveUri coreUri = buildURI coreUri "new"
+
+-- | composes the core uri and a string to create a usable URI
+buildURI :: String -> String -> URI
+buildURI coreUri str = fromJust $ parseURI $ coreUri ++ str
+
+-- | Posts the given content to lpaste.net, returning the new uri.
+post :: Config -> String -> IO URI
+post conf str = do
+  (url, _) <- Network.Browser.browse $ do
+                  setOutHandler outHandler
+                  setAllowRedirects True -- handle HTTP redirects
+                  request $ buildRequest conf str
+  return url
+
+-- | Creates the request to post a chunk of content.
+buildRequest :: Config -> String -> Request String
+buildRequest conf str = formToRequest $ Form POST (saveUri $ uri conf)
+                             [ ("title", title conf)
+                             , ("author", userName conf)
+                             , ("paste", str)
+                             , ("language", language conf)
+                             , ("channel", "")
+                             , ("email", "")
+                             ]
+
+fakePost ::  Config -> String -> IO URI
+fakePost conf str = do
+  putStrLn $ "uri: "++uri conf
+  putStrLn $ "user: "++userName conf
+  putStrLn $ "lang: "++language conf
+  putStrLn $ "title: "++title conf
+  putStrLn $ "content: "++str
+  return $ fromJust $ parseURI $ uri conf
