diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,12 @@
 # Revision history for glirc2
 
+## 2.25
+* `/ignore` can list ignores and supports full wildcard masks
+* Updated C extension API
+* Improved OTR extension to avoid interacting with ZNC replays
+* Added `protocol-family` configuration option. Set to `inet` or
+  `inet6` to force a particular IP protocol.
+
 ## 2.24
 
 * `/query` now takes a message parameter and tab-completes
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -16,8 +16,7 @@
 up-to-date:
 
 ```
-$ cabal update # if you're using cabal
-$ stack update # if you're using stack
+$ cabal update
 ```
 
 To install the latest version from Hackage using cabal-install:
@@ -33,16 +32,6 @@
 $ cabal build
 ```
 
-Building with stack
-
-```
-$ stack init --resolver=lts-8 --solver
-$ stack build
-```
-
-Note that if you're using a *nightly* resolver that you'll need to work around a
-bug in stack by manually installing `alex` and `happy`.
-
 Client Features
 ===============
 
@@ -119,6 +108,7 @@
     sasl-password: "somepass"
     socks-host:    "socks5.example.com"
     socks-port:    8080 -- defaults to 1080
+    log-dir:       "/home/myuser/ircLogs"
 
   * name: "example"
     hostname:      "example.com"
diff --git a/glirc.cabal b/glirc.cabal
--- a/glirc.cabal
+++ b/glirc.cabal
@@ -1,5 +1,5 @@
 name:                glirc
-version:             2.24
+version:             2.25
 synopsis:            Console IRC client
 description:         Console IRC client
                      .
@@ -89,6 +89,7 @@
                        Client.Image.StatusLine
                        Client.Image.Textbox
                        Client.Log
+                       Client.Mask
                        Client.Message
                        Client.Network.Async
                        Client.Network.Connect
@@ -104,6 +105,7 @@
                        Client.View.ChannelInfo
                        Client.View.Digraphs
                        Client.View.Help
+                       Client.View.IgnoreList
                        Client.View.KeyMap
                        Client.View.MaskList
                        Client.View.Mentions
@@ -133,13 +135,13 @@
                        containers           >=0.5.7  && <0.6,
                        directory            >=1.2.6  && <1.4,
                        filepath             >=1.4.1  && <1.5,
-                       free                 >=4.12   && <4.13,
+                       free                 >=4.12   && <5.1,
                        gitrev               >=1.2    && <1.4,
                        hashable             >=1.2.4  && <1.3,
-                       hookup               >=0.1    && <0.2,
+                       hookup               >=0.2    && <0.3,
                        irc-core             >=2.3    && <2.4,
-                       kan-extensions       >=5.0    && <5.1,
-                       lens                 >=4.14   && <4.16,
+                       kan-extensions       >=5.0    && <5.2,
+                       lens                 >=4.14   && <4.17,
                        network              >=2.6.2  && <2.7,
                        process              >=1.4.2  && <1.7,
                        regex-tdfa           >=1.2    && <1.3,
@@ -149,12 +151,12 @@
                        stm                  >=2.4    && <2.5,
                        template-haskell     >=2.11   && <2.13,
                        text                 >=1.2.2  && <1.3,
-                       time                 >=1.6    && <1.9,
+                       time                 >=1.6    && <1.10,
                        transformers         >=0.5.2  && <0.6,
                        unix                 >=2.7    && <2.8,
                        unordered-containers >=0.2.7  && <0.3,
                        vector               >=0.11   && <0.13,
-                       vty                  >=5.11.1 && <5.18
+                       vty                  >=5.11.1 && <5.20
 
 test-suite test
   type:                exitcode-stdio-1.0
diff --git a/include/glirc-api.h b/include/glirc-api.h
--- a/include/glirc-api.h
+++ b/include/glirc-api.h
@@ -40,8 +40,7 @@
 };
 
 struct glirc_command {
-        const struct glirc_string *params;
-        size_t params_n;
+        struct glirc_string command;
 };
 
 typedef void *start_type         (struct glirc *G, const char *path);
diff --git a/src/Client/CApi.hs b/src/Client/CApi.hs
--- a/src/Client/CApi.hs
+++ b/src/Client/CApi.hs
@@ -167,11 +167,11 @@
 -- | Notify an extension of a client command with the given parameters.
 commandExtension ::
   Ptr ()          {- ^ client state stableptr -} ->
-  [Text]          {- ^ parameters             -} ->
+  Text            {- ^ command                -} ->
   ActiveExtension {- ^ extension to command   -} ->
   IO ()
-commandExtension stab params ae = evalNestedIO $
-  do cmd <- withCommand params
+commandExtension stab command ae = evalNestedIO $
+  do cmd <- withCommand command
      let f = fgnCommand (aeFgn ae)
      liftIO $ unless (f == nullFunPtr)
             $ runProcessCommand f stab (aeSession ae) cmd
@@ -209,12 +209,11 @@
      nest1 $ with $ FgnChat net' tgt' msg'
 
 withCommand ::
-  [Text] {- ^ parameters -} ->
+  Text {- ^ command -} ->
   NestedIO (Ptr FgnCmd)
-withCommand params =
-  do prms          <- traverse withText params
-     (prmN,prmPtr) <- nest2 $ withArrayLen prms
-     nest1 $ with $ FgnCmd prmPtr (fromIntegral prmN)
+withCommand command =
+  do cmd <- withText command
+     nest1 $ with $ FgnCmd cmd
 
 withTag :: TagEntry -> NestedIO (FgnStringLen, FgnStringLen)
 withTag (TagEntry k v) =
diff --git a/src/Client/CApi/Types.hsc b/src/Client/CApi/Types.hsc
--- a/src/Client/CApi/Types.hsc
+++ b/src/Client/CApi/Types.hsc
@@ -223,20 +223,16 @@
 
 -- | @struct glirc_command@
 data FgnCmd = FgnCmd
-  { fcParams  :: Ptr FgnStringLen -- ^ array
-  , fcParamN  :: CSize            -- ^ array length
+  { fcCommand :: FgnStringLen
   }
 
 instance Storable FgnCmd where
   alignment _ = #alignment struct glirc_command
   sizeOf    _ = #size      struct glirc_command
   peek p      = FgnCmd
-            <$> (#peek struct glirc_command, params  ) p
-            <*> (#peek struct glirc_command, params_n) p
+            <$> (#peek struct glirc_command, command) p
 
-  poke p FgnCmd{..} =
-             do (#poke struct glirc_command, params  ) p fcParams
-                (#poke struct glirc_command, params_n) p fcParamN
+  poke p FgnCmd{..} = (#poke struct glirc_command, command) p fcCommand
 
 ------------------------------------------------------------------------
 
diff --git a/src/Client/Commands.hs b/src/Client/Commands.hs
--- a/src/Client/Commands.hs
+++ b/src/Client/Commands.hs
@@ -33,6 +33,7 @@
 import           Client.Commands.Recognizer
 import           Client.Commands.WordCompletion
 import           Client.Configuration
+import           Client.Mask
 import           Client.Message
 import           Client.State
 import           Client.State.Channel
@@ -627,9 +628,29 @@
 
   , Command
       (pure "ignore")
-      (remainingArg "nicks")
-      "Toggle the soft-ignore on each of the space-delimited given nicknames.\n"
-    $ ClientCommand cmdIgnore simpleClientTab
+      (remainingArg "masks")
+      "\^BParameters:\^B\n\
+      \\n\
+      \    masks: List of masks\n\
+      \\n\
+      \\^BDescription:\^B\n\
+      \\n\
+      \    Toggle the soft-ignore on each of the space-delimited given\n\
+      \    nicknames. Ignores can use \^B*\^B (many) and \^B?\^B (one) wildcards.\n\
+      \    Masks can be of the form: nick[[!user]@host]\n\
+      \    Masks use a case-insensitive comparison.\n\
+      \\n\
+      \    If no masks are specified the current ignore list is displayed.\n\
+      \\n\
+      \\^BExamples:\^B\n\
+      \\n\
+      \    /ignore\n\
+      \    /ignore nick1 nick2 nick3\n\
+      \    /ignore nick@host\n\
+      \    /ignore nick!user@host\n\
+      \    /ignore *@host\n\
+      \    /ignore *!baduser@*\n"
+    $ ClientCommand cmdIgnore tabIgnore
 
   , Command
       (pure "grep")
@@ -1890,15 +1911,28 @@
 
 cmdIgnore :: ClientCommand String
 cmdIgnore st rest =
-  case mkId . Text.pack <$> words rest of
-    [] -> commandFailureMsg "bad arguments" st
-    xs -> commandSuccess
-            $ over clientIgnores updateIgnores st
+  case mkId <$> Text.words (Text.pack rest) of
+    [] -> commandSuccess (changeSubfocus FocusIgnoreList st)
+    xs -> commandSuccess st2
       where
+        (newIgnores, st1) = (clientIgnores <%~ updateIgnores) st
+        st2 = set clientIgnoreMask (buildMask (toList newIgnores)) st1
+
         updateIgnores :: HashSet Identifier -> HashSet Identifier
         updateIgnores s = foldl' updateIgnore s xs
+
         updateIgnore s x = over (contains x) not s
 
+-- | Complete the nickname at the current cursor position using the
+-- userlist for the currently focused channel (if any)
+tabIgnore :: Bool {- ^ reversed -} -> ClientCommand String
+tabIgnore isReversed st _ =
+  simpleTabCompletion mode hint completions isReversed st
+  where
+    hint          = activeNicks st
+    completions   = currentCompletionList st ++ views clientIgnores toList st
+    mode          = currentNickCompletionMode st
+
 -- | Implementation of @/reload@
 --
 -- Attempt to reload the configuration file
@@ -2054,7 +2088,7 @@
     -- the window line when that action was significant enough to
     -- be considered a hint for tab completion.
     summaryActor :: IrcSummary -> Maybe Identifier
-    summaryActor (ChatSummary who) = Just who
+    summaryActor (ChatSummary who) = Just $! userNick who
     summaryActor _                 = Nothing
 
 -- | Use the *!*@host masks of users for channel lists when setting list modes
@@ -2114,13 +2148,13 @@
     mode          = currentNickCompletionMode st
 
 cmdExtension :: ClientCommand (String, String)
-cmdExtension st (name,params) =
+cmdExtension st (name,command) =
   case find (\ae -> aeName ae == Text.pack name)
             (view (clientExtensions . esActive) st) of
         Nothing -> commandFailureMsg "unknown extension" st
         Just ae ->
           do (st',_) <- clientPark st $ \ptr ->
-                          commandExtension ptr (Text.pack <$> words params) ae
+                          commandExtension ptr (Text.pack command) ae
              commandSuccess st'
 
 -- | Implementation of @/exec@ command.
diff --git a/src/Client/Configuration.hs b/src/Client/Configuration.hs
--- a/src/Client/Configuration.hs
+++ b/src/Client/Configuration.hs
@@ -93,7 +93,7 @@
   , _configMacros          :: Recognizer Macro -- ^ command macros
   , _configExtensions      :: [FilePath] -- ^ paths to shared library
   , _configUrlOpener       :: Maybe FilePath -- ^ paths to url opening executable
-  , _configIgnores         :: HashSet Identifier -- ^ initial ignore list
+  , _configIgnores         :: [Text] -- ^ initial ignore mask list
   , _configActivityBar     :: Bool -- ^ initially visibility of the activity bar
   , _configBellOnMention   :: Bool -- ^ notify terminal on mention
   , _configHideMeta        :: Bool -- ^ default setting for hidemeta on new windows
@@ -273,7 +273,7 @@
                                "Extra words to highlight in chat messages"
      _configNickPadding     <- sec' NoPadding "nick-padding" nickPaddingSpec
                                "Amount of space to reserve for nicknames in chat messages"
-     _configIgnores         <- sec' mempty "ignores" identifierSetSpec
+     _configIgnores         <- sec' [] "ignores" valuesSpec
                                "Set of nicknames to ignore on startup"
      _configActivityBar     <- sec' False  "activity-bar" yesOrNoSpec
                                "Show channel names and message counts for activity on\
diff --git a/src/Client/Configuration/ServerSettings.hs b/src/Client/Configuration/ServerSettings.hs
--- a/src/Client/Configuration/ServerSettings.hs
+++ b/src/Client/Configuration/ServerSettings.hs
@@ -47,6 +47,7 @@
   , ssAutoconnect
   , ssNickCompletion
   , ssLogDir
+  , ssProtocolFamily
 
   -- * Load function
   , loadDefaultServerSettings
@@ -68,7 +69,7 @@
 import           Data.Text (Text)
 import qualified Data.Text as Text
 import           Irc.Identifier (Identifier, mkId)
-import           Network.Socket (HostName, PortNumber)
+import           Network.Socket (HostName, PortNumber, Family(..))
 import           System.Environment
 
 -- | Static server-level settings
@@ -100,6 +101,7 @@
   , _ssAutoconnect      :: Bool -- ^ Connect to this network on server startup
   , _ssNickCompletion   :: WordCompletionMode -- ^ Nick completion mode for this server
   , _ssLogDir           :: Maybe FilePath -- ^ Directory to save logs of chat
+  , _ssProtocolFamily   :: Maybe Family -- ^ Protocol family to connect with
   }
   deriving Show
 
@@ -148,6 +150,7 @@
        , _ssAutoconnect      = False
        , _ssNickCompletion   = defaultNickWordCompleteMode
        , _ssLogDir           = Nothing
+       , _ssProtocolFamily   = Nothing
        }
 
 serverSpec :: ValueSpecs (ServerSettings -> ServerSettings)
@@ -249,7 +252,17 @@
 
       , opt "log-dir" ssLogDir stringSpec
         "Path to log file directory for this server"
+
+      , opt "protocol-family" ssProtocolFamily protocolFamilySpec
+        "IP protocol family to use for this connection"
       ]
+
+
+-- | Specification for IP protocol family.
+protocolFamilySpec :: ValueSpecs Family
+protocolFamilySpec =
+      AF_INET   <$ atomSpec "inet"
+  <!> AF_INET6  <$ atomSpec "inet6"
 
 
 nicksSpec :: ValueSpecs (NonEmpty Text)
diff --git a/src/Client/Image/PackedImage.hs b/src/Client/Image/PackedImage.hs
--- a/src/Client/Image/PackedImage.hs
+++ b/src/Client/Image/PackedImage.hs
@@ -45,8 +45,8 @@
   = HorizText'
       !Attr -- don't unpack, these get reused from the palette
       {-# UNPACK #-} !S.Text
-      {-# UNPACK #-} !Int
-      {-# UNPACK #-} !Int
+      {-# UNPACK #-} !Int -- terminal width
+      {-# UNPACK #-} !Int -- codepoint count
       !Image'
   | EmptyImage'
   deriving (Show)
@@ -91,6 +91,7 @@
            Nothing -> 0
            Just ix -> ix
 
+-- | Width in terms of terminal columns
 imageWidth :: Image' -> Int
 imageWidth = go 0
   where
diff --git a/src/Client/Image/StatusLine.hs b/src/Client/Image/StatusLine.hs
--- a/src/Client/Image/StatusLine.hs
+++ b/src/Client/Image/StatusLine.hs
@@ -338,6 +338,7 @@
     FocusKeyMap   -> Just $ string (view palLabel pal) "keymap"
     FocusHelp mb  -> Just $ string (view palLabel pal) "help" <>
                             opt mb
+    FocusIgnoreList -> Just $ string (view palLabel pal) "ignores"
     FocusRtsStats -> Just $ string (view palLabel pal) "rtsstats"
     FocusMasks m  -> Just $ mconcat
       [ string (view palLabel pal) "masks"
diff --git a/src/Client/Image/Textbox.hs b/src/Client/Image/Textbox.hs
--- a/src/Client/Image/Textbox.hs
+++ b/src/Client/Image/Textbox.hs
@@ -144,7 +144,7 @@
   String               {- ^ input text   -} ->
   Image'               {- ^ output image -}
 renderLine st pal myNick nicks macros focused ('/':xs) =
-  char defAttr '/' <> string attr cmd <> continue rest
+  char defAttr '/' <> string attr cleanCmd <> continue rest
   where
     specAttr spec =
       case parse st spec rest of
@@ -152,6 +152,8 @@
         Just{}  -> view palCommandReady pal
 
     (cmd, rest) = break isSpace xs
+    cleanCmd = map cleanChar cmd
+
     allCommands = (Left <$> macros) <> (Right <$> commands)
     (attr, continue)
       = case recognize (Text.pack cmd) allCommands of
diff --git a/src/Client/Mask.hs b/src/Client/Mask.hs
new file mode 100644
--- /dev/null
+++ b/src/Client/Mask.hs
@@ -0,0 +1,102 @@
+{-# Language OverloadedStrings #-}
+module Client.Mask
+  ( Mask
+  , matchMask
+  , buildMask
+  ) where
+
+import Irc.UserInfo
+import Irc.Identifier
+import Data.Text (Text)
+import qualified Data.Text as Text
+import Text.Regex.TDFA
+import Text.Regex.TDFA.String (compile)
+import Data.List
+
+newtype Mask = Mask Regex
+
+-- | Compile a list of masks down to a single, reuseable 'Mask' value
+-- suitable for being used with 'matchMask'.
+--
+-- Masks can match zero-to-many arbitrary characters with @*@.
+--
+-- Masks can match one arbitrary character with @?@.
+--
+-- Literal @*@ @?@ and @|@ can be matched with a preceding @\@.
+--
+-- Missing host or username components of a mask will automatically
+-- be treated as wildcards.
+buildMask ::
+  [Identifier] {- ^ masks -} ->
+  Mask
+buildMask patterns =
+  case componentsToMask (map (translate . parseMaskComponents . idTextNorm) patterns) of
+    Left e -> error e
+    Right m -> m
+
+-- | Determine if a given 'Mask' matches a given 'UserInfo'
+matchMask :: Mask -> UserInfo -> Bool
+matchMask (Mask re) userInfo =
+  matchTest re (Text.unpack (normalized (renderUserInfo userInfo)))
+
+normalized :: Text -> Text
+normalized = idTextNorm . mkId
+
+-- | Parse a mask into the nick, user, and hostname components
+-- while replacing omitted components with @"*"@.
+parseMaskComponents :: Text -> String
+parseMaskComponents str = Text.unpack nick ++ "!" ++ user ++ "@" ++ host
+  where
+    (nickuser,rawhost) = Text.break (=='@') str
+    (nick    ,rawuser) = Text.break (=='!') nickuser
+
+    user = defaultWild rawuser
+    host = defaultWild rawhost
+
+    defaultWild x =
+      case Text.uncons x of
+        Nothing     -> "*"
+        Just (_, y) -> Text.unpack y
+
+componentsToMask :: [String] -> Either String Mask
+componentsToMask xs =
+  Mask <$> compile defaultCompOpt { multiline     = False }
+                   defaultExecOpt { captureGroups = False }
+                   ("^(" ++ intercalate "|" xs ++ ")$")
+
+-- | Translate from the languge of masks to the language of
+-- regular expressions.
+--
+-- Masks support the @*@ (many) and @?@ (one) wildcards. Wildcards
+-- and @\@ can be escaped by preceding them with a @\@. All other
+-- uses of @\@ are treated as matching the literal backslash.
+translate :: String -> String
+translate [] = []
+translate ('\\' : '*'  : xs) = '\\' : '*'  : translate xs
+translate ('\\' : '?'  : xs) = '\\' : '?'  : translate xs
+translate ('\\' : '\\' : xs) = '\\' : '\\' : translate xs
+translate ('*'         : xs) = '.'  : '*'  : translate xs
+translate ('?'         : xs) = '.'  : '?'  : translate xs
+translate (x           : xs)
+  | isMetaChar x = '\\' : x : translate xs
+  | otherwise    =        x : translate xs
+
+-- | returns True iff the charactr is a regular expression meta character:
+-- @^$\\.|*?+()[]{}@
+isMetaChar :: Char -> Bool
+isMetaChar c = case c of
+  '^'  -> True
+  '\\' -> True
+  '.'  -> True
+  '|'  -> True
+  '*'  -> True
+  '?'  -> True
+  '+'  -> True
+  '('  -> True
+  ')'  -> True
+  '['  -> True
+  ']'  -> True
+  '{'  -> True
+  '}'  -> True
+  '$'  -> True
+  _    -> False
diff --git a/src/Client/Message.hs b/src/Client/Message.hs
--- a/src/Client/Message.hs
+++ b/src/Client/Message.hs
@@ -61,7 +61,7 @@
   | PartSummary {-# UNPACK #-} !Identifier
   | NickSummary {-# UNPACK #-} !Identifier {-# UNPACK #-} !Identifier
   | ReplySummary {-# UNPACK #-} !ReplyCode
-  | ChatSummary {-# UNPACK #-} !Identifier
+  | ChatSummary {-# UNPACK #-} !UserInfo
   | CtcpSummary {-# UNPACK #-} !Identifier
   | NoSummary
   deriving (Eq, Show)
@@ -87,10 +87,10 @@
     Part who _ _    -> PartSummary (userNick who)
     Quit who _      -> QuitSummary (userNick who)
     Nick who who'   -> NickSummary (userNick who) who'
-    Privmsg who _ _ -> ChatSummary (userNick who)
-    Notice who _ _  -> ChatSummary (userNick who)
-    Ctcp who _ "ACTION" _ -> ChatSummary (userNick who)
+    Privmsg who _ _ -> ChatSummary who
+    Notice who _ _  -> ChatSummary who
+    Ctcp who _ "ACTION" _ -> ChatSummary who
     Ctcp who _ _ _ -> CtcpSummary (userNick who)
-    CtcpNotice who _ _ _ -> ChatSummary (userNick who)
+    CtcpNotice who _ _ _ -> ChatSummary who
     Reply code _    -> ReplySummary code
     _               -> NoSummary
diff --git a/src/Client/Network/Connect.hs b/src/Client/Network/Connect.hs
--- a/src/Client/Network/Connect.hs
+++ b/src/Client/Network/Connect.hs
@@ -33,6 +33,11 @@
                     (view ssTlsServerCert args)
                     (view ssTlsCiphers    args)
 
+      family =
+        case view ssProtocolFamily args of
+          Nothing -> defaultFamily
+          Just pf -> pf
+
       useSecure =
         case view ssTls args of
           UseInsecure    -> Nothing
@@ -45,7 +50,8 @@
                           (view ssSocksPort args)
 
   in ConnectionParams
-    { cpHost  = view ssHostName args
+    { cpFamily = family
+    , cpHost  = view ssHostName args
     , cpPort  = ircPort args
     , cpTls   = useSecure
     , cpSocks = proxySettings
diff --git a/src/Client/State.hs b/src/Client/State.hs
--- a/src/Client/State.hs
+++ b/src/Client/State.hs
@@ -33,6 +33,7 @@
   , clientSubfocus
   , clientNetworkMap
   , clientIgnores
+  , clientIgnoreMask
   , clientConnection
   , clientBell
   , clientExtensions
@@ -111,6 +112,7 @@
 import           Client.Image.Message
 import           Client.Image.Palette
 import           Client.Log
+import           Client.Mask
 import           Client.Message
 import           Client.Network.Async
 import           Client.State.Channel
@@ -181,7 +183,8 @@
 
   , _clientBell              :: !Bool                     -- ^ sound a bell next draw
 
-  , _clientIgnores           :: !(HashSet Identifier)     -- ^ ignored nicknames
+  , _clientIgnores           :: !(HashSet Identifier)     -- ^ ignored masks
+  , _clientIgnoreMask        :: Mask                      -- ^ precomputed ignore regular expression (lazy)
 
   , _clientExtensions        :: !ExtensionState           -- ^ state of loaded extensions
   , _clientLogQueue          :: ![LogLine]                -- ^ log lines ready to write
@@ -240,11 +243,13 @@
 
   withExtensionState $ \exts ->
 
-  do events         <- atomically newTQueue
+  do events <- atomically newTQueue
+     let ignoreIds = map mkId (view configIgnores cfg)
      k ClientState
         { _clientWindows           = _Empty # ()
         , _clientNetworkMap        = _Empty # ()
-        , _clientIgnores           = view configIgnores cfg
+        , _clientIgnores           = HashSet.fromList ignoreIds
+        , _clientIgnoreMask        = buildMask ignoreIds
         , _clientConnections       = _Empty # ()
         , _clientTextBox           = Edit.defaultEditBox
         , _clientTextBoxOffset     = 0
@@ -404,17 +409,17 @@
     _                    -> Nothing
   where
     checkUser !who
-      | identIgnored (userNick who) st = Just (userNick who)
-      | otherwise                      = Nothing
+      | identIgnored who st = Just (userNick who)
+      | otherwise           = Nothing
 
 
 
 -- | Predicate for nicknames to determine if messages should be ignored.
 identIgnored ::
-  Identifier  {- ^ nickname     -} ->
+  UserInfo    {- ^ target user  -} ->
   ClientState {- ^ client state -} ->
   Bool        {- ^ is ignored   -}
-identIgnored who st = HashSet.member who (view clientIgnores st)
+identIgnored who st = matchMask (view clientIgnoreMask st) who
 
 
 -- | Record a message in the windows corresponding to the given target
diff --git a/src/Client/State/Focus.hs b/src/Client/State/Focus.hs
--- a/src/Client/State/Focus.hs
+++ b/src/Client/State/Focus.hs
@@ -54,6 +54,7 @@
   | FocusKeyMap      -- ^ Show key bindings
   | FocusHelp (Maybe Text) -- ^ Show help window with optional command
   | FocusRtsStats    -- ^ Show GHC RTS statistics
+  | FocusIgnoreList    -- ^ Show ignored masks
   deriving (Eq,Show)
 
 -- | Unfocused first, followed by focuses sorted by network.
diff --git a/src/Client/View.hs b/src/Client/View.hs
--- a/src/Client/View.hs
+++ b/src/Client/View.hs
@@ -19,6 +19,7 @@
 import           Client.View.ChannelInfo
 import           Client.View.Digraphs
 import           Client.View.Help
+import           Client.View.IgnoreList
 import           Client.View.KeyMap
 import           Client.View.MaskList
 import           Client.View.Mentions
@@ -49,6 +50,7 @@
     (_, FocusKeyMap) -> keyMapLines st
     (_, FocusHelp mb) -> helpImageLines st mb pal
     (_, FocusRtsStats) -> rtsStatsLines (view clientRtsStats st) pal
+    (_, FocusIgnoreList) -> ignoreListLines (view clientIgnores st) pal
     _ -> chatMessageImages focus w st
   where
     pal = clientPalette st
diff --git a/src/Client/View/IgnoreList.hs b/src/Client/View/IgnoreList.hs
new file mode 100644
--- /dev/null
+++ b/src/Client/View/IgnoreList.hs
@@ -0,0 +1,44 @@
+{-# Language OverloadedStrings #-}
+{-|
+Module      : Client.View.IgnoreList
+Description : Line renderers for ignore mask list view
+Copyright   : (c) Eric Mertens, 2016
+License     : ISC
+Maintainer  : emertens@gmail.com
+
+This module renders the lines used to list the ignore masks.
+-}
+module Client.View.IgnoreList
+  ( ignoreListLines
+  ) where
+
+import           Client.Image.PackedImage
+import           Client.Image.Palette
+import           Client.Image.Message
+import           Graphics.Vty.Attributes
+import           Irc.Identifier
+import           Data.HashSet (HashSet)
+import           Data.Foldable
+import           Data.Semigroup
+import           Control.Lens
+
+-- | Render the lines used in a channel mask list.
+ignoreListLines ::
+  HashSet Identifier {- ^ ignore masks -} ->
+  Palette            {- ^ palette      -} ->
+  [Image']
+ignoreListLines ignores pal =
+  summaryLine ignores pal :
+  [ text' defAttr (cleanText (idText mask))
+  | mask <- toList ignores ]
+
+
+-- | Render a summary describing the number of ignore masks.
+summaryLine ::
+  HashSet Identifier {- ^ ignore masks -} ->
+  Palette            {- ^ palette      -} ->
+  Image'
+summaryLine ignores pal
+  | null ignores = text' (view palError pal) "Ignore list empty"
+  | otherwise    = text' (view palLabel pal) "Ignore entries: "
+                <> string defAttr (show (length ignores))
diff --git a/src/Client/View/Messages.hs b/src/Client/View/Messages.hs
--- a/src/Client/View/Messages.hs
+++ b/src/Client/View/Messages.hs
@@ -31,6 +31,7 @@
 import           Data.Semigroup
 import           Irc.Identifier
 import           Irc.Message
+import           Irc.UserInfo
 
 
 chatMessageImages :: Focus -> Int -> ClientState -> [Image']
@@ -169,5 +170,5 @@
         {- ^ Image, incoming identifier, outgoing identifier if changed -}
 metadataWindowLine st wl =
   case view wlSummary wl of
-    ChatSummary who -> (ignoreImage, who, Nothing) <$ guard (identIgnored who st)
+    ChatSummary who -> (ignoreImage, userNick who, Nothing) <$ guard (identIgnored who st)
     summary         -> metadataImg summary
diff --git a/src/Client/View/UrlSelection.hs b/src/Client/View/UrlSelection.hs
--- a/src/Client/View/UrlSelection.hs
+++ b/src/Client/View/UrlSelection.hs
@@ -31,6 +31,7 @@
 import           Data.Text (Text)
 import           Graphics.Vty.Attributes
 import           Irc.Identifier
+import           Irc.UserInfo (userNick)
 import           Text.Read (readMaybe)
 
 
@@ -76,7 +77,7 @@
     QuitSummary who   -> Just who
     PartSummary who   -> Just who
     NickSummary who _ -> Just who
-    ChatSummary who   -> Just who
+    ChatSummary who   -> Just (userNick who)
     CtcpSummary who   -> Just who
     ReplySummary {}   -> Nothing
     NoSummary         -> Nothing
