diff --git a/Intricacy.hs b/Intricacy.hs
new file mode 100644
--- /dev/null
+++ b/Intricacy.hs
@@ -0,0 +1,48 @@
+-- This file is part of Intricacy
+-- Copyright (C) 2013 Martin Bays <mbays@sdf.org>
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of version 3 of the GNU General Public License as
+-- published by the Free Software Foundation, or any later version.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see http://www.gnu.org/licenses/.
+
+{-# LANGUAGE CPP #-}
+#ifdef APPLE
+{-# LANGUAGE ForeignFunctionInterface #-}
+#endif
+module Main where
+
+#ifdef MAIN_SDL
+import qualified SDLUI (UIM)
+import SDLUIMInstance ()
+#endif
+
+#ifdef MAIN_CURSES
+import qualified CursesUI (UIM)
+import CursesUIMInstance ()
+#endif
+
+import Init
+import MainState
+
+#ifdef APPLE
+foreign export ccall hs_MAIN :: IO ()
+
+hs_MAIN :: IO ()
+hs_MAIN = main
+#endif
+
+main = main'
+#ifdef MAIN_SDL
+    (Just (doUI::SDLUI.UIM MainState -> IO (Maybe MainState)))
+#else
+    (Nothing :: (Maybe (CursesUI.UIM MainState -> IO (Maybe MainState))))
+#endif
+
+#ifdef MAIN_CURSES
+    (Just (doUI::CursesUI.UIM MainState -> IO (Maybe MainState)))
+#else
+    (Nothing :: (Maybe (SDLUI.UIM MainState -> IO (Maybe MainState))))
+#endif
diff --git a/MainBoth.hs b/MainBoth.hs
deleted file mode 100644
--- a/MainBoth.hs
+++ /dev/null
@@ -1,33 +0,0 @@
--- This file is part of Intricacy
--- Copyright (C) 2013 Martin Bays <mbays@sdf.org>
---
--- This program is free software: you can redistribute it and/or modify
--- it under the terms of version 3 of the GNU General Public License as
--- published by the Free Software Foundation, or any later version.
---
--- You should have received a copy of the GNU General Public License
--- along with this program.  If not, see http://www.gnu.org/licenses/.
-
-{-# OPTIONS_GHC -cpp #-}
-#ifdef APPLE
-{-# LANGUAGE ForeignFunctionInterface #-}
-#endif
-module Main where
-
-import Init
-import qualified SDLUI (UIM)
-import SDLUIMInstance ()
-import qualified CursesUI (UIM)
-import CursesUIMInstance ()
-import MainState
-
-#ifdef APPLE
-foreign export ccall hs_MAIN :: IO ()
-
-hs_MAIN :: IO ()
-hs_MAIN = main
-#endif
-
-main = main'
-    (Just (doUI::SDLUI.UIM MainState -> IO (Maybe MainState)))
-    (Just (doUI::CursesUI.UIM MainState -> IO (Maybe MainState)))
diff --git a/MainCurses.hs b/MainCurses.hs
deleted file mode 100644
--- a/MainCurses.hs
+++ /dev/null
@@ -1,20 +0,0 @@
--- This file is part of Intricacy
--- Copyright (C) 2013 Martin Bays <mbays@sdf.org>
---
--- This program is free software: you can redistribute it and/or modify
--- it under the terms of version 3 of the GNU General Public License as
--- published by the Free Software Foundation, or any later version.
---
--- You should have received a copy of the GNU General Public License
--- along with this program.  If not, see http://www.gnu.org/licenses/.
-
-module Main where
-
-import Init
-import qualified CursesUI (UIM)
-import CursesUIMInstance ()
-import MainState
-
-main = main'
-    (Nothing :: (Maybe (CursesUI.UIM MainState -> IO (Maybe MainState))))
-    (Just (doUI::CursesUI.UIM MainState -> IO (Maybe MainState)))
diff --git a/MainSDL.hs b/MainSDL.hs
deleted file mode 100644
--- a/MainSDL.hs
+++ /dev/null
@@ -1,31 +0,0 @@
--- This file is part of Intricacy
--- Copyright (C) 2013 Martin Bays <mbays@sdf.org>
---
--- This program is free software: you can redistribute it and/or modify
--- it under the terms of version 3 of the GNU General Public License as
--- published by the Free Software Foundation, or any later version.
---
--- You should have received a copy of the GNU General Public License
--- along with this program.  If not, see http://www.gnu.org/licenses/.
-
-{-# OPTIONS_GHC -cpp #-}
-#ifdef APPLE
-{-# LANGUAGE ForeignFunctionInterface #-}
-#endif
-module Main where
-
-import Init
-import qualified SDLUI
-import SDLUIMInstance ()
-import MainState
-
-#ifdef APPLE
-foreign export ccall hs_MAIN :: IO ()
-
-hs_MAIN :: IO ()
-hs_MAIN = main
-#endif
-
-main = main'
-    (Just (doUI::SDLUI.UIM MainState -> IO (Maybe MainState)))
-    (Nothing :: (Maybe (SDLUI.UIM MainState -> IO (Maybe MainState))))
diff --git a/NEWS b/NEWS
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,7 @@
 This is an abbreviated summary; see the git log for gory details.
 
+0.7.2.1:
+    Support >=ghc-8.6.5
 0.7.2:
     Support ghc-8.0
     Use Argon2 for server-side password hashing
diff --git a/SDLUI.hs b/SDLUI.hs
--- a/SDLUI.hs
+++ b/SDLUI.hs
@@ -8,7 +8,7 @@
 -- You should have received a copy of the GNU General Public License
 -- along with this program.  If not, see http://www.gnu.org/licenses/.
 
-{-# OPTIONS_GHC -cpp #-}
+{-# LANGUAGE CPP #-}
 
 module SDLUI where
 
diff --git a/SDLUIMInstance.hs b/SDLUIMInstance.hs
--- a/SDLUIMInstance.hs
+++ b/SDLUIMInstance.hs
@@ -8,8 +8,8 @@
 -- You should have received a copy of the GNU General Public License
 -- along with this program.  If not, see http://www.gnu.org/licenses/.
 
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE FlexibleInstances, FlexibleContexts #-}
-{-# OPTIONS_GHC -cpp #-}
 module SDLUIMInstance () where
 
 import Graphics.UI.SDL hiding (flip, name)
@@ -251,8 +251,6 @@
                     | (sign,score,pos) <-
                         [ ('-',-negScore,posLeft+^neg hv+^hw)
                         , ('+',posScore,posRight+^neg hv+^hw) ] ]
-
-        drawMainState' _ = return ()
 
     drawMessage = say
     drawPrompt full s = say $ s ++ (if full then "" else "_")
diff --git a/Server.hs b/Server.hs
--- a/Server.hs
+++ b/Server.hs
@@ -528,8 +528,7 @@
             Nothing -> return ()
             Just feedPath -> lift $ void $ forkIO $ do
                 let baseFeed = withFeedTitle (TS.pack "Intricacy updates") $ newFeed $ RSSKind Nothing
-                feed <- (parseFeedFromFile feedPath) `catchAll`
-                    (const $ return baseFeed)
+                feed <- fromMaybe baseFeed <$> parseFeedFromFile feedPath
                 time <- formatTime defaultTimeLocale rfc822DateFormat <$> getZonedTime
                 let newsText = TS.pack news
                     timeText = TS.pack time
diff --git a/intricacy.cabal b/intricacy.cabal
--- a/intricacy.cabal
+++ b/intricacy.cabal
@@ -1,18 +1,12 @@
-name:                intricacy
-version:             0.7.2
-synopsis:            A game of competitive puzzle-design
-homepage:            http://mbays.freeshell.org/intricacy
-license:             GPL-3
-license-file:        COPYING
-author:              Martin Bays
-maintainer:          mbays@sdf.org
--- copyright:           
-category:            Game
-build-type:          Simple
-cabal-version:       >=1.10
-data-files: VeraMoBd.ttf tutorial/*.lock tutorial/*.text sounds/*.ogg
-extra-source-files: Main_stub.h README BUILD NEWS tutorial-extra/*.lock tutorial-extra/README
-
+cabal-version:      >=1.10
+name:               intricacy
+version:            0.7.2.1
+license:            GPL-3
+license-file:       COPYING
+maintainer:         mbays@sdf.org
+author:             Martin Bays
+homepage:           http://mbays.freeshell.org/intricacy
+synopsis:           A game of competitive puzzle-design
 description:
     A networked game with client-server architecture. The core game is a
     lockpicking-themed turn-based puzzle game on a hex grid. Players design
@@ -25,110 +19,218 @@
     incorporates an implementation of a graph 5-colouring algorithm (see
     GraphColouring.hs).
 
+category:           Game
+build-type:         Simple
+data-files:
+    VeraMoBd.ttf
+    tutorial/*.lock
+    tutorial/*.text
+    sounds/*.ogg
+
+extra-source-files:
+    Main_stub.h
+    README
+    BUILD
+    NEWS
+    tutorial-extra/*.lock
+    tutorial-extra/README
+
 source-repository head
-   type:     git
-   location: http://mbays.freeshell.org/intricacy/.git
+    type:     git
+    location: http://mbays.freeshell.org/intricacy/.git
 
-Flag Game
-    Description: Build game
-    Default: True
-    Manual: True
-Flag SDL 
-    Description: Enable SDL UI
-    Default: True
-Flag Sound 
-    Description: Enable sound
-    Default: True
-Flag Curses 
-    Description: Enable Curses UI
-    Default: True
-Flag Server
-    Description: Build server
-    Default: False
-    Manual: True
+flag game
+    description: Build game
+    manual:      True
 
+flag sdl
+    description: Enable SDL UI
+
+flag sound
+    description: Enable sound
+
+flag curses
+    description: Enable Curses UI
+
+flag server
+    description: Build server
+    default:     False
+    manual:      True
+
 executable intricacy
-  if flag(Game)
-      default-extensions: DoAndIfThenElse
-      build-depends: base >=4.3, base < 5
-        , mtl >=2.2, transformers >=0.4, stm >= 2.1
-        , directory >= 1.0, filepath >= 1.0, time >= 1.2
-        , bytestring >=0.10
-        , array >=0.3, containers >=0.4, vector >=0.9
-        , binary >=0.5, network-fancy >= 0.1.5
-        , cryptohash >= 0.8
-        , safe >= 0.2
-        , RSA >= 2.0, crypto-pubkey-types >= 0.2, crypto-api >= 0.10
-      if !impl(ghc >= 8.0)
-        build-depends: semigroups == 0.18.*
-      if flag(SDL)
-          build-depends: SDL >=0.6.5, SDL-ttf >=0.6, SDL-gfx >=0.6
-          if flag(Sound)
-              cpp-options: -DSOUND
-              build-depends: SDL-mixer >= 0.6, random >= 1.0
-          if os(windows)
-              -- Extra-Lib-Dirs:    winlibs
-              Extra-Libraries:   SDL_ttf SDL SDL_gfx freetype
-              if flag(Sound)
-                  Extra-Libraries: SDL_mixer
-              ghc-options: -optl-mwindows
-          if os(darwin)
-              -- network-fancy-0.2.1+ causes a ___xpg_strerror_r link error
-              build-depends: network-fancy < 0.2.1
-              -- workaround for SDL on OS X, borrowed from TimePiece-0.0.5
-              cpp-options: -DAPPLE
-              ghc-options: -no-hs-main
-              include-dirs: /usr/include/SDL /usr/local/include/SDL
-              c-sources: c_main.c
-      if flag(Curses)
-          build-depends: hscurses >=1.4
-      if flag(SDL)
-          if flag(Curses)
-            main-is: MainBoth.hs
-          else
-            main-is: MainSDL.hs
-      else
-          if flag(Curses)
-            main-is: MainCurses.hs
-          else
-            Buildable: False
-            -- XXX: there must be a neater way to prevent the cabal flag sat
-            -- solver from thinking it's acceptable to have both SDL and Curses be
-            -- False... but this will have to do for now:
-            build-depends: Unsatisfiable >= 1337
-  else
-      main-is: MainBoth.hs
-      Buildable: False
+    main-is:          Intricacy.hs
+    other-modules:
+        AsciiLock
+        BinaryInstances
+        BoardColouring
+        Cache
+        Command
+        CVec
+        Database
+        EditGameState
+        Frame
+        GameState
+        GameStateTypes
+        GraphColouring
+        Hex
+        Init
+        InputMode
+        Interact
+        InteractUtil
+        KeyBindings
+        Lock
+        MainState
+        Maxlocksize
+        Metagame
+        Mundanities
+        Paths_intricacy
+        Physics
+        Protocol
+        ServerAddr
+        Util
+        Version
 
-  default-language: Haskell2010
-  other-modules: AsciiLock, BinaryInstances, BoardColouring, Cache, Command,
-      CursesRender, CursesUI, CursesUIMInstance, CVec, Database,
-      EditGameState, Frame, GameState, GameStateTypes, GraphColouring, Hex, Init,
-      InputMode, Interact, InteractUtil, KeyBindings, Lock, MainState,
-      Maxlocksize, Metagame, Mundanities, Physics, Protocol, SDLGlyph,
-      SDLRender, SDLUI, SDLUIMInstance, ServerAddr, Util, Version
+    default-language: Haskell2010
 
+    if !flag(game)
+        buildable: False
+
+    else
+        default-extensions: DoAndIfThenElse
+        build-depends:
+            base >=4.3 && <5,
+            mtl >=2.1.3.1 && <2.3,
+            transformers >=0.3.0.0 && <0.6,
+            stm >=2.1 && <2.6,
+            directory >=1.0 && <1.4,
+            filepath >=1.0 && <1.5,
+            time >=1.2 && <1.10,
+            bytestring ==0.10.*,
+            array >=0.3 && <0.6,
+            containers >=0.4 && <0.7,
+            vector >=0.9 && <0.13,
+            binary >=0.5 && <0.9,
+            network-fancy >=0.1.5 && <0.3,
+            cryptohash >=0.8,
+            safe >=0.2 && <0.4,
+            RSA >=2.0 && <2.5,
+            crypto-pubkey-types >=0.2 && <0.5,
+            crypto-api >=0.10 && <0.14
+
+        if !impl(ghc >=8.0)
+            build-depends: semigroups ==0.18.*
+
+        if flag(sdl)
+            build-depends:
+                SDL >=0.6.5 && <0.7,
+                SDL-ttf ==0.6.*,
+                SDL-gfx >=0.6 && <0.8
+
+            if flag(sound)
+                cpp-options:   -DSOUND
+                build-depends:
+                    SDL-mixer ==0.6.*,
+                    random >=1.0 && <1.2
+
+            if os(windows)
+                extra-libraries:
+                    SDL_ttf
+                    SDL
+                    SDL_gfx
+                    freetype
+
+                ghc-options:     -optl-mwindows
+
+                if flag(sound)
+                    extra-libraries: SDL_mixer
+
+            if os(osx)
+                cpp-options:   -DAPPLE
+                c-sources:     c_main.c
+                include-dirs:  /usr/include/SDL /usr/local/include/SDL
+                ghc-options:   -no-hs-main
+                build-depends: network-fancy <0.2.1
+
+        if flag(curses)
+            cpp-options:     -DMAIN_CURSES
+            other-modules:
+                CursesRender
+                CursesUI
+                CursesUIMInstance
+
+            extra-libraries: tinfow
+            build-depends:   hscurses ==1.4.*
+
+        if flag(sdl)
+            cpp-options:   -DMAIN_SDL
+            other-modules:
+                SDLGlyph
+                SDLRender
+                SDLUI
+                SDLUIMInstance
+
+        if (!flag(sdl) && !flag(curses))
+            buildable:     False
+            build-depends: base <0
+
 executable intricacy-server
-  if flag(Server)
-      default-extensions: DoAndIfThenElse
-      build-depends: base >=4.3, base < 5
-        , mtl >=2.2, transformers >=0.4, stm >= 2.1
-        , directory >= 1.0, filepath >= 1.0, time >= 1.5
-        , bytestring >=0.10
-        , array >=0.3, containers >=0.4, vector >=0.9
-        , binary >=0.5, network-fancy >= 0.1.5
-        , cryptohash >= 0.8
-        , RSA >= 2.0, crypto-pubkey-types >= 0.2, crypto-api >= 0.10
-        , random >= 1.0, pipes >= 4
-        , feed >= 1.0.0, xml-conduit >= 1.0.0
-        , email-validate >= 1.0.0, text, text-short, smtp-mail >= 0.1.4.1
-        , argon2 >= 1.3
-      if !impl(ghc >= 8.0)
-        build-depends: semigroups == 0.18.*
-  else
-    Buildable: False
-  main-is:  Server.hs
-  default-language: Haskell2010
-  other-modules: AsciiLock, BinaryInstances, BoardColouring, CVec, Database,
-      Frame, GameState, GameStateTypes, GraphColouring, Hex, Lock,
-      Maxlocksize, Metagame, Mundanities, Physics, Protocol, Util, Version
+    main-is:          Server.hs
+    other-modules:
+        AsciiLock
+        BinaryInstances
+        BoardColouring
+        CVec
+        Database
+        Frame
+        GameState
+        GameStateTypes
+        GraphColouring
+        Hex
+        Lock
+        Maxlocksize
+        Metagame
+        Mundanities
+        Paths_intricacy
+        Physics
+        Protocol
+        Util
+        Version
+
+    default-language: Haskell2010
+
+    if flag(server)
+        default-extensions: DoAndIfThenElse
+        build-depends:
+            base >=4.3,
+            base <5,
+            mtl >=2.2,
+            transformers >=0.4,
+            stm >=2.1,
+            directory >=1.0,
+            filepath >=1.0,
+            time >=1.5,
+            bytestring >=0.10,
+            array >=0.3,
+            containers >=0.4,
+            vector >=0.9,
+            binary >=0.5,
+            network-fancy >=0.1.5,
+            cryptohash >=0.8,
+            RSA >=2.0,
+            crypto-pubkey-types >=0.2,
+            crypto-api >=0.10,
+            random >=1.0,
+            pipes >=4,
+            feed >=1.1.0,
+            xml-conduit >=1.0.0,
+            email-validate >=1.0.0,
+            text -any,
+            text-short -any,
+            smtp-mail >=0.1.4.1,
+            argon2 >=1.3
+
+        if !impl(ghc >=8.0)
+            build-depends: semigroups ==0.18.*
+
+    else
+        buildable: False
