packages feed

mediawiki (empty) → 0.2

raw patch · 97 files changed

+6723/−0 lines, 97 filesdep +HTTPdep +basedep +mimesetup-changed

Dependencies added: HTTP, base, mime, network, pretty, utf8-string, xml

Files

+ LICENSE view
@@ -0,0 +1,27 @@+Copyright (c) Sigbjorn Finne 2008++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:+1. Redistributions of source code must retain the above copyright+   notice, this list of conditions and the following disclaimer.+2. Redistributions in binary form must reproduce the above copyright+   notice, this list of conditions and the following disclaimer in the+   documentation and/or other materials provided with the distribution.+3. Neither the name of the author nor the names of his contributors+   may be used to endorse or promote products derived from this software+   without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+SUCH DAMAGE.
+ Main.hs view
@@ -0,0 +1,83 @@+module Main(main) where
+
+import MediaWiki.API
+import MediaWiki.API.Types
+
+import MediaWiki.API.Query.Info
+import MediaWiki.API.Query.Info.Import as I
+import MediaWiki.API.Query.LangLinks
+import MediaWiki.API.Query.LangLinks.Import as LL
+import MediaWiki.API.Query.SiteInfo
+
+import System.Environment
+import Data.List ( isPrefixOf )
+
+mw_api_url :: String
+mw_api_url = "http://en.wikipedia.org/w/"
+
+main :: IO ()
+main = do
+  ls <- getArgs
+  let 
+   (url,pg) =
+    case ls of
+      ("WP":y:_) -> (mw_api_url,y)
+      (x:y:_) -> (x,y)
+      _ -> (mw_api_url, "Main_Page")
+  i <- queryInfo url pg
+  case I.stringXml i of
+    Left x -> putStrLn ("Error getting info for page " ++ pg ++ " error: " ++ show x)
+    Right x -> putStrLn ("Page last touched: " ++ headS (map infTouched (infPages x)))
+  lns <- getAll url pg [] Nothing
+  putStrLn ("The page " ++ pg ++ " is available in other languages:")
+  iwMap <- getIWUrlMap url
+  let 
+   getIWUrl (x,y) = 
+     case filter ((x==).iwPrefix) iwMap of
+        (a:_) -> (x,subst y (iwUrl a))
+	_ -> (x,"<unknown>")
+  let lns1 = map getIWUrl lns
+  putStrLn (' ':' ':unlines (map (\ (a,b) -> a ++ "=> " ++ b) lns1))
+ where
+   subst ss x = 
+    case spanUntil ("$1" `isPrefixOf`) x of
+     (as,_:_:bs) -> as ++ ss ++ subst ss bs
+     (as,_) -> as
+
+spanUntil :: ([a] -> Bool) -> [a] -> ([a],[a])
+spanUntil _ [] = ([],[])
+spanUntil p ls@(x:xs)
+ | p ls = ([],ls)
+ | otherwise = 
+     case spanUntil p xs of
+       (as,bs) -> (x:as,bs)
+
+getAll :: String -> String -> [[(String,String)]] -> Maybe String -> IO [(String,String)]
+getAll url pg acc mbCont = do
+--  i <- catch (queryLangPage url pg mbCont) (\ _ -> return "")
+  i <- queryLangPage url pg mbCont
+  case LL.stringXml i of
+   Left{} -> return (concat $ reverse acc)
+   Right ll -> do
+    let lls = map (\ lli -> (langName lli, lTitle lli)) (concat (map snd (llPages ll)))
+    case llContinue ll of
+      Nothing -> return $ concat $ reverse (lls:acc)
+      Just mb -> do
+        getAll url pg (lls:acc) (Just mb)
+ where
+  lTitle x =
+    case langTitle x of
+      Nothing -> pg
+      Just "" -> pg
+      Just xs -> xs
+
+getIWUrlMap :: String -> IO [InterwikiEntry]
+getIWUrlMap api_url = do
+  mb <- querySiteIWInfo api_url
+  case mb of
+    Nothing -> return []
+    Just si -> return (siInterwiki si)
+
+headS :: [String] -> String
+headS    [] = ""
+headS (x:_) = x
+ MediaWiki/API.hs view
@@ -0,0 +1,194 @@+{-# OPTIONS_GHC -XExistentialQuantification -XDeriveDataTypeable #-}
+--------------------------------------------------------------------
+-- |
+-- Module      : MediaWiki.API
+-- Description : A Haskell MediaWiki API binding
+-- Copyright   : (c) Sigbjorn Finne, 2008
+-- License     : BSD3
+--
+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>
+-- Stability : provisional
+-- Portability: portable
+--
+-- A Haskell MediaWiki API binding.
+-- 
+--------------------------------------------------------------------
+module MediaWiki.API 
+       ( module MediaWiki.API
+       , URLString
+       ) where
+
+import MediaWiki.API.Base
+import MediaWiki.API.Types
+import MediaWiki.API.Output
+
+import MediaWiki.Util.Fetch as Fetch
+import Codec.MIME.Type
+
+import MediaWiki.API.Query.SiteInfo as SI
+import MediaWiki.API.Query.SiteInfo.Import as SI
+import MediaWiki.API.Action.Login.Import as Login
+
+import Data.Maybe
+
+import Control.Exception as CE
+import Data.Typeable
+
+import MediaWiki.API.Utils
+import Text.XML.Light.Types
+import Control.Monad
+
+-- | @webGet url req@ issues a GET to a MediaWiki server, appending
+-- @api.php?@ followed by the request @req@ to the URL base @url@.
+webGet :: URLString -> Request -> IO String
+webGet url req = do
+  let url_q = url ++ "api.php?" ++ showRequest req
+--  print url_q
+  readContentsURL url_q
+
+-- | @webGet mbUser url req@ issues a POST to a MediaWiki server, appending
+-- @api.php?@ followed by the request @req@ to the URL base @url@.
+webPost :: Maybe Fetch.User -> URLString -> String -> Request -> IO ([(String,String)], String)
+webPost mbUser url act req = do
+  let url_q  = url ++ "api.php?action="++act
+  let pload  = showRequest req
+  postContentsURL mbUser url_q
+                  [ ("Content-Length", show $ length pload)
+		  , ("Content-Type",   showMIMEType form_mime_ty)
+		  ]
+		  pload
+ where
+  form_mime_ty = Application "x-www-form-urlencoded"
+
+webPostXml :: (String -> Either (String,[String]) a)
+           -> Maybe Fetch.User
+           -> URLString
+	   -> String
+	   -> Request
+	   -> IO (Maybe a)
+webPostXml p mbUser url act req = do
+  (hs,mb) <- webPost mbUser url act req
+  case mb of
+    "" -> return Nothing
+    ls -> do
+     case p ls of
+      Left (x,errs) -> 
+         case parseError ls of
+	   Right e -> throwMWError e
+	   _ -> putStrLn (x ++ ':':' ':unlines errs) >> return Nothing
+      Right x  -> return (Just x)
+
+webGetXml :: (String -> Either (String,[String]) a)
+          -> URLString
+	  -> Request
+	  -> IO (Maybe a)
+webGetXml p url req = do
+  ls <- webGet url req
+  case p ls of
+    Left (x,errs) -> 
+         case parseError ls of
+	   Right e -> throwMWError e
+	   _ -> putStrLn (x ++ ':':' ':unlines errs) >> return Nothing
+    Right x  -> return (Just x)
+
+queryPage :: PageName -> QueryRequest
+queryPage pg = emptyQuery{quTitles=[pg]}
+
+mkQueryAction :: APIRequest a => QueryRequest -> a -> Action
+mkQueryAction q qr = 
+  case queryKind qr of
+    QProp s -> Query q{quProps=(PropKind s):quProps q} (toReq qr)
+    QList s -> Query q{quLists=(ListKind s):quLists q} (toReq qr)
+    QMeta s -> Query q{quMetas=(MetaKind s):quMetas q} (toReq qr)
+    QGen  s -> Query q{quGenerator=(Just (GeneratorKind s))} (toReq qr)
+
+-- | @loginWiki u usr pass
+loginWiki :: URLString -> String -> String -> IO (Maybe LoginResponse)
+loginWiki url usr pwd = webPostXml Login.stringXml Nothing url "login" req
+  where
+   req = emptyXmlRequest (Login (emptyLogin usr pwd))
+
+queryInfo :: URLString -> PageName -> IO String
+queryInfo url pgName = webGet url req
+  where
+   req = emptyXmlRequest (mkQueryAction (queryPage pgName) infoRequest)
+
+querySiteIWInfo :: URLString -> IO (Maybe SiteInfoResponse)
+querySiteIWInfo url = webGetXml SI.stringXml url req 
+ where
+  req = emptyXmlRequest 
+                 (mkQueryAction (queryPage "XP") 
+		                siteInfoRequest{siProp=["interwikimap"]})
+
+queryLangPage :: URLString -> PageName -> Maybe String -> IO String
+queryLangPage url pgName mb = webGet url req
+  where
+   req = emptyXmlRequest
+                 (mkQueryAction (queryPage pgName)
+		                langLinksRequest{llContinueFrom=mb})
+
+
+parseError :: String -> Either (String,[{-Error msg-}String]) MediaWikiError
+parseError s = parseDoc xmlError s
+
+xmlError :: Element -> Maybe MediaWikiError
+xmlError e = do
+  guard (elName e == nsName "api")
+  let es1 = children e
+  p  <- pNode "error" es1
+  return mwError{ mwErrorCode = fromMaybe "" $ pAttr "code" p
+                , mwErrorInfo = fromMaybe "" $ pAttr "info" p
+		}
+
+-- MW exceptions/errors:
+
+data MediaWikiError
+ = MediaWikiError
+     { mwErrorCode :: String
+     , mwErrorInfo :: String
+     } deriving ( Typeable )
+
+mwError :: MediaWikiError
+mwError = MediaWikiError{mwErrorCode="",mwErrorInfo=""}
+
+data SomeMWException = forall e . Exception e => SomeMWException e 
+    deriving Typeable 
+
+instance Show SomeMWException where 
+    show (SomeMWException e) = show e 
+
+instance Exception SomeMWException 
+
+mwToException :: Exception e => e -> SomeException
+mwToException = toException . SomeMWException 
+
+mwFromException :: Exception e => SomeException -> Maybe e 
+mwFromException x = do 
+    SomeMWException a <- fromException x 
+    cast a 
+
+instance Exception MediaWikiError where
+  toException = mwToException
+  fromException = mwFromException
+
+handleMW :: (MediaWikiError -> IO a) -> IO a -> IO a
+handleMW h e = catchMW e h
+
+tryMW :: IO a -> IO (Either MediaWikiError a)
+tryMW f = handleMW (\ x -> return (Left x)) (f >>= return.Right)
+
+throwMWError :: MediaWikiError -> IO a
+throwMWError e = throwIO e
+
+catchMW :: IO a -> (MediaWikiError -> IO a) -> IO a
+catchMW f hdlr = 
+  CE.catch f
+           (\ e1 -> hdlr e1)
+
+instance Show MediaWikiError where
+  show x = unlines (
+   [ "MediaWiki error:"
+   , ""
+   , " Code: " ++ mwErrorCode x
+   , " Info: " ++ mwErrorInfo x
+   ])
+ MediaWiki/API/Action/Block.hs view
@@ -0,0 +1,63 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Action.Block+-- Description : Representing Block requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing Block requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.Block where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data BlockRequest+ = BlockRequest+    { blkUser   :: UserName+    , blkToken  :: Token+    , blkGetToken :: Bool+    , blkExpiry :: Maybe Timestamp+    , blkReason :: Maybe String+    , blkAnonOnly :: Bool+    , blkNoCreate :: Bool+    , blkAutoBlock :: Bool+    , blkNoEmail :: Bool+    , blkHide    :: Bool+    }++instance APIRequest BlockRequest where+  isPostable _ = True+  showReq r =+    [ opt "user" (blkUser r)+    , opt "token" (blkToken r)+    , optB "gettoken" (blkGetToken r)+    , mbOpt "expiry" id (blkExpiry r)+    , mbOpt "reason" id (blkReason r)+    , optB "anononly" (blkAnonOnly r)+    , optB "nocreate" (blkNoCreate r)+    , optB "autoblock" (blkAutoBlock r)+    , optB "noemail"   (blkNoEmail r)+    , optB "hidename"  (blkHide r)+    ]+++emptyBlockRequest :: BlockRequest+emptyBlockRequest = BlockRequest+    { blkUser   = ""+    , blkToken  = ""+    , blkGetToken = False+    , blkExpiry = Nothing+    , blkReason = Nothing+    , blkAnonOnly = False+    , blkNoCreate = False+    , blkAutoBlock = False+    , blkNoEmail = False+    , blkHide    = False+    }+
+ MediaWiki/API/Action/Delete.hs view
@@ -0,0 +1,50 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Action.Delete+-- Description : Representing Delete requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing Delete requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.Delete where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data DeleteRequest+ = DeleteRequest+    { delTitle  :: PageName+    , delToken  :: Token+    , delReason :: Maybe String+    , delWatch  :: Maybe Bool+    , delUnwatch :: Maybe Bool +    , delOldImage :: Maybe String+    }++instance APIRequest DeleteRequest where+  isPostable _ = True+  showReq r = +    [ opt "title" (delTitle r)+    , opt "token" (delToken r)+    , mbOpt "reason" id (delReason r)+    , optB "watch" (fromMaybe False $ delWatch r)+    , optB "unwatch" (fromMaybe False $ delUnwatch r)+    , mbOpt "oldimage" id (delOldImage r)+    ]++emptyDeleteRequest :: DeleteRequest+emptyDeleteRequest = DeleteRequest+    { delTitle = ""+    , delToken = ""+    , delReason = Nothing+    , delWatch = Nothing+    , delUnwatch = Nothing+    , delOldImage = Nothing+    } +
+ MediaWiki/API/Action/Edit.hs view
@@ -0,0 +1,90 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Action.Edit+-- Description : Representing Edit requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing Edit requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.Edit where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data EditRequest+ = EditRequest+    { edTitle   :: Maybe PageName+    , edSection :: Maybe String+    , edText    :: Maybe String -- ^ Page content+    , edToken   :: Maybe Token  -- ^ Edit token. You can get one of these through prop=info+    , edSummary :: Maybe String+    , edIsMinor   :: Bool+    , edIsNonMinor :: Bool+    , edAsBot   :: Bool+    , edBaseTimestamp :: Maybe Timestamp+    , edRecreate :: Bool+    , edCreateOnly :: Bool+    , edNoCreate :: Bool+    , edCaptchaWord :: Maybe String+    , edCaptchaId   :: Maybe String+    , edWatch :: Bool+    , edUnwatch :: Bool+    , edMD5 :: Maybe String+    , edPrependText :: Maybe String+    , edAppendText :: Maybe String+    }++instance APIRequest EditRequest where+  isPostable _ = True+  showReq r = +    [ mbOpt "title" id (edTitle r)+    , mbOpt "section" id (edSection r)+    , mbOpt "text" id (edText r)+    , mbOpt "token" id (edToken r)+    , mbOpt "summary" id (edSummary r)+    , optB "minor" (edIsMinor r)+    , optB "notminor" (edIsNonMinor r)+    , optB "bot" (edAsBot r)+    , mbOpt "basetimestamp" id (edBaseTimestamp r)+    , optB  "recreate" (edRecreate r)+    , optB  "createonly" (edCreateOnly r)+    , optB  "nocreate" (edNoCreate r)+    , mbOpt "captchaword" id (edCaptchaWord r)+    , mbOpt "captchaid" id (edCaptchaId r)+    , optB  "watch" (edWatch r)+    , optB  "unwatch" (edUnwatch r)+    , mbOpt "md5" id (edMD5 r)+    , mbOpt "prependtext" id (edPrependText r)+    , mbOpt "appendtext" id (edAppendText r)+    ]+++emptyEditRequest :: EditRequest+emptyEditRequest = EditRequest+    { edTitle   = Nothing+    , edSection = Nothing+    , edText    = Nothing+    , edToken   = Nothing+    , edSummary = Nothing+    , edIsMinor   = False+    , edIsNonMinor = True+    , edAsBot   = False+    , edBaseTimestamp = Nothing+    , edRecreate = False+    , edCreateOnly = False+    , edNoCreate = False+    , edCaptchaWord = Nothing+    , edCaptchaId   = Nothing+    , edWatch = False+    , edUnwatch = False+    , edMD5 = Nothing+    , edPrependText = Nothing+    , edAppendText = Nothing+    }+
+ MediaWiki/API/Action/EmailUser.hs view
@@ -0,0 +1,46 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Action.EmailUser+-- Description : Representing EmailUser requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing EmailUser requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.EmailUser where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data EmailUserRequest+ = EmailUserRequest+    { emTarget  :: Maybe String+    , emSubject :: Maybe String+    , emText    :: Maybe String+    , emToken   :: Maybe Token+    , emCcMe    :: Bool+    }++instance APIRequest EmailUserRequest where+  isPostable _ = True+  showReq r = +   [ mbOpt "target" id (emTarget r)+   , mbOpt "subject" id (emSubject r)+   , mbOpt "text" id (emText r)+   , mbOpt "token" id (emToken r)+   , optB  "ccme" (emCcMe r)+   ]++emptyEmailUserRequest :: EmailUserRequest+emptyEmailUserRequest = EmailUserRequest+    { emTarget  = Nothing+    , emSubject = Nothing+    , emText    = Nothing+    , emToken   = Nothing+    , emCcMe    = False+    }
+ MediaWiki/API/Action/ExpandTemplates.hs view
@@ -0,0 +1,44 @@+--------------------------------------------------------------------
+-- |
+-- Module      : MediaWiki.API.Action.ExpandTemplates
+-- Description : Representing ExpandTemplates requests.
+-- Copyright   : (c) Sigbjorn Finne, 2008
+-- License     : BSD3
+--
+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>
+-- Stability : provisional
+-- Portability: portable
+--
+-- Representing ExpandTemplates requests.
+-- 
+--------------------------------------------------------------------
+module MediaWiki.API.Action.ExpandTemplates where
+
+import MediaWiki.API.Types
+
+data ExpandTemplatesRequest
+ = ExpandTemplatesRequest
+    { etTitle      :: Maybe PageName
+    , etText       :: String
+    , etGenXml     :: Maybe Bool
+    }
+
+emptyExpandTemplatesRequest :: ExpandTemplatesRequest
+emptyExpandTemplatesRequest = ExpandTemplatesRequest
+    { etTitle      = Nothing
+    , etText       = ""
+    , etGenXml     = Nothing
+    }
+
+data ExpandTemplatesResponse
+ = ExpandTemplatesResponse
+    { etExpandedText :: String
+    , etExpandedXml  :: Maybe String
+    }
+
+emptyExpandTemplatesResponse :: ExpandTemplatesResponse
+emptyExpandTemplatesResponse = ExpandTemplatesResponse
+    { etExpandedText  = ""
+    , etExpandedXml   = Nothing
+    }
+
+ MediaWiki/API/Action/ExpandTemplates/Import.hs view
@@ -0,0 +1,39 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Action.ExpandTemplates.Import+-- Description : Serializing ExpandTemplates requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Serializing ExpandTemplates requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.ExpandTemplates.Import where++--import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Action.ExpandTemplates++import Text.XML.Light.Types+import Text.XML.Light.Proc   ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) ExpandTemplatesResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe ExpandTemplatesResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "expandtemplates" es1+  let xm = fmap strContent $ pNode "parsetree" es1+  return emptyExpandTemplatesResponse+      { etExpandedText = strContent p+      , etExpandedXml  = xm+      }
+ MediaWiki/API/Action/FeedWatchlist.hs view
@@ -0,0 +1,49 @@+--------------------------------------------------------------------
+-- |
+-- Module      : MediaWiki.API.Action.FeedWatchlist
+-- Description : Representing FeedWatchList requests.
+-- Copyright   : (c) Sigbjorn Finne, 2008
+-- License     : BSD3
+--
+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>
+-- Stability : provisional
+-- Portability: portable
+--
+-- Representing FeedWatchList requests.
+-- 
+--------------------------------------------------------------------
+module MediaWiki.API.Action.FeedWatchlist where
+
+import MediaWiki.API.Types
+
+data FeedWatchListRequest
+ = FeedWatchListRequest
+    { feAsAtom    :: Bool  -- False => rss
+    , feHours     :: Maybe Int
+    , feAllRev    :: Bool
+    }
+
+emptyFeedWatchListRequest :: FeedWatchListRequest
+emptyFeedWatchListRequest = FeedWatchListRequest
+    { feAsAtom    = False
+    , feHours     = Nothing
+    , feAllRev    = False
+    }
+
+data FeedWatchListResponse
+ = FeedWatchListResponse
+    { fwFeedFormat  :: String
+    , fwFeedRaw     :: String
+    , fwFeedItems   :: [FeedItem]
+    }
+
+data FeedItem
+ = FeedItem
+    { fiTitle     :: String
+    , fiUrl       :: URLString
+    , fiComment   :: String
+    , fiTimestamp :: String
+    , fiUser      :: String
+    , fiText      :: String
+    }
+
+ MediaWiki/API/Action/Login.hs view
@@ -0,0 +1,67 @@+--------------------------------------------------------------------
+-- |
+-- Module      : MediaWiki.API.Action.Login
+-- Description : Representing Login requests.
+-- Copyright   : (c) Sigbjorn Finne, 2008
+-- License     : BSD3
+--
+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>
+-- Stability : provisional
+-- Portability: portable
+--
+-- Representing Login requests.
+-- 
+--------------------------------------------------------------------
+module MediaWiki.API.Action.Login where
+
+import MediaWiki.API.Types
+import MediaWiki.API.Utils
+
+data LoginRequest
+ = LoginRequest
+     { lgName     :: User
+     , lgPassword :: Password
+     , lgDomain   :: Maybe String
+     }
+
+instance APIRequest LoginRequest where
+  isPostable _ = True
+  showReq r =
+   [ opt "lgname" (lgName r)
+   , opt "lgpassword" (lgPassword r)
+   , mbOpt "lgdomain" id (lgDomain r)
+   ]
+
+emptyLogin :: User -> Password -> LoginRequest
+emptyLogin u p 
+ = LoginRequest
+    { lgName     = u
+    , lgPassword = p
+    , lgDomain   = Nothing
+    }
+
+data LoginResponse
+    -- error responses, all together:
+ = LoginError
+    { lgSuccess  :: Bool
+    , lgeError   :: String -- NeedToWait/NoName/Illegal/WrongPluginPass/NotExists/WrongPass/EmptyPass/future ones.
+        -- (resist the temptation(?) to encode errors via a separate type, keep it loose for now in a String.
+    , lgeDetails :: Maybe String
+    , lgeWait    :: String
+    }
+    -- Successfully logged in, bundle up the result in a separate record so as to ease
+    -- the carrying around of a user session. 
+    --
+    -- Notice the use of a shared boolean field betw. the constructors; eases the processing of
+    -- responses in code where conds/guards are more convenient:
+    --
+    --    x <- submitLoginRequest lgReq
+    --    when (not $ lgSuccess x) (handleError x)
+    --    let sess = lgSession x
+    --    ...
+    --
+ | LoginResponse
+    { lgSuccess :: Bool
+    , lgSession :: UserSession
+    } 
+
+ MediaWiki/API/Action/Login/Import.hs view
@@ -0,0 +1,61 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Action.Login.Import+-- Description : Serializing Login requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Serializing Login requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.Login.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Action.Login++import Text.XML.Light.Types+import Text.XML.Light.Proc   ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) LoginResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe LoginResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p <- pNode "login" es1+  let res = pAttr "result" p+  let uid = pAttr "lguserid" p+  let unm = pAttr "lgusername" p+  let tok = pAttr "lgtoken" p+  let coo = pAttr "cookieprefix" p+  let ses = pAttr "sessionid" p+  case res of+    Just "Success" -> +       return LoginResponse{ lgSuccess=True+                           , lgSession=UserSession+			                 { sessUserId    = fromMaybe "" uid+					 , sessUserName  = fromMaybe "" unm+					 , sessPassword  = Nothing+					 , sessCookiePrefix = coo+					 , sessSessionId = ses+					 , sessToken     =  fromMaybe "" tok+					 }}+    Just x -> do+       let det = pAttr "details" p+       let wai = pAttr "wait" p+       return LoginError+                { lgSuccess = False+		, lgeError  = x+		, lgeDetails = det+		, lgeWait   = fromMaybe "" wai+		}+		
+ MediaWiki/API/Action/Move.hs view
@@ -0,0 +1,57 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Action.Move+-- Description : Representing Move requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing Move requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.Move where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data MoveRequest+ = MoveRequest+    { mvFrom    :: Maybe PageName+    , mvTo      :: Maybe PageName+    , mvToken   :: Token+    , mvReason  :: Maybe String+    , mvMoveTalk :: Bool+    , mvNoRedir  :: Bool+    , mvWatch    :: Bool+    , mvUnwatch  :: Bool+    }++instance APIRequest MoveRequest where+ isPostable _ = True+ showReq r = +    [ mbOpt "from" id (mvFrom r)+    , mbOpt "to"   id (mvTo r)+    , opt   "token" (mvToken r)+    , mbOpt "reason" id (mvReason r)+    , optB "movetalk" (mvMoveTalk r)+    , optB "noredirect"  (mvNoRedir r)+    , optB "watch" (mvWatch r)+    , optB "unwatch" (mvUnwatch r)+    ]+++emptyMoveRequest :: MoveRequest+emptyMoveRequest = MoveRequest+    { mvFrom    = Nothing+    , mvTo      = Nothing+    , mvToken   = ""+    , mvReason  = Nothing+    , mvMoveTalk = False+    , mvNoRedir  = False+    , mvWatch    = False+    , mvUnwatch  = False+    }+
+ MediaWiki/API/Action/OpenSearch.hs view
@@ -0,0 +1,44 @@+--------------------------------------------------------------------
+-- |
+-- Module      : MediaWiki.API.Action.OpenSearch
+-- Description : Representing OpenSearch requests.
+-- Copyright   : (c) Sigbjorn Finne, 2008
+-- License     : BSD3
+--
+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>
+-- Stability : provisional
+-- Portability: portable
+--
+-- Representing OpenSearch requests.
+-- 
+--------------------------------------------------------------------
+module MediaWiki.API.Action.OpenSearch where
+
+import MediaWiki.API.Types
+
+data OpenSearchRequest
+ = OpenSearchRequest
+    { osSearch     :: String
+    , osLimit      :: Maybe Int
+    , osNamespaces :: Maybe [Int]
+    }
+
+emptyOpenSearchRequest :: String -> OpenSearchRequest
+emptyOpenSearchRequest tit 
+ = OpenSearchRequest
+    { osSearch     = tit
+    , osLimit      = Nothing
+    , osNamespaces = Nothing
+    }
+
+data OpenSearchResponse
+ = OpenSearchResponse
+      { osHits :: [OpenSearchHit]
+      }
+
+data OpenSearchHit
+ = OpenSearchHit
+      { oshTitle   :: String
+      , oshMatches :: [String]
+      }
+
+ MediaWiki/API/Action/ParamInfo.hs view
@@ -0,0 +1,59 @@+--------------------------------------------------------------------
+-- |
+-- Module      : MediaWiki.API.Action.ParamInfo
+-- Description : Representing ParamInfo requests.
+-- Copyright   : (c) Sigbjorn Finne, 2008
+-- License     : BSD3
+--
+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>
+-- Stability : provisional
+-- Portability: portable
+--
+-- Representing ParamInfo requests.
+-- 
+--------------------------------------------------------------------
+module MediaWiki.API.Action.ParamInfo where
+
+import MediaWiki.API.Types
+
+data ParamInfoRequest
+ = ParamInfoRequest
+    { paModules      :: [String]
+    , paQueryModules :: [String]
+    }
+
+emptyParamInfoRequest :: ParamInfoRequest
+emptyParamInfoRequest = ParamInfoRequest
+    { paModules      = []
+    , paQueryModules = []
+    }
+
+data ParamInfoResponse
+ = ParamInfoResponse
+    { parModules :: [APIModule]
+    }
+
+data APIModule
+ = APIModule
+    { modName        :: String
+    , modClass       :: String
+    , modDescription :: String
+    , modParams      :: [ModuleParam]
+    }
+
+data ModuleParam
+ = ModuleParam
+    { modParamName        :: String
+    , modParamDefault     :: String
+    , modParamDescription :: String
+    , modParamPrefix      :: String
+    , modParamType        :: ParamType
+    }
+
+data ParamType
+ = TypeBool
+ | TypeString
+ | TypeInteger
+ | TypeTimestamp
+ | TypeName String
+ | TypeEnum [String]
+ MediaWiki/API/Action/Parse.hs view
@@ -0,0 +1,89 @@+--------------------------------------------------------------------
+-- |
+-- Module      : MediaWiki.API.Action.Parse
+-- Description : Representing Parse requests.
+-- Copyright   : (c) Sigbjorn Finne, 2008
+-- License     : BSD3
+--
+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>
+-- Stability : provisional
+-- Portability: portable
+--
+-- Representing Parse requests.
+-- 
+--------------------------------------------------------------------
+module MediaWiki.API.Action.Parse where
+
+import MediaWiki.API.Types
+
+data ParseRequest
+ = ParseRequest
+    { paTitle     :: Maybe PageName
+    , paText      :: String
+    , paPage      :: Maybe PageName
+    , paOldId     :: Maybe RevID
+    , paProp      :: [String]
+    }
+
+emptyParseRequest :: String -> ParseRequest
+emptyParseRequest txt = ParseRequest
+    { paTitle     = Nothing
+    , paText      = txt
+    , paPage      = Nothing
+    , paOldId     = Nothing
+    , paProp      = []
+    }
+
+data ParseResponse
+ = ParseResponse
+    { parText          :: String
+    , parRevId         :: Maybe RevID
+    , parLangLinks     :: Maybe [LanguageLink]
+    , parCategories    :: Maybe [CategoryLink]
+    , parLinks         :: Maybe [Link]
+    , parTemplates     :: Maybe [Link]
+    , parImages        :: Maybe [String]
+    , parExternalLinks :: Maybe [URLString]
+    , parSections      :: Maybe [TOCSection]
+    }
+
+emptyParseResponse :: ParseResponse
+emptyParseResponse  = ParseResponse
+    { parText          = ""
+    , parRevId         = Nothing
+    , parLangLinks     = Nothing
+    , parCategories    = Nothing
+    , parLinks         = Nothing
+    , parTemplates     = Nothing
+    , parImages        = Nothing
+    , parExternalLinks = Nothing
+    , parSections      = Nothing
+    }
+
+data LanguageLink
+ = LanguageLink
+    { laLang  :: String
+    , laLink  :: String
+    }
+
+data CategoryLink
+ = CategoryLink
+    { caSortKey :: String
+    , caLink    :: String
+    }
+
+data Link
+ = Link
+    { liNamespace :: String
+    , liExists    :: Bool
+    , liLink      :: String
+    }
+
+data TOCSection
+ = TOCSection
+    { tocTocLevel :: Int
+    , tocLevel    :: Int
+    , tocLine     :: String
+    , tocNumber   :: String
+    }
+
+ MediaWiki/API/Action/Parse/Import.hs view
@@ -0,0 +1,102 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Action.Parse.Import+-- Description : Serializing Parse requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Serializing Parse requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.Parse.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Action.Parse++import Text.XML.Light.Types+import Text.XML.Light.Proc   ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) ParseResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe ParseResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "parse" es1+  let es = children p+  let txt = fromMaybe "" (pNode "text" es >>= return.strContent)+  let rev = pAttr "revid" p+  let ll  = fmap (mapMaybe xmlLL) (fmap children $ pNode "langlinks" es)+  let ca  = fmap (mapMaybe xmlCat) (fmap children $ pNode "categories" es)+  let li  = fmap (mapMaybe xmlLi) (fmap children $ pNode "links" es)+  let te  = fmap (mapMaybe xmlTe) (fmap children $ pNode "templates" es)+  let im  = fmap (mapMaybe xmlIm) (fmap children $ pNode "images" es)+  let ex  = fmap (mapMaybe xmlEx) (fmap children $ pNode "externallinks" es)+  let se  = fmap (mapMaybe xmlSe) (fmap children $ pNode "sections" es)+  return emptyParseResponse+           { parText = txt+	   , parRevId = rev+	   , parLangLinks = ll+	   , parCategories = ca+	   , parLinks = li+	   , parTemplates = te+	   , parImages = im+	   , parExternalLinks = ex+	   , parSections = se+	   }++xmlLL :: Element -> Maybe LanguageLink+xmlLL e = do+   guard (elName e == nsName "ll")+   let lng    = fromMaybe "en"  $ pAttr "lang" e+   return LanguageLink{laLang=lng,laLink=strContent e}++xmlCat :: Element -> Maybe CategoryLink+xmlCat e = do+   guard (elName e == nsName "cl")+   let sk    = fromMaybe ""  $ pAttr "sortkey" e+   return CategoryLink{caSortKey=sk,caLink=strContent e}++xmlLi :: Element -> Maybe Link+xmlLi e = do+   guard (elName e == nsName "pl")+   let ex   = isJust (pAttr "exists" e)+   let ns   = fromMaybe mainNamespace $ pAttr "ns" e+   return Link{liNamespace=ns,liExists=ex,liLink=strContent e}+++xmlTe :: Element -> Maybe Link+xmlTe e = do+   guard (elName e == nsName "tl")+   let ex   = isJust (pAttr "exists" e)+   let ns   = fromMaybe mainNamespace $ pAttr "ns" e +   return Link{liNamespace=ns,liExists=ex,liLink=strContent e}++xmlIm :: Element -> Maybe URLString+xmlIm e = do+   guard (elName e == nsName "img")+   return (strContent e)++xmlEx :: Element -> Maybe URLString+xmlEx e = do+   guard (elName e == nsName "el")+   return (strContent e)++xmlSe :: Element -> Maybe TOCSection+xmlSe e = do+   guard (elName e == nsName "s")+   let tlev = fromMaybe 0 $ pAttr "toclevel" e >>= readMb+   let lev = fromMaybe 0 $ pAttr "level" e >>= readMb+   let lin = fromMaybe "" $ pAttr "line" e+   let num = fromMaybe "" $ pAttr "number" e+   return TOCSection{tocTocLevel=tlev,tocLevel=lev,tocLine=lin,tocNumber=num}+
+ MediaWiki/API/Action/Protect.hs view
@@ -0,0 +1,50 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Action.Protect+-- Description : Representing Protect requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing Protect requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.Protect where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data ProtectRequest+ = ProtectRequest+    { protTitle  :: PageName+    , protToken  :: Token+    , protProtections :: [(String,String)]+    , protExpiry :: Maybe Timestamp+    , protReason :: Maybe String+    , protCascade :: Maybe Bool+    }++instance APIRequest ProtectRequest where+ isPostable _ = True+ showReq r =+  [ opt "title" (protTitle r)+  , opt "token" (protToken r)+  , opt1 "protections" (map (\ (a,b) -> a ++ '=':b) (protProtections r))+  , mbOpt "expiry" id (protExpiry r)+  , mbOpt "reason" id (protReason r)+  , optB "cascade" (fromMaybe False $ protCascade r)+  ]++emptyProtectRequest :: ProtectRequest+emptyProtectRequest = ProtectRequest+    { protTitle = ""+    , protToken = ""+    , protProtections = []+    , protExpiry = Nothing+    , protReason = Nothing+    , protCascade = Nothing+    } +
+ MediaWiki/API/Action/Rollback.hs view
@@ -0,0 +1,47 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Action.Rollback+-- Description : Representing Rollback requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing Rollback requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.Rollback where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data RollbackRequest+ = RollbackRequest+    { rbTitle :: PageName+    , rbUser  :: UserName+    , rbToken :: Token+    , rbSummary :: Maybe String+    , rbMarkBot :: Maybe Bool+    }++instance APIRequest RollbackRequest where+  isPostable _ = True+  showReq r = +    [ opt "title" (rbTitle r)+    , opt "user"  (rbUser r)+    , opt "token" (rbToken r)+    , mbOpt "summary" id (rbSummary r)+    , mbOpt "markbot" (\ x -> if x then "1" else "0") (rbMarkBot r)+    ] ++emptyRollbackRequest :: RollbackRequest+emptyRollbackRequest = RollbackRequest+    { rbTitle = ""+    , rbUser  = ""+    , rbToken = ""+    , rbSummary = Nothing+    , rbMarkBot = Nothing+    } +
+ MediaWiki/API/Action/Sitematrix.hs view
@@ -0,0 +1,48 @@+--------------------------------------------------------------------
+-- |
+-- Module      : MediaWiki.API.Action.Sitematrix
+-- Description : Representing Sitematrix requests.
+-- Copyright   : (c) Sigbjorn Finne, 2008
+-- License     : BSD3
+--
+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>
+-- Stability : provisional
+-- Portability: portable
+--
+-- Representing Sitematrix requests.
+-- 
+--------------------------------------------------------------------
+module MediaWiki.API.Action.Sitematrix where
+
+import MediaWiki.API.Types
+
+-- 1.12+ and later
+data SitematrixRequest
+ = SitematrixRequest
+
+emptySitematrixRequest :: SitematrixRequest
+emptySitematrixRequest = SitematrixRequest
+
+data SitematrixResponse
+ = SitematrixResponse
+     { smCount     :: Int
+     , smSpecials  :: [SiteSpecialInfo]
+     , smLanguages :: [LanguageInfo]
+     }
+
+data SiteSpecialInfo
+ = SiteSpecialInfo
+     { siCode :: String
+     , siUrl  :: URLString
+     }
+
+data LanguageInfo
+ = LanguageInfo
+     { liCode  :: String
+     , liName  :: String
+     , liSites :: [SiteInfos]
+     }
+
+data SiteInfos
+ = SiteInfos
+     { siInfo :: String }
+ MediaWiki/API/Action/Unblock.hs view
@@ -0,0 +1,47 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Action.Unblock+-- Description : Representing Unblock requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing Unblock requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.Unblock where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data UnblockRequest+ = UnblockRequest+    { ublkId    :: Maybe String+    , ublkUser   :: Maybe UserName+    , ublkToken  :: Maybe Token+    , ublkGetToken :: Bool+    , ublkReason :: Maybe String+    }++instance APIRequest UnblockRequest where+  isPostable _ = True+  showReq r = +   [ mbOpt "id" id (ublkId r)+   , mbOpt "user" id (ublkUser r)+   , mbOpt "token" id (ublkToken r)+   , optB "gettoken" (ublkGetToken r)+   , mbOpt "reason" id (ublkReason r)+   ]++emptyUnblockRequest :: UnblockRequest+emptyUnblockRequest = UnblockRequest+    { ublkId = Nothing+    , ublkUser   = Nothing+    , ublkToken  = Nothing+    , ublkGetToken = False+    , ublkReason = Nothing+    }+
+ MediaWiki/API/Action/Undelete.hs view
@@ -0,0 +1,43 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Action.Undelete+-- Description : Representing Undelete requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing Undelete requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.Undelete where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data UndeleteRequest+ = UndeleteRequest+    { udelTitle  :: PageName+    , udelToken  :: Token+    , udelReason :: Maybe String+    , udelTimestamps :: [Timestamp]+    }++instance APIRequest UndeleteRequest where+  isPostable _ = True+  showReq r = +    [ opt "title" (udelTitle r)+    , opt "token" (udelToken r)+    , mbOpt "reason" id (udelReason r)+    , opt1 "timestamps" (udelTimestamps r)+    ]+emptyUndeleteRequest :: UndeleteRequest+emptyUndeleteRequest = UndeleteRequest+    { udelTitle = ""+    , udelToken = ""+    , udelReason = Nothing+    , udelTimestamps = []+    } +
+ MediaWiki/API/Action/Watch.hs view
@@ -0,0 +1,37 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Action.Watch+-- Description : Representing Watch requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing Watch requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Action.Watch where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data WatchRequest+ = WatchRequest+    { waTitle  :: PageName+    , waIsUnwatch :: Bool+    }++instance APIRequest WatchRequest where+  isPostable _ = True+  showReq r = +   [ opt "title" (waTitle r)+   , optB "unwatch" (waIsUnwatch r)+   ]++emptyWatchRequest :: WatchRequest+emptyWatchRequest = WatchRequest+    { waTitle = ""+    , waIsUnwatch = False+    }
+ MediaWiki/API/Base.hs view
@@ -0,0 +1,329 @@+--------------------------------------------------------------------
+-- |
+-- Module      : MediaWiki.API.Base
+-- Description : Collector module of types used by the MediaWiki API
+-- Copyright   : (c) Sigbjorn Finne, 2008
+-- License     : BSD3
+--
+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>
+-- Stability : provisional
+-- Portability: portable
+--
+-- Collector module of types used by the MediaWiki API
+-- 
+--------------------------------------------------------------------
+module MediaWiki.API.Base 
+	( module MediaWiki.API.Base
+	, module MediaWiki.API.Query.AllCategories
+	, module MediaWiki.API.Query.AllImages
+	, module MediaWiki.API.Query.AllLinks
+	, module MediaWiki.API.Query.AllMessages
+	, module MediaWiki.API.Query.AllPages
+	, module MediaWiki.API.Query.AllUsers
+	, module MediaWiki.API.Query.BackLinks
+	, module MediaWiki.API.Query.Blocks
+	, module MediaWiki.API.Query.Categories
+	, module MediaWiki.API.Query.CategoryInfo
+	, module MediaWiki.API.Query.CategoryMembers
+	, module MediaWiki.API.Query.DeletedRevisions
+	, module MediaWiki.API.Query.EmbeddedIn
+	, module MediaWiki.API.Query.ExternalLinks
+	, module MediaWiki.API.Query.ExternalURLUsage
+	, module MediaWiki.API.Query.ImageInfo
+	, module MediaWiki.API.Query.Images
+	, module MediaWiki.API.Query.ImageUsage
+	, module MediaWiki.API.Query.Info
+	, module MediaWiki.API.Query.LangLinks
+	, module MediaWiki.API.Query.LogEvents
+	, module MediaWiki.API.Query.Random
+	, module MediaWiki.API.Query.RecentChanges
+	, module MediaWiki.API.Query.Revisions
+	, module MediaWiki.API.Query.Search
+	, module MediaWiki.API.Query.SiteInfo
+	, module MediaWiki.API.Query.Templates
+	, module MediaWiki.API.Query.UserContribs
+	, module MediaWiki.API.Query.UserInfo
+	, module MediaWiki.API.Query.Users
+	, module MediaWiki.API.Query.WatchList
+
+	, module MediaWiki.API.Action.Login
+	, module MediaWiki.API.Action.ParamInfo
+	, module MediaWiki.API.Action.Parse
+	, module MediaWiki.API.Action.OpenSearch
+	, module MediaWiki.API.Action.FeedWatchlist
+	, module MediaWiki.API.Action.ExpandTemplates
+        , module MediaWiki.API.Action.Sitematrix
+        , module MediaWiki.API.Action.Unblock
+        , module MediaWiki.API.Action.Watch
+        , module MediaWiki.API.Action.EmailUser
+        , module MediaWiki.API.Action.Edit
+        , module MediaWiki.API.Action.Move
+        , module MediaWiki.API.Action.Block
+        , module MediaWiki.API.Action.Protect
+        , module MediaWiki.API.Action.Undelete
+        , module MediaWiki.API.Action.Delete
+        , module MediaWiki.API.Action.Rollback
+
+	) where
+
+import MediaWiki.API.Types
+import MediaWiki.API.Query.AllCategories
+import MediaWiki.API.Query.AllImages
+import MediaWiki.API.Query.AllLinks
+import MediaWiki.API.Query.AllMessages
+import MediaWiki.API.Query.AllPages
+import MediaWiki.API.Query.AllUsers
+import MediaWiki.API.Query.BackLinks
+import MediaWiki.API.Query.Blocks
+import MediaWiki.API.Query.Categories
+import MediaWiki.API.Query.CategoryInfo
+import MediaWiki.API.Query.CategoryMembers
+import MediaWiki.API.Query.DeletedRevisions
+import MediaWiki.API.Query.EmbeddedIn
+import MediaWiki.API.Query.ExternalLinks
+import MediaWiki.API.Query.ExternalURLUsage
+import MediaWiki.API.Query.ImageInfo
+import MediaWiki.API.Query.Images
+import MediaWiki.API.Query.ImageUsage
+import MediaWiki.API.Query.Info
+import MediaWiki.API.Query.LangLinks
+import MediaWiki.API.Query.Links
+import MediaWiki.API.Query.LogEvents
+import MediaWiki.API.Query.Random
+import MediaWiki.API.Query.RecentChanges
+import MediaWiki.API.Query.Revisions
+import MediaWiki.API.Query.Search
+import MediaWiki.API.Query.SiteInfo
+import MediaWiki.API.Query.Templates
+import MediaWiki.API.Query.UserContribs
+import MediaWiki.API.Query.UserInfo
+import MediaWiki.API.Query.Users
+import MediaWiki.API.Query.WatchList
+
+import MediaWiki.API.Action.Login
+import MediaWiki.API.Action.ParamInfo
+import MediaWiki.API.Action.Parse
+import MediaWiki.API.Action.OpenSearch
+import MediaWiki.API.Action.FeedWatchlist
+import MediaWiki.API.Action.ExpandTemplates
+import MediaWiki.API.Action.Sitematrix
+import MediaWiki.API.Action.Unblock
+import MediaWiki.API.Action.Watch
+import MediaWiki.API.Action.EmailUser
+import MediaWiki.API.Action.Edit
+import MediaWiki.API.Action.Move
+import MediaWiki.API.Action.Block
+import MediaWiki.API.Action.Protect
+import MediaWiki.API.Action.Undelete
+import MediaWiki.API.Action.Delete
+import MediaWiki.API.Action.Rollback
+
+-- | Type collecting together the main parts of a MediaWiki API request.
+data Request
+ = Request
+    { reqAction :: Action
+    , reqFormat :: Format
+    , reqMaxLag :: Maybe Int
+    }
+
+emptyRequest :: Action -> Format -> Request
+emptyRequest a f 
+ = Request
+    { reqAction = a
+    , reqFormat = f
+    , reqMaxLag = Nothing
+    }
+
+emptyXmlRequest :: Action -> Request
+emptyXmlRequest a = emptyRequest a xmlFormat
+
+data Action
+ = Sitematrix
+ | Login           LoginRequest
+ | Logout
+ | Query           QueryRequest [String]
+ | ExpandTemplates ExpandTemplatesRequest
+ | Parse           ParseRequest
+ | OpenSearch      OpenSearchRequest
+ | FeedWatch       FeedWatchListRequest
+ | Help            HelpRequest
+ | ParamInfo       ParamInfoRequest
+ | Unblock         UnblockRequest
+ | Watch           WatchRequest
+ | EmailUser       EmailUserRequest
+ | Edit            EditRequest
+ | Move            MoveRequest
+ | Block           BlockRequest
+ | Protect         ProtectRequest
+ | Undelete        UndeleteRequest
+ | Delete          DeleteRequest
+ | Rollback        RollbackRequest
+ | OtherAction     String [ValueName]
+
+
+infoRequest :: InfoRequest
+infoRequest = emptyInfoRequest
+
+revisionRequest :: RevisionRequest
+revisionRequest  = emptyRevisionRequest
+
+linksRequest :: LinksRequest
+linksRequest = emptyLinksRequest
+
+langLinksRequest :: LangLinksRequest
+langLinksRequest  = emptyLangLinksRequest
+
+imagesRequest :: ImagesRequest
+imagesRequest = emptyImagesRequest
+
+imageInfoRequest :: ImageInfoRequest
+imageInfoRequest = emptyImageInfoRequest
+
+templatesRequest :: TemplatesRequest
+templatesRequest = emptyTemplatesRequest
+
+categoriesRequest :: CategoriesRequest
+categoriesRequest = emptyCategoriesRequest
+
+allCategoriesRequest :: AllCategoriesRequest
+allCategoriesRequest = emptyAllCategoriesRequest
+
+allImagesRequest :: AllImagesRequest
+allImagesRequest = emptyAllImagesRequest
+
+allLinksRequest :: AllLinksRequest
+allLinksRequest  = emptyAllLinksRequest
+
+allMessagesRequest :: AllMessagesRequest
+allMessagesRequest = emptyAllMessagesRequest
+
+allPagesRequest :: AllPagesRequest
+allPagesRequest = emptyAllPagesRequest
+
+allUsersRequest :: AllUsersRequest
+allUsersRequest = emptyAllUsersRequest
+
+backLinksRequest :: BackLinksRequest
+backLinksRequest = emptyBackLinksRequest
+
+embeddedInRequest :: EmbeddedInRequest
+embeddedInRequest = emptyEmbeddedInRequest
+
+imageUsageRequest :: ImageUsageRequest
+imageUsageRequest = emptyImageUsageRequest
+
+categoryInfoRequest :: CategoryInfoRequest
+categoryInfoRequest = emptyCategoryInfoRequest
+
+categoryMembersRequest :: CategoryMembersRequest
+categoryMembersRequest = emptyCategoryMembersRequest
+
+externalLinksRequest :: ExternalLinksRequest
+externalLinksRequest = emptyExternalLinksRequest
+
+externalURLUsageRequest :: ExternalURLUsageRequest
+externalURLUsageRequest = emptyExternalURLUsageRequest
+
+logEventsRequest :: LogEventsRequest
+logEventsRequest = emptyLogEventsRequest
+
+recentChangesRequest :: RecentChangesRequest
+recentChangesRequest = emptyRecentChangesRequest
+
+searchRequest :: String -> SearchRequest
+searchRequest = emptySearchRequest
+
+siteInfoRequest :: SiteInfoRequest
+siteInfoRequest = emptySiteInfoRequest
+
+userContribsRequest :: UserContribsRequest
+userContribsRequest = emptyUserContribsRequest
+
+userInfoRequest :: UserInfoRequest
+userInfoRequest = emptyUserInfoRequest
+
+watchListRequest :: WatchListRequest
+watchListRequest = emptyWatchListRequest
+
+blocksRequest :: BlocksRequest
+blocksRequest = emptyBlocksRequest
+
+deletedRevisionsRequest :: DeletedRevisionsRequest
+deletedRevisionsRequest = emptyDeletedRevisionsRequest
+
+usersRequest :: UsersRequest
+usersRequest = emptyUsersRequest
+
+randomPagesRequest :: RandomPagesRequest
+randomPagesRequest = emptyRandomPagesRequest
+
+data QueryRequestKind
+ = InfoProp          InfoRequest
+ | RevisionsProp     RevisionRequest
+ | LinksPropProp     LinksRequest
+ | LangLinksProp     LangLinksRequest
+ | ImagesProp        ImagesRequest
+ | ImageInfoProp     ImageInfoRequest
+ | TemplatesProp     TemplatesRequest
+ | CategoriesProp    CategoriesRequest
+ | AllCategoriesProp AllCategoriesRequest
+ | AllImagesProp     AllImagesRequest
+ | AllLinksProp      AllLinksRequest
+ | AllMessagesProp   AllMessagesRequest
+ | AllPagesProp      AllPagesRequest
+ | AllUsersProp      AllUsersRequest
+ | BacklinksProp     BackLinksRequest
+ | EmbeddedInProp    EmbeddedInRequest
+ | ImageUsageProp    ImageUsageRequest
+ | CategoryInfoProp  CategoryInfoRequest
+ | CategoryMembersProp  CategoryMembersRequest
+ | ExternalLinksProp    ExternalLinksRequest
+ | ExternalURLUsageProp ExternalURLUsageRequest
+ | LogEventsProp        LogEventsRequest
+ | RecentChangesProp    RecentChangesRequest
+ | SearchProp           SearchRequest
+ | SiteInfoProp         SiteInfoRequest
+ | UserContribsProp     UserContribsRequest
+ | UserInfoProp         UserInfoRequest
+ | WatchListProp        WatchListRequest
+ | BlocksProp           BlocksRequest
+ | DeletedRevsProp      DeletedRevisionsRequest
+ | UsersProp            UsersRequest
+ | RandomProp           RandomPagesRequest
+
+qKind :: QueryRequestKind -> QueryKind
+qKind q = 
+ case q of
+   InfoProp k -> queryKind k
+   RevisionsProp k -> queryKind k
+   LinksPropProp k -> queryKind k
+   LangLinksProp k -> queryKind k
+   ImagesProp    k -> queryKind k
+   ImageInfoProp k -> queryKind k
+   TemplatesProp k -> queryKind k
+   CategoriesProp k -> queryKind k
+   AllCategoriesProp k -> queryKind k
+   AllImagesProp     k -> queryKind k
+   AllLinksProp      k -> queryKind k
+   AllMessagesProp   k -> queryKind k
+   AllPagesProp      k -> queryKind k
+   AllUsersProp      k -> queryKind k
+   BacklinksProp     k -> queryKind k
+   EmbeddedInProp    k -> queryKind k
+   ImageUsageProp    k -> queryKind k
+   CategoryInfoProp  k -> queryKind k
+   CategoryMembersProp k -> queryKind k
+   ExternalLinksProp   k -> queryKind k
+   ExternalURLUsageProp k -> queryKind k
+   LogEventsProp        k -> queryKind k
+   RecentChangesProp    k -> queryKind k
+   SearchProp           k -> queryKind k
+   SiteInfoProp         k -> queryKind k
+   UserContribsProp     k -> queryKind k
+   UserInfoProp         k -> queryKind k
+   WatchListProp        k -> queryKind k
+   BlocksProp           k -> queryKind k
+   DeletedRevsProp      k -> queryKind k
+   UsersProp            k -> queryKind k
+   RandomProp           k -> queryKind k
+ 
+ MediaWiki/API/Output.hs view
@@ -0,0 +1,209 @@+--------------------------------------------------------------------
+-- |
+-- Module      : MediaWiki.API.Output
+-- Description : Serializing MediaWiki API types
+-- Copyright   : (c) Sigbjorn Finne, 2008
+-- License     : BSD3
+--
+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>
+-- Stability : provisional
+-- Portability: portable
+--
+-- Serializing MediaWiki API types
+-- 
+--------------------------------------------------------------------
+module MediaWiki.API.Output where
+
+import MediaWiki.API.Types
+import MediaWiki.API.Base
+
+import Data.List
+import Data.Maybe
+
+
+showRequest :: Request
+            -> String
+showRequest req = 
+  join (showAction (reqAction req) : showMaxLag (reqMaxLag req) (showFormat (reqFormat req)))
+
+showMaxLag :: Maybe Int -> String -> [String]
+showMaxLag Nothing  rs = [rs]
+showMaxLag (Just l) rs = [field "maxlag" (show l), rs]
+
+showFormat :: Format -> String
+showFormat f = field "format" $ isFormatted (formatFormatted f) $
+ case formatKind f of
+   FormatJSON -> "json"
+   FormatPHP  -> "php"
+   FormatWDDX -> "wddx"
+   FormatXML  -> "xml"
+   FormatYAML -> "yaml"
+   FormatTxt  -> "txt"
+   FormatDbg  -> "dbg"
+ where
+  isFormatted False xs = xs
+  isFormatted _     xs = xs++"fm"
+  
+toReq :: APIRequest a => a -> [String]
+toReq x =
+ case catMaybes $ showReq x of
+   [] -> []
+   xs -> map showP xs
+ where
+  showP (a,b) = a ++ '=':b
+
+showQueryRequestKind :: QueryRequestKind -> [String]
+showQueryRequestKind r = 
+ case r of
+   InfoProp p -> toReq p
+   RevisionsProp p -> toReq p
+   LinksPropProp p -> toReq p
+   LangLinksProp p -> toReq p
+   ImagesProp    p -> toReq p
+   ImageInfoProp p -> toReq p
+   TemplatesProp p -> toReq p
+   CategoriesProp p -> toReq p
+   AllCategoriesProp p -> toReq p
+   AllImagesProp     p -> toReq p
+   AllLinksProp      p -> toReq p
+   AllMessagesProp   p -> toReq p
+   AllPagesProp      p -> toReq p
+   AllUsersProp      p -> toReq p
+   BacklinksProp     p -> toReq p
+   EmbeddedInProp    p -> toReq p
+   ImageUsageProp    p -> toReq p
+   CategoryInfoProp  p -> toReq p
+   CategoryMembersProp p -> toReq p
+   ExternalLinksProp    p -> toReq p
+   ExternalURLUsageProp p -> toReq p
+   LogEventsProp        p -> toReq p
+   RecentChangesProp    p -> toReq p
+   SearchProp           p -> toReq p
+   SiteInfoProp         p -> toReq p
+   UserContribsProp     p -> toReq p
+   UserInfoProp         p -> toReq p
+   WatchListProp        p -> toReq p
+   BlocksProp           p -> toReq p
+   DeletedRevsProp      p -> toReq p
+   UsersProp            p -> toReq p
+   RandomProp           p -> toReq p
+ 
+
+showAction :: Action -> String
+showAction act = join $
+  case act of
+    Sitematrix -> [field "action" "sitematrix"]
+    Login l    -> (field "action" "login"): (toReq l)
+    Logout     -> [field "action" "logout"]
+    Query q qr -> (field "action" "query") : (showQuery q) ++ qr
+    ExpandTemplates et -> (field "action" "expandtemplates") : (showExpandTemplates et)
+    Parse pt -> (field "action" "parse") : (showParseRequest pt)
+    OpenSearch os ->  (field "action" "opensearch") : (showOpenSearch os)
+    FeedWatch f -> (field "action" "feedwatchlist") : (showFeedWatch f)
+    Help h -> (field "action" "help") : (showHelpRequest h)
+    ParamInfo pin ->  (field "action" "paraminfo") : (showParamInfoRequest pin)
+    Unblock r -> (field "action" "unblock") : toReq r
+    Watch   r -> (field "action" "watch") : toReq r
+    EmailUser r -> (field "action" "emailuser") : toReq r
+    Edit      r -> (field "action" "edit") : toReq r
+    Move      r -> (field "action" "move") : toReq r
+    Block     r -> (field "action" "block") : toReq r
+    Protect   r -> (field "action" "protect") : toReq r
+    Undelete  r -> (field "action" "undelete") : toReq r
+    Delete    r -> (field "action" "delete") : toReq r
+    Rollback  r -> (field "action" "rollback") : toReq r
+    OtherAction  at vs -> (field "action" at) : (map showValueName vs)
+
+{-
+showLoginRequest :: LoginRequest -> [String]
+showLoginRequest l = catMaybes 
+  [ Just $ field "name" (lgName l)
+  , Just $ field "password" (lgPassword l)
+  , fieldMb "version" id (lgDomain l)
+  ]
+-}
+
+showHelpRequest :: HelpRequest -> [String]
+showHelpRequest h = 
+  maybeToList (fieldMb "version" showBool (helpVersion h))
+
+showQuery :: QueryRequest -> [String]
+showQuery q = catMaybes
+  [ fieldList "titles"  "," (quTitles q)
+  , fieldList "pageids" "," (quPageIds q)
+  , fieldList "revids"  "," (quRevIds q)
+  , fieldList "prop"    "|" (map showPropKind $ quProps q)
+  , fieldList "list"    "|" (map showListKind $ quLists q)
+  , fieldList "meta"    "|" (map showMetaKind $ quMetas q)
+  , fieldMb   "generator" showGeneratorKind  (quGenerator q)
+  , fieldMb   "redirects" showBool           (quFollowRedirects q)
+  , fieldMb   "indexpageids" showBool        (quIndexPageIds q)
+  ]
+
+showExpandTemplates :: ExpandTemplatesRequest -> [String]
+showExpandTemplates et = catMaybes
+  [ fieldMb "title" id (etTitle et)
+  , Just $ field "text" (etText et)
+  ]
+  
+showPropKind :: PropKind -> String
+showPropKind pk = prKind pk
+
+showListKind :: ListKind -> String
+showListKind lk = liKind lk
+
+showMetaKind :: MetaKind -> String
+showMetaKind mk = meKind mk
+
+showParseRequest :: ParseRequest -> [String]
+showParseRequest p = catMaybes
+  [ fieldMb "title" id (paTitle p)
+  , Just $ field "text" (paText p)
+  , fieldMb "page" id (paPage p)
+  , fieldList "prop" "|" (paProp p)
+  ]
+  
+showOpenSearch :: OpenSearchRequest -> [String]
+showOpenSearch o = catMaybes
+  [ Just $ field "search" (osSearch o)
+  , fieldMb "limit" show (osLimit o)
+  ]
+  
+showFeedWatch :: FeedWatchListRequest -> [String]
+showFeedWatch f = catMaybes
+ [ Just $ field "feedformat" (if feAsAtom f then "atom" else "rss")
+ , fieldMb "hours" show (feHours f)
+ , if feAllRev f then (Just $ field  "allrev" "") else Nothing
+ ]
+ 
+showParamInfoRequest :: ParamInfoRequest -> [String]
+showParamInfoRequest p = catMaybes
+ [ fieldList "modules" "," (paModules p)
+ , fieldList "querymodules" "|" (paQueryModules p)
+ ]
+ 
+showGeneratorKind :: GeneratorKind -> String
+showGeneratorKind gk = genKind gk
+
+showValueName :: ValueName -> String
+showValueName (n,v) = field n v
+
+showBool :: Bool -> String
+showBool True = "true"
+showBool _    = "false"
+
+join :: [String] -> String
+join [] = ""
+join xs = concat (intersperse "&" xs)
+
+field :: String -> String -> String
+field a b = a ++ '=':b
+
+fieldMb :: String -> (a -> String) -> Maybe a -> Maybe String
+fieldMb _ _ Nothing = Nothing
+fieldMb n f (Just x) = Just (field n (f x))
+
+fieldList :: String -> String -> [String] -> Maybe String
+fieldList _ _ [] = Nothing
+fieldList n s xs = Just (field n (concat $ intersperse s xs))
+
+ MediaWiki/API/Query/AllCategories.hs view
@@ -0,0 +1,62 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.AllCategories+-- Description : Representing 'allcategories' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'allcategories' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.AllCategories where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.CategoryInfo ( CategoryInfo )++data AllCategoriesRequest+ = AllCategoriesRequest+    { acFrom            :: Maybe PageName+    , acPrefix          :: Maybe PageName+    , acDir             :: Maybe Direction+    , acLimit           :: Maybe Int+    , acProp            :: [String]+    }++instance APIRequest AllCategoriesRequest where+  queryKind _ = QList "allcategories"+  showReq r +   = [ mbOpt "acfrom" id (acFrom r)+     , mbOpt "acprefix" id (acPrefix r)+     , mbOpt "acdir" (\ x -> if x == Up then "ascending" else "descending")+                     (acDir r)+     , mbOpt "aclimit" show (acLimit r)+     , opt1   "acprop" (acProp r)+     ]++emptyAllCategoriesRequest :: AllCategoriesRequest+emptyAllCategoriesRequest = AllCategoriesRequest+    { acFrom            = Nothing+    , acPrefix          = Nothing+    , acDir             = Nothing+    , acLimit           = Nothing+    , acProp            = []+    }++  +data AllCategoriesResponse+ = AllCategoriesResponse+    { acCategories :: [CategoryInfo]+    , acContinue   :: Maybe String+    }+    +emptyAllCategoriesResponse :: AllCategoriesResponse+emptyAllCategoriesResponse+ = AllCategoriesResponse+    { acCategories = []+    , acContinue   = Nothing+    }
+ MediaWiki/API/Query/AllCategories/Import.hs view
@@ -0,0 +1,33 @@+module MediaWiki.API.Query.AllCategories.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.AllCategories+import MediaWiki.API.Query.CategoryInfo+import MediaWiki.API.Query.CategoryInfo.Import ( xmlCI )++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) AllCategoriesResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe AllCategoriesResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlCII) (fmap children $ pNode "allcategories" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "allcategories" "acfrom"+  return emptyAllCategoriesResponse{acCategories=ps,acContinue=cont}++xmlCII :: Element -> Maybe CategoryInfo+xmlCII e = do+  c <- xmlCI emptyPageTitle "c" e+  let tit = strContent e+  return c{ciPage=(ciPage c){pgTitle=tit}}+  
+ MediaWiki/API/Query/AllImages.hs view
@@ -0,0 +1,75 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.AllImages+-- Description : Representing 'allimages' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'allimages' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.AllImages where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.ImageInfo ( ImageInfo )++data AllImagesRequest+ = AllImagesRequest+    { aiFrom            :: Maybe PageName+    , aiPrefix          :: Maybe PageName+    , aiMinSize         :: Maybe Int+    , aiMaxSize         :: Maybe Int+    , aiLimit           :: Maybe Int+    , aiDir             :: Maybe Direction+    , aiSha1            :: Maybe String+    , aiSha1Base36      :: Maybe String+    , aiProp            :: [String]+    }++instance APIRequest AllImagesRequest where+  queryKind _ = QList "allimages"+  showReq r+   = [ mbOpt "aifrom" id (aiFrom r)+     , mbOpt "aiprefix" id (aiPrefix r)+     , mbOpt "aiminsize" show (aiMinSize r)+     , mbOpt "aimaxsize" show (aiMaxSize r)+     , mbOpt "ailimit" show (aiLimit r)+     , mbOpt "aidir"   (\ x -> if x == Up then "ascending" else "descending")+                       (aiDir r)+     , mbOpt "aisha1"  id (aiSha1 r)+     , mbOpt "aisha1base36" id (aiSha1Base36 r)+     , opt1  "aiprop" (aiProp r)+     ]+++emptyAllImagesRequest :: AllImagesRequest+emptyAllImagesRequest = AllImagesRequest+    { aiFrom            = Nothing+    , aiPrefix          = Nothing+    , aiMinSize         = Nothing+    , aiMaxSize         = Nothing+    , aiLimit           = Nothing+    , aiDir             = Nothing+    , aiSha1            = Nothing+    , aiSha1Base36      = Nothing+    , aiProp            = []+    }++  +data AllImagesResponse+ = AllImagesResponse+    { aiImages   :: [ImageInfo]+    , aiContinue :: Maybe String+    }+    +emptyAllImagesResponse :: AllImagesResponse+emptyAllImagesResponse+ = AllImagesResponse+    { aiImages   = []+    , aiContinue = Nothing+    }
+ MediaWiki/API/Query/AllImages/Import.hs view
@@ -0,0 +1,25 @@+module MediaWiki.API.Query.AllImages.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.AllImages+import MediaWiki.API.Query.ImageInfo.Import ( xmlII )++import Text.XML.Light.Types+import Text.XML.Light.Proc   ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) AllImagesResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe AllImagesResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe (xmlII "img")) (fmap children $ pNode "allimages" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "allimages" "aifrom"+  return emptyAllImagesResponse{aiImages=ps,aiContinue=cont}
+ MediaWiki/API/Query/AllLinks.hs view
@@ -0,0 +1,66 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.AllLinks+-- Description : Representing 'alllinks' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'alllinks' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.AllLinks where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data AllLinksRequest+ = AllLinksRequest+    { alContinueFrom :: Maybe String+    , alFrom      :: Maybe PageName+    , alPrefix    :: Maybe PageName+    , alUnique    :: Bool+    , alProp      :: [String]+    , alNamespace :: Maybe NamespaceID+    , alLimit     :: Maybe Int+    }++instance APIRequest AllLinksRequest where+  queryKind _ = QList "alllinks"+  showReq r  =+   [ mbOpt "alcontinue" id (alContinueFrom r)+   , mbOpt "alfrom" id (alFrom r)+   , mbOpt "alprefix" id (alPrefix r)+   , optB  "alunique" (alUnique r)+   , opt1 "alprop" (alProp r)+   , mbOpt "alnamespace" id (alNamespace r)+   , mbOpt "allimit" show (alLimit r)+   ]++emptyAllLinksRequest :: AllLinksRequest+emptyAllLinksRequest = AllLinksRequest+    { alContinueFrom = Nothing+    , alFrom      = Nothing+    , alPrefix    = Nothing+    , alUnique    = False+    , alProp      = []+    , alNamespace = Nothing+    , alLimit     = Nothing+    }+  +data AllLinksResponse+ = AllLinksResponse+    { alLinks    :: [PageTitle]+    , alContinue :: Maybe String+    }+    +emptyAllLinksResponse :: AllLinksResponse+emptyAllLinksResponse+ = AllLinksResponse+    { alLinks    = []+    , alContinue = Nothing+    }+    
+ MediaWiki/API/Query/AllLinks/Import.hs view
@@ -0,0 +1,31 @@+module MediaWiki.API.Query.AllLinks.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.AllLinks++import Text.XML.Light.Types++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) AllLinksResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe AllLinksResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlLink) (fmap children $ pNode "alllinks" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "alllinks" "alcontinue"+  return emptyAllLinksResponse{alLinks=ps,alContinue=cont}++xmlLink :: Element -> Maybe PageTitle+xmlLink e = do+   guard (elName e == nsName "l")+   let ns     = fromMaybe "0" $ pAttr "ns" e+   let tit    = fromMaybe ""  $ pAttr "title" e+   let pid    = pAttr "fromid" e+   return emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}
+ MediaWiki/API/Query/AllMessages.hs view
@@ -0,0 +1,66 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.AllMessages+-- Description : Representing 'allmessages' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'allmessages' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.AllMessages where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data AllMessagesRequest+ = AllMessagesRequest+    { amMessages        :: [String]+    , amFilter          :: Maybe String+    , amLang            :: Maybe String+    }++instance APIRequest AllMessagesRequest where+  queryKind _ = QMeta "allmessages"+  showReq r = [ opt1  "ammessages" (amMessages r)+              , mbOpt "amfilter" id (amFilter r)+	      , mbOpt "amlang" id (amLang r)+	      ]++emptyAllMessagesRequest :: AllMessagesRequest+emptyAllMessagesRequest = AllMessagesRequest+    { amMessages = []+    , amFilter   = Nothing+    , amLang     = Nothing+    }++  +data AllMessagesResponse+ = AllMessagesResponse+    { amsgMessages :: [MessageInfo]+    }+    +emptyAllMessagesResponse :: AllMessagesResponse+emptyAllMessagesResponse+ = AllMessagesResponse+    { amsgMessages = []+    }++data MessageInfo+ = MessageInfo+     { msgiName :: String+     , msgiMissing :: Bool+     , msgiContent :: String+     }+     +emptyMessageInfo :: MessageInfo+emptyMessageInfo = MessageInfo+     { msgiName = ""+     , msgiMissing = False+     , msgiContent = ""+     }+     
+ MediaWiki/API/Query/AllMessages/Import.hs view
@@ -0,0 +1,31 @@+module MediaWiki.API.Query.AllMessages.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.AllMessages++import Text.XML.Light.Types+import Text.XML.Light.Proc   ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) AllMessagesResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe AllMessagesResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "pages" es)+  return emptyAllMessagesResponse{amsgMessages=ps}++xmlPage :: Element -> Maybe MessageInfo+xmlPage e = do+   guard (elName e == nsName "message")+   let nm    = fromMaybe "" $ pAttr "name" e+   let mi    = isJust (pAttr "missing" e)+   return emptyMessageInfo{msgiName=nm,msgiMissing=mi,msgiContent=strContent e}+   
+ MediaWiki/API/Query/AllPages.hs view
@@ -0,0 +1,76 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.AllPages+-- Description : Representing 'allpages' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'allpages' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.AllPages where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data AllPagesRequest+ = AllPagesRequest+    { apFrom            :: Maybe PageName+    , apPrefix          :: Maybe PageName+    , apNamespace       :: NamespaceID+    , apFilterRedir     :: Maybe WithRedirects+    , apMinSize         :: Maybe Int+    , apMaxSize         :: Maybe Int+    , apProtTypeLevel   :: ([String],[String])+    , apLimit           :: Maybe Int+    , apDir             :: Maybe Direction+    , apFilterLangLinks :: Maybe FilterLang+    }++instance APIRequest AllPagesRequest where+  queryKind _ = QList "allpages"+  showReq r = +    [ mbOpt "apfrom" id (apFrom r)+    , mbOpt "apprefix" id (apPrefix r)+    , mbOpt  "apnamespace" id (Just $ apNamespace r)+    , mbOpt "apfilterredir" id (apFilterRedir r)+    , mbOpt "apminsize" show (apMinSize r)+    , mbOpt "apmaxsize" show (apMaxSize r)+    , mbOpt "apprtype"  (piped.fst) (Just $ apProtTypeLevel r)+    , mbOpt "apprlevel" (piped.snd) (Just $ apProtTypeLevel r)+    , mbOpt "aplimit" show (apLimit r)+    , mbOpt "apdir"  (\ x -> if x==Up then "ascending" else "descending") (apDir r)+    , mbOpt "apfilterlanglinks" id (apFilterLangLinks r)+    ]++emptyAllPagesRequest :: AllPagesRequest+emptyAllPagesRequest = AllPagesRequest+    { apFrom            = Nothing+    , apPrefix          = Nothing+    , apNamespace       = mainNamespace+    , apFilterRedir     = Nothing+    , apMinSize         = Nothing+    , apMaxSize         = Nothing+    , apProtTypeLevel   = ([],[])+    , apLimit           = Nothing+    , apDir             = Nothing+    , apFilterLangLinks = Nothing+    }++  +data AllPagesResponse+ = AllPagesResponse+    { apLinks    :: [PageTitle] -- seems to have evolved now (1.13) to PageInfo.+    , apContinue :: Maybe String+    }+    +emptyAllPagesResponse :: AllPagesResponse+emptyAllPagesResponse+ = AllPagesResponse+    { apLinks    = []+    , apContinue = Nothing+    }
+ MediaWiki/API/Query/AllPages/Import.hs view
@@ -0,0 +1,37 @@+module MediaWiki.API.Query.AllPages.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.AllPages++import Text.XML.Light.Types+import Text.XML.Light.Proc   ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) AllPagesResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe AllPagesResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "pages" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "allpages" "gapfrom"+  return emptyAllPagesResponse{apLinks=ps,apContinue=cont}++xmlPage :: Element -> Maybe PageTitle+xmlPage e = do+   guard (elName e == nsName "page")+   let ns     = fromMaybe "0" $ pAttr "ns" e+   let tit    = fromMaybe ""  $ pAttr "title" e+   let pid    = pAttr "pageid" e+    -- more to follow, I'm also seeing these with 1.13:+   let tou    = pAttr "touched" e+   let las    = pAttr "lastrevid" e+   let views  = pAttr "counter" e+   let len    = pAttr "length" e+   return emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}
+ MediaWiki/API/Query/AllUsers.hs view
@@ -0,0 +1,60 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.AllUsers+-- Description : Representing 'allusers' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'allusers' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.AllUsers where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data AllUsersRequest+ = AllUsersRequest+    { auFrom   :: Maybe UserName+    , auPrefix :: Maybe UserName+    , auGroup  :: Maybe GroupName+    , auProp   :: [String]+    , auLimit  :: Maybe Int+    }+    +instance APIRequest AllUsersRequest where+  queryKind _ = QList "allusers"+  showReq r = +   [ mbOpt "aufrom" id (auFrom r)+   , mbOpt "auprefix" id (auPrefix r)+   , mbOpt "augroup" id (auGroup r)+   , opt1  "auprop" (auProp r)+   , mbOpt "aulimit" show (auLimit r)+   ]+    ++emptyAllUsersRequest :: AllUsersRequest+emptyAllUsersRequest = AllUsersRequest+    { auFrom   = Nothing+    , auPrefix = Nothing+    , auGroup  = Nothing+    , auProp   = []+    , auLimit  = Nothing+    }++data AllUsersResponse+ = AllUsersResponse+    { auUsers    :: [(UserName, Maybe Int, Maybe String)]+    , auContinue :: Maybe String+    }+    +emptyAllUsersResponse :: AllUsersResponse+emptyAllUsersResponse+ = AllUsersResponse+    { auUsers    = []+    , auContinue = Nothing+    }
+ MediaWiki/API/Query/AllUsers/Import.hs view
@@ -0,0 +1,33 @@+module MediaWiki.API.Query.AllUsers.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.AllUsers++import Text.XML.Light.Types+import Text.XML.Light.Proc   ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) AllUsersResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe AllUsersResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlUser) (fmap children $ pNode "allusers" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "allusers" "aufrom"+  return emptyAllUsersResponse{auUsers=ps,auContinue=cont}++xmlUser :: Element -> Maybe (UserName,Maybe Int, Maybe String)+xmlUser e = do+   guard (elName e == nsName "u")+   let ns     = fromMaybe "0" $ pAttr "ns" e+   let nm     = fromMaybe ""  $ pAttr "name" e+   let ec     = pAttr "editcount" e >>= \ x -> case reads x of { ((v,_):_) -> Just v; _ -> Nothing}+   let grps   = pAttr "groups" e+   return (nm,ec,grps)
+ MediaWiki/API/Query/BackLinks.hs view
@@ -0,0 +1,62 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.BackLinks+-- Description : Representing 'backlinks' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'backlinks' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.BackLinks where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data BackLinksRequest+ = BackLinksRequest+    { blTitle        :: Maybe String+    , blContinueFrom :: Maybe String+    , blNamespace    :: [NamespaceID]+    , blFilterRedir  :: Maybe Redirect+    , blRedirect     :: Maybe Bool+    , blLimit        :: Maybe Int+    }++instance APIRequest BackLinksRequest where+  queryKind _ = QList "backlinks"+  showReq r = +   [ mbOpt "bltitle" id (blTitle r)+   , mbOpt "blcontinue" id (blContinueFrom r)+   , opt1  "blnamespace" (blNamespace r)+   , mbOpt "blfilterredir" id (blFilterRedir r)+   , optB  "blredirect" (fromMaybe False $ blRedirect r)+   , mbOpt "bllimit" show (blLimit r)+   ]++emptyBackLinksRequest :: BackLinksRequest+emptyBackLinksRequest = BackLinksRequest+    { blTitle        = Nothing+    , blContinueFrom = Nothing+    , blNamespace    = []+    , blFilterRedir  = Nothing+    , blRedirect     = Nothing+    , blLimit        = Nothing+    }++data BackLinksResponse+ = BackLinksResponse+    { blLinks    :: [PageTitle]+    , blContinue :: Maybe String+    }+    +emptyBackLinksResponse :: BackLinksResponse+emptyBackLinksResponse+ = BackLinksResponse+    { blLinks    = []+    , blContinue = Nothing+    }
+ MediaWiki/API/Query/BackLinks/Import.hs view
@@ -0,0 +1,31 @@+module MediaWiki.API.Query.BackLinks.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.BackLinks++import Text.XML.Light.Types++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) BackLinksResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe BackLinksResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "backlinks" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "backlinks" "blcontinue"+  return emptyBackLinksResponse{blLinks=ps,blContinue=cont}++xmlPage :: Element -> Maybe PageTitle+xmlPage e = do+   guard (elName e == nsName "bl")+   let ns     = fromMaybe "0" $ pAttr "ns" e+   let tit    = fromMaybe ""  $ pAttr "title" e+   let mbpid  = pAttr "pageid" e+   return emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=mbpid}
+ MediaWiki/API/Query/Blocks.hs view
@@ -0,0 +1,107 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.Blocks+-- Description : Representing 'blocks' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'blocks' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.Blocks where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data BlocksRequest+ = BlocksRequest+    { bkStart    :: Maybe Timestamp+    , bkEnd      :: Maybe Timestamp+    , bkDir      :: Maybe TimeArrow+    , bkIds      :: [UserID]+    , bkUsers    :: [UserID]+    , bkIp       :: [String]+    , bkLimit    :: Maybe Int+    , bkProp     :: [String]+    }++instance APIRequest BlocksRequest where+  queryKind _ = QList "blocks"+  showReq r+   = [ mbOpt "bkstart" id (bkStart r)+     , mbOpt "bkend"   id (bkEnd r)+     , mbOpt "bkdir"   (\ x -> if x==Earlier then "older" else "newer")+                       (bkDir r)+     , opt1 "bkids"    (bkIds r)+     , opt1 "bkusers"  (bkUsers r)+     , opt1 "bkip"     (bkIp r)+     , mbOpt "bklimit" show (bkLimit r)+     , opt1 "bkprop"    (bkProp r)+     ]++emptyBlocksRequest :: BlocksRequest+emptyBlocksRequest = BlocksRequest+    { bkStart    = Nothing+    , bkEnd      = Nothing+    , bkDir      = Nothing+    , bkIds      = []+    , bkUsers    = []+    , bkIp       = []+    , bkLimit    = Nothing+    , bkProp     = []+    }+    +data BlocksResponse+ = BlocksResponse+    { bkBlocks :: [BlockInfo]+    , bkContinue :: Maybe String+    }+    +emptyBlocksResponse :: BlocksResponse+emptyBlocksResponse = BlocksResponse+    { bkBlocks   = []+    , bkContinue = Nothing+    }++data BlockInfo+ = BlockInfo+    { bkId :: Maybe String+    , bkUser :: Maybe UserName+    , bkBy   :: Maybe UserName+    , bkTimestamp :: Maybe Timestamp+    , bkExpiry :: Maybe Timestamp+    , bkReason :: Maybe String+    , bkRangeStart :: Maybe String+    , bkRangeEnd :: Maybe String+    , bkIsAuto :: Bool+    , bkIsAnonOnly :: Bool+    , bkIsNoCreate :: Bool+    , bkIsAutoBlock :: Bool+    , bkIsNoEmail :: Bool+    , bkIsHidden :: Bool+    }+    +emptyBlockInfo :: BlockInfo+emptyBlockInfo = BlockInfo+    { bkId = Nothing+    , bkUser = Nothing+    , bkBy   = Nothing+    , bkTimestamp = Nothing+    , bkExpiry = Nothing+    , bkReason = Nothing+    , bkRangeStart = Nothing+    , bkRangeEnd = Nothing+    , bkIsAuto = False+    , bkIsAnonOnly  = False+    , bkIsNoCreate  = False+    , bkIsAutoBlock  = False+    , bkIsNoEmail  = False+    , bkIsHidden  = False+    }+++
+ MediaWiki/API/Query/Blocks/Import.hs view
@@ -0,0 +1,58 @@+module MediaWiki.API.Query.Blocks.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.Blocks++import Text.XML.Light.Types+import Text.XML.Light.Proc   ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) BlocksResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe BlocksResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlB) (fmap children $ pNode "blocks" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "blocks" "blfrom"+  return emptyBlocksResponse{bkBlocks=ps,bkContinue=cont}++xmlB :: Element -> Maybe BlockInfo+xmlB e = do+   guard (elName e == nsName "block")+   let i      = pAttr "id" e+   let usr    = pAttr "user" e+   let by     = pAttr "by" e+   let ts     = pAttr "timestamp" e+   let ex     = pAttr "expiry" e+   let re     = pAttr "reason" e+   let ras    = pAttr "rangestart" e+   let rae    = pAttr "rangeend" e+   let isa    = isJust $ pAttr "automatic" e+   let isan   = isJust $ pAttr "anononly" e+   let isnc   = isJust $ pAttr "nocreate" e+   let isab   = isJust $ pAttr "autoblock" e+   let isne   = isJust $ pAttr "noemail" e+   let ishi   = isJust $ pAttr "hidden" e+   return emptyBlockInfo+    { bkId = i+    , bkUser = usr+    , bkBy   = by+    , bkTimestamp = ts+    , bkExpiry = ex+    , bkReason = re+    , bkRangeStart = ras+    , bkRangeEnd = rae+    , bkIsAuto = isa+    , bkIsAnonOnly  = isan+    , bkIsNoCreate  = isnc+    , bkIsAutoBlock  = isab+    , bkIsNoEmail  = isne+    , bkIsHidden  = ishi+    }
+ MediaWiki/API/Query/Categories.hs view
@@ -0,0 +1,57 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.Categories+-- Description : Representing 'categories' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'categories' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.Categories where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data CategoriesRequest+ = CategoriesRequest+    { clProps :: [PropKind]+    , clShow  :: Maybe Bool+    , clLimit :: Maybe Int+    , clContinueFrom :: Maybe String+    }++instance APIRequest CategoriesRequest where+  queryKind _ = QProp "categories"+  showReq r = +   [ opt1 "clprop" (map prKind $ clProps r)+   , mbOpt "clshow" (\ x -> if x then "!hidden" else "hidden") (clShow r)+   , mbOpt "cllimit" show (clLimit r)+   , mbOpt "clcontinue" id (clContinueFrom r)+   ]++emptyCategoriesRequest :: CategoriesRequest+emptyCategoriesRequest = CategoriesRequest+    { clProps = []+    , clShow  = Nothing+    , clLimit = Nothing+    , clContinueFrom = Nothing+    }+++data CategoriesResponse+ = CategoriesResponse+    { clPages    :: [(PageTitle,[PageTitle])]+    , clContinue :: Maybe String+    }+    +emptyCategoriesResponse :: CategoriesResponse+emptyCategoriesResponse+ = CategoriesResponse+    { clPages    = []+    , clContinue = Nothing+    }
+ MediaWiki/API/Query/Categories/Import.hs view
@@ -0,0 +1,45 @@+module MediaWiki.API.Query.Categories.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.Categories++import Text.XML.Light.Types++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) CategoriesResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe CategoriesResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es2 = children p+  p  <- pNode "pages" es2+  let es = children p+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "page" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "categories" "clcontinue"+  return emptyCategoriesResponse{clPages=ps,clContinue=cont}++xmlPage :: Element -> Maybe (PageTitle,[PageTitle])+xmlPage e = do+   guard (elName e == nsName "page")+   let es = children e+   p <- pNode "categories" es+   let es1 = children p+   cs <- fmap (mapMaybe xmlCL) (fmap children $ pNode "cl" es1)+   let ns     = fromMaybe "0" $ pAttr "ns" p+   let tit    = fromMaybe ""  $ pAttr "title" p+   let mbpid  = pAttr "pageid" p+   return (emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=mbpid}, cs)++xmlCL :: Element -> Maybe PageTitle+xmlCL e = do+   guard (elName e == nsName "cl")+   let ns     = fromMaybe "0" $ pAttr "ns" e+   let tit    = fromMaybe ""  $ pAttr "title" e+   let mbpid  = pAttr "pageid" e+   return emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=mbpid}
+ MediaWiki/API/Query/CategoryInfo.hs view
@@ -0,0 +1,59 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.CategoryInfo+-- Description : Representing CategoryInfo requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing CategoryInfo requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.CategoryInfo where++import MediaWiki.API.Types+import MediaWiki.API.Utils ()++data CategoryInfoRequest+ = CategoryInfoRequest+ +instance APIRequest CategoryInfoRequest where+  queryKind _ = QProp "categoryinfo"+  showReq _ = []++emptyCategoryInfoRequest :: CategoryInfoRequest+emptyCategoryInfoRequest = CategoryInfoRequest++data CategoryInfoResponse + = CategoryInfoResponse+     { ciPages :: [CategoryInfo]+     }+     +emptyCategoryInfoResponse :: CategoryInfoResponse+emptyCategoryInfoResponse = CategoryInfoResponse+     { ciPages = []+     }++data CategoryInfo+ = CategoryInfo+     { ciPage       :: PageTitle+     , ciSize       :: Maybe Int+     , ciPageSize   :: Maybe Int+     , ciFiles      :: Maybe Int+     , ciSubCats    :: Maybe Int+     , ciHidden     :: Bool+     }++emptyCategoryInfo :: CategoryInfo+emptyCategoryInfo = CategoryInfo+     { ciPage = emptyPageTitle+     , ciSize = Nothing+     , ciPageSize = Nothing+     , ciFiles = Nothing+     , ciSubCats = Nothing+     , ciHidden = False+     }+     
+ MediaWiki/API/Query/CategoryInfo/Import.hs view
@@ -0,0 +1,50 @@+module MediaWiki.API.Query.CategoryInfo.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.CategoryInfo++import Text.XML.Light.Types++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) CategoryInfoResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe CategoryInfoResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "pages" es)+  return emptyCategoryInfoResponse{ciPages=ps}++xmlPage :: Element -> Maybe CategoryInfo+xmlPage e = do+   guard (elName e == nsName "page")+   let ns     = fromMaybe "0" $ pAttr "ns" e+   let tit    = fromMaybe ""  $ pAttr "title" e+   let pid    = pAttr "pageid" e+   let pg     = emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}+   let cs = mapMaybe (xmlCI pg "categoryinfo") (children e)+   listToMaybe cs+   +xmlCI :: PageTitle -> String -> Element -> Maybe CategoryInfo+xmlCI pg tg e = do+   guard (elName e == nsName tg)+   let sz  = pAttr "size" e >>= readMb+   let psz = pAttr "pagesize" e >>= readMb+   let fi  = pAttr "files" e >>= readMb+   let su  = pAttr "subcats" e >>= readMb+   let hi  = isJust (pAttr "hidden" e)+   return emptyCategoryInfo+               { ciPage = pg+	       , ciSize = sz+	       , ciPageSize = psz+	       , ciFiles = fi+	       , ciSubCats = su+	       , ciHidden = hi+	       }+
+ MediaWiki/API/Query/CategoryMembers.hs view
@@ -0,0 +1,71 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.CategoryMembers+-- Description : Representing 'categorymembers' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'categorymembers' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.CategoryMembers where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data CategoryMembersRequest+ = CategoryMembersRequest+    { cmTitle        :: Maybe PageName+    , cmProp         :: [String]+    , cmNamespace    :: [NamespaceID]+    , cmContinueFrom :: Maybe String+    , cmLimit        :: Maybe Int+    , cmSort         :: Maybe SortKind+    , cmDir          :: Maybe Direction+    , cmStart        :: Maybe Timestamp+    , cmEnd          :: Maybe Timestamp+    }++instance APIRequest CategoryMembersRequest where+  queryKind _ = QList "categorymembers"+  showReq r = +    [ mbOpt "cmtitle" id (cmTitle r)+    , opt1  "cmprop" (cmProp r)+    , opt1  "cmnamespace" (cmNamespace r)+    , mbOpt "cmcontinue" id (cmContinueFrom r)+    , mbOpt "cmlimit" show (cmLimit r)+    , mbOpt "cmsort" id (cmSort r)+    , mbOpt "cmdir"  (\ x -> if x==Up then "asc" else "desc") (cmDir r)+    , mbOpt "cmstart" id (cmStart r)+    , mbOpt "cmend" id (cmEnd r)+    ]++emptyCategoryMembersRequest :: CategoryMembersRequest+emptyCategoryMembersRequest = CategoryMembersRequest+    { cmTitle        = Nothing+    , cmProp         = []+    , cmNamespace    = []+    , cmContinueFrom = Nothing+    , cmLimit        = Nothing+    , cmSort         = Nothing+    , cmDir          = Nothing+    , cmStart        = Nothing+    , cmEnd          = Nothing+    }++data CategoryMembersResponse+ = CategoryMembersResponse+    { cmPages    :: [PageTitle]+    , cmContinue :: Maybe String+    }+    +emptyCategoryMembersResponse :: CategoryMembersResponse+emptyCategoryMembersResponse = CategoryMembersResponse+    { cmPages = []+    , cmContinue = Nothing+    }+    
+ MediaWiki/API/Query/CategoryMembers/Import.hs view
@@ -0,0 +1,32 @@+module MediaWiki.API.Query.CategoryMembers.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.CategoryMembers++import Text.XML.Light.Types++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) CategoryMembersResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe CategoryMembersResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "categorymembers" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "categorymembers" "cmcontinue"+  return emptyCategoryMembersResponse{cmPages=ps,cmContinue=cont}++xmlPage :: Element -> Maybe PageTitle+xmlPage e = do+   guard (elName e == nsName "cm")+   let ns     = fromMaybe "0" $ pAttr "ns" e+   let tit    = fromMaybe ""  $ pAttr "title" e+   let mbpid  = pAttr "pageid" e+   let ts     = pAttr "timestamp" e+   return emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=mbpid}
+ MediaWiki/API/Query/DeletedRevisions.hs view
@@ -0,0 +1,85 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.DeletedRevisions+-- Description : Representing 'deletedrevs' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'deletedrevs' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.DeletedRevisions where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data DeletedRevisionsRequest+ = DeletedRevisionsRequest+    { drStart       :: Maybe Timestamp+    , drEnd         :: Maybe Timestamp+    , drDir         :: Maybe TimeArrow+    , drLimit       :: Maybe Int+    , drProp        :: [String]+    }++instance APIRequest DeletedRevisionsRequest where+  queryKind _ = QList "deletedrevs"+  showReq r = [ mbOpt   "drstart" id (drStart r)+              , mbOpt   "drend"   id (drEnd r)+	      , mbOpt   "drdir"   (\ x -> if x==Earlier then "older" else "newer")+	                (drDir r)+	      , mbOpt   "drlimit" show (drLimit r)+	      , opt1    "drprop"  (drProp r)+	      ]++emptyDeletedRevisionsRequest :: DeletedRevisionsRequest+emptyDeletedRevisionsRequest = DeletedRevisionsRequest+    { drStart       = Nothing+    , drEnd         = Nothing+    , drDir         = Nothing+    , drLimit       = Nothing+    , drProp        = []+    }++data DeletedRevisionsResponse+ = DeletedRevisionsResponse+    { drRevisions :: [DeletedRevision]+    , drContinue  :: Maybe String+    }++emptyDeletedRevisionsResponse :: DeletedRevisionsResponse+emptyDeletedRevisionsResponse = DeletedRevisionsResponse+    { drRevisions = []+    , drContinue  = Nothing+    }++data DeletedRevision+ = DeletedRevision+    { drPage      :: PageTitle+    , drTimestamp :: Maybe Timestamp+    , drRevId     :: Maybe RevID+    , drUser      :: Maybe UserName+    , drComment   :: Maybe String+    , drIsMinor   :: Bool+    , drLength    :: Maybe Int+    , drContent   :: Maybe String+    , drToken     :: Maybe String+    }+    +emptyDeletedRevision :: DeletedRevision+emptyDeletedRevision + = DeletedRevision+    { drPage      = emptyPageTitle+    , drTimestamp = Nothing+    , drRevId     = Nothing+    , drUser      = Nothing+    , drComment   = Nothing+    , drIsMinor   = False+    , drLength    = Nothing+    , drContent   = Nothing+    , drToken     = Nothing+    }
+ MediaWiki/API/Query/DeletedRevisions/Import.hs view
@@ -0,0 +1,51 @@+module MediaWiki.API.Query.DeletedRevisions.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.DeletedRevisions++import Text.XML.Light.Types+import Text.XML.Light.Proc   ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) DeletedRevisionsResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe DeletedRevisionsResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "revisions" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "deletedrevs" "drstart"+  return emptyDeletedRevisionsResponse{drRevisions=ps,drContinue=cont}++xmlPage :: Element -> Maybe DeletedRevision+xmlPage e = do+   guard (elName e == nsName "page")+   let ns     = fromMaybe "0" $ pAttr "ns" e+   let tit    = fromMaybe ""  $ pAttr "title" e+   let pid    = pAttr "pageid" e+   let pg     = emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}+   let ts     = pAttr "timestamp" e+   let re     = pAttr "revid" e+   let usr    = pAttr "user" e+   let co     = pAttr "comment" e+   let ism     = isJust $ pAttr "minor" e+   let le     = pAttr "len" e >>= readMb+   let cts    = case (strContent e) of { "" -> Nothing; xs -> Just xs}+   let tok    = pAttr "token" e+   return emptyDeletedRevision+    { drPage      = pg+    , drTimestamp = ts+    , drRevId     = re+    , drUser      = usr+    , drComment   = co+    , drIsMinor   = ism+    , drLength    = le+    , drContent   = cts+    , drToken     = tok+    }
+ MediaWiki/API/Query/EmbeddedIn.hs view
@@ -0,0 +1,62 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.EmbeddedIn+-- Description : Representing 'embeddedin' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'embeddedin' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.EmbeddedIn where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data EmbeddedInRequest+ = EmbeddedInRequest+    { eiTitle        :: Maybe String+    , eiContinueFrom :: Maybe String+    , eiNamespace    :: [NamespaceID]+    , eiFilterRedir  :: Maybe Redirect+    , eiRedirect     :: Bool+    , eiLimit        :: Maybe Int+    }++instance APIRequest EmbeddedInRequest where+  queryKind _ = QList "embeddedin"+  showReq r = +   [ mbOpt "eititle" id (eiTitle r)+   , mbOpt "eicontinue" id (eiContinueFrom r)+   , opt1  "einamespace" (eiNamespace r)+   , mbOpt "eifilterredir" id (eiFilterRedir r)+   , optB  "eirdirect" (eiRedirect r)+   , mbOpt "eilimit" show (eiLimit r)+   ]++emptyEmbeddedInRequest :: EmbeddedInRequest+emptyEmbeddedInRequest = EmbeddedInRequest+    { eiTitle        = Nothing+    , eiContinueFrom = Nothing+    , eiNamespace    = []+    , eiFilterRedir  = Nothing+    , eiRedirect     = False+    , eiLimit        = Nothing+    }++data EmbeddedInResponse+ = EmbeddedInResponse+    { eiLinks    :: [PageTitle]+    , eiContinue :: Maybe String+    }+    +emptyEmbeddedInResponse :: EmbeddedInResponse+emptyEmbeddedInResponse+ = EmbeddedInResponse+    { eiLinks    = []+    , eiContinue = Nothing+    }
+ MediaWiki/API/Query/EmbeddedIn/Import.hs view
@@ -0,0 +1,31 @@+module MediaWiki.API.Query.EmbeddedIn.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.EmbeddedIn++import Text.XML.Light.Types++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) EmbeddedInResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe EmbeddedInResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "embeddedin" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "embeddedin" "eicontinue"+  return emptyEmbeddedInResponse{eiLinks=ps,eiContinue=cont}++xmlPage :: Element -> Maybe PageTitle+xmlPage e = do+   guard (elName e == nsName "ei")+   let ns     = fromMaybe "0" $ pAttr "ns" e+   let tit    = fromMaybe ""  $ pAttr "title" e+   let mbpid  = pAttr "pageid" e+   return emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=mbpid}
+ MediaWiki/API/Query/ExternalLinks.hs view
@@ -0,0 +1,50 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.ExternalLinks+-- Description : Representing 'extlinks' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'extlinks' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.ExternalLinks where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data ExternalLinksRequest+ = ExternalLinksRequest+     { elLimit  :: Maybe Int+     , elOffset :: Maybe String+     }+     +instance APIRequest ExternalLinksRequest where+  queryKind _ = QProp "extlinks"+  showReq r =+    [ mbOpt "ellimit" show (elLimit r)+    , mbOpt "eloffset" id (elOffset r)+    ]++emptyExternalLinksRequest :: ExternalLinksRequest+emptyExternalLinksRequest = ExternalLinksRequest+     { elLimit  = Nothing+     , elOffset = Nothing+     }+     +data ExternalLinksResponse+ = ExternalLinksResponse+     { elPages    :: [(PageTitle,[URLString])]+     , elContinue :: Maybe String+     }+     +emptyExternalLinksResponse :: ExternalLinksResponse+emptyExternalLinksResponse = ExternalLinksResponse+     { elPages    = []+     , elContinue = Nothing+     }+     
+ MediaWiki/API/Query/ExternalLinks/Import.hs view
@@ -0,0 +1,44 @@+module MediaWiki.API.Query.ExternalLinks.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.ExternalLinks++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) ExternalLinksResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe ExternalLinksResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es2 = children p+  p  <- pNode "pages" es2+  let es = children p+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "page" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "extlinks" "eloffset"+  return emptyExternalLinksResponse{elPages=ps,elContinue=cont}++xmlPage :: Element -> Maybe (PageTitle,[URLString])+xmlPage e = do+   guard (elName e == nsName "page")+   let es = children e+   p <- pNode "extlinks" es+   let es1 = children p+   cs <- fmap (mapMaybe xmlEL) (fmap children $ pNode "el" es1)+   let ns     = fromMaybe "0" $ pAttr "ns" p+   let tit    = fromMaybe ""  $ pAttr "title" p+   let mbpid  = pAttr "pageid" p+   return (emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=mbpid}, cs)++xmlEL :: Element -> Maybe URLString+xmlEL e = do+   guard (elName e == nsName "el")+   return (strContent e)+
+ MediaWiki/API/Query/ExternalURLUsage.hs view
@@ -0,0 +1,63 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.ExternalURLUsage+-- Description : Representing 'exturlusage' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'exturlusage' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.ExternalURLUsage where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data ExternalURLUsageRequest+ = ExternalURLUsageRequest+    { euProp       :: [String]+    , euOffset     :: Maybe String+    , euProtocol   :: Maybe String+    , euQuery      :: Maybe String+    , euNamespaces :: [NamespaceID]+    , euLimit      :: Maybe Int+    }++instance APIRequest ExternalURLUsageRequest where+  queryKind _ = QList "exturlusage"+  showReq r = +    [ opt1 "euprop" (euProp r)+    , mbOpt "euoffset" id (euOffset r)+    , mbOpt "euprotocol" id (euProtocol r)+    , mbOpt "euquery" id (euQuery r)+    , opt1  "eunamespace" (euNamespaces r)+    , mbOpt "eulimit" show (euLimit r)+    ]++emptyExternalURLUsageRequest :: ExternalURLUsageRequest+emptyExternalURLUsageRequest = ExternalURLUsageRequest+    { euProp       = []+    , euOffset     = Nothing+    , euProtocol   = Nothing+    , euQuery      = Nothing+    , euNamespaces = []+    , euLimit      = Nothing+    }+    +data ExternalURLUsageResponse+ = ExternalURLUsageResponse+    { euPages    :: [(URLString,PageTitle)]+    , euContinue :: Maybe String+    }++emptyExternalURLUsageResponse :: ExternalURLUsageResponse+emptyExternalURLUsageResponse = ExternalURLUsageResponse+    { euPages    = []+    , euContinue = Nothing+    }+    +
+ MediaWiki/API/Query/ExternalURLUsage/Import.hs view
@@ -0,0 +1,35 @@+module MediaWiki.API.Query.ExternalURLUsage.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.ExternalURLUsage++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) ExternalURLUsageResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe ExternalURLUsageResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "exturlusage" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "exturlusage" "euoffset"+  return emptyExternalURLUsageResponse{euPages=ps,euContinue=cont}++xmlPage :: Element -> Maybe (URLString,PageTitle)+xmlPage e = do+   guard (elName e == nsName "eu")+   let ns     = fromMaybe "0" $ pAttr "ns" e+   let tit    = fromMaybe ""  $ pAttr "title" e+   let mbpid  = pAttr "pageid" e+   let url    = fromMaybe ""  $ pAttr "url" e+   return (url,emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=mbpid})++
+ MediaWiki/API/Query/ImageInfo.hs view
@@ -0,0 +1,90 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.ImageInfo+-- Description : Representing 'imageinfo' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'imageinfo' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.ImageInfo where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data ImageInfo+ = ImageInfo+    { iiTimestamp :: Timestamp+    , iiUser      :: UserName+    , iiWidth     :: Maybe Int+    , iiHeight    :: Maybe Int+    , iiSize      :: Maybe Int+    , iiURL       :: Maybe URLString+    , iiComment   :: Maybe String+    , iiSHA1      :: Maybe String+    , iiArchive   :: Maybe String+    , iiBitDepth  :: Maybe Int+    , iiMime      :: Maybe String+    }+    +emptyImageInfo :: ImageInfo+emptyImageInfo = ImageInfo+    { iiTimestamp = nullTimestamp+    , iiUser      = nullUser+    , iiWidth     = Nothing+    , iiHeight    = Nothing+    , iiSize      = Nothing+    , iiURL       = Nothing+    , iiComment   = Nothing+    , iiSHA1      = Nothing+    , iiArchive   = Nothing+    , iiBitDepth  = Nothing+    , iiMime      = Nothing+    }++data ImageInfoRequest+ = ImageInfoRequest +    { iiProp      :: [PropKind]+    , iiLimit     :: Maybe Int+    , iiStart     :: Maybe Timestamp+    , iiEnd       :: Maybe Timestamp+    , iiURLSize   :: Maybe (Int,Int)+    }++instance APIRequest ImageInfoRequest where+ queryKind _ = QProp "imageinfo"+ showReq r =+  [ opt1 "iiprop" (map prKind $ iiProp r)+  , mbOpt "iilimit" show (iiLimit r)+  , mbOpt "iistart" id (iiStart r)+  , mbOpt "iiend" id (iiEnd r)+  , mbOpt "iiurlwidth" (show.fst) (iiURLSize r)+  , mbOpt "iiurlheight" (show.snd) (iiURLSize r)+  ]++emptyImageInfoRequest :: ImageInfoRequest+emptyImageInfoRequest = ImageInfoRequest+    { iiProp      = []+    , iiLimit     = Nothing+    , iiStart     = Nothing+    , iiEnd       = Nothing+    , iiURLSize   = Nothing+    }++data ImageInfoResponse + = ImageInfoResponse+    { iiPages    :: [(PageTitle,[ImageInfo])]+    , iiContinue :: Maybe String+    }++emptyImageInfoResponse :: ImageInfoResponse+emptyImageInfoResponse = ImageInfoResponse+    { iiPages = []+    , iiContinue = Nothing+    }+    
+ MediaWiki/API/Query/ImageInfo/Import.hs view
@@ -0,0 +1,75 @@+module MediaWiki.API.Query.ImageInfo.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.ImageInfo++import Text.XML.Light.Types+import Text.XML.Light.Proc ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) ImageInfoResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe ImageInfoResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1 >>= (pNode "pages").children+  let es = children p+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "page" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "imageinfo" "iistart"+  return emptyImageInfoResponse{iiPages=ps,iiContinue=cont}++xmlPage :: Element -> Maybe (PageTitle,[ImageInfo])+xmlPage e = do+   guard (elName e == nsName "page")+   let es = children e+   p <- pNode "imageinfo" es+   let es1 = children p+   cs <- fmap (mapMaybe (xmlII "ii")) (fmap children $ pNode "ii" es1)+   let ns     = fromMaybe "0" $ pAttr "ns" p+   let tit    = fromMaybe ""  $ pAttr "title" p+   let mbpid  = pAttr "pageid" p+   let miss   = isJust (pAttr "missing" p)+   let rep    = pAttr "imagerepository" p+   return (emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=mbpid}, cs)++xmlII :: String -> Element -> Maybe ImageInfo+xmlII tg p = do+   guard (elName p == nsName tg) +   let ts = fromMaybe nullTimestamp (pAttr "timestamp" p)+   let us = fromMaybe nullUser (pAttr "user" p)+   let wi = pAttr "width" p >>= readI+   let he = pAttr "height" p >>= readI+   let si = pAttr "size" p >>= readI+   let ur = pAttr "url" p+   let co = pAttr "comment" p+   let sh = pAttr "sha1" p+   let ar = pAttr "archivename" p+   let bi = pAttr "bitdepth" p >>= readI+   let mi = pAttr "mime" p+   return emptyImageInfo+    { iiTimestamp = ts+    , iiUser      = us+    , iiWidth     = wi+    , iiHeight    = he+    , iiSize      = si+    , iiURL       = ur+    , iiComment   = co+    , iiSHA1      = sh+    , iiArchive   = ar+    , iiBitDepth  = bi+    , iiMime      = mi+    }++   +readI :: String -> Maybe Int+readI s = +  case reads s of+    ((v,_):_) -> Just v+    _ -> Nothing+    +
+ MediaWiki/API/Query/ImageUsage.hs view
@@ -0,0 +1,62 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.ImageUsage+-- Description : Representing 'imageusage' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'imageusage' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.ImageUsage where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data ImageUsageRequest+ = ImageUsageRequest+    { iuTitle        :: Maybe String+    , iuContinueFrom :: Maybe String+    , iuNamespace    :: [NamespaceID]+    , iuFilterRedir  :: Maybe Redirect+    , iuRedirect     :: Bool+    , iuLimit        :: Maybe Int+    }++instance APIRequest ImageUsageRequest where+  queryKind _ = QList "imageusage"+  showReq r = +   [ mbOpt "iutitle" id (iuTitle r)+   , mbOpt "iucontinue" id (iuContinueFrom r)+   , opt1 "iunamespace" (iuNamespace r)+   , mbOpt "iufilterredir" id (iuFilterRedir r)+   , optB  "iuredirect" (iuRedirect r)+   , mbOpt "iulimit" show (iuLimit r)+   ]++emptyImageUsageRequest :: ImageUsageRequest+emptyImageUsageRequest = ImageUsageRequest+    { iuTitle        = Nothing+    , iuContinueFrom = Nothing+    , iuNamespace    = []+    , iuFilterRedir  = Nothing+    , iuRedirect     = False+    , iuLimit        = Nothing+    }++data ImageUsageResponse+ = ImageUsageResponse+    { iuLinks    :: [PageTitle]+    , iuContinue :: Maybe String+    }+    +emptyImageUsageResponse :: ImageUsageResponse+emptyImageUsageResponse+ = ImageUsageResponse+    { iuLinks    = []+    , iuContinue = Nothing+    }
+ MediaWiki/API/Query/ImageUsage/Import.hs view
@@ -0,0 +1,31 @@+module MediaWiki.API.Query.ImageUsage.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.ImageUsage++import Text.XML.Light.Types++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) ImageUsageResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe ImageUsageResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "imageusage" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "imageusage" "iucontinue"+  return emptyImageUsageResponse{iuLinks=ps,iuContinue=cont}++xmlPage :: Element -> Maybe PageTitle+xmlPage e = do+   guard (elName e == nsName "iu")+   let ns     = fromMaybe "0" $ pAttr "ns" e+   let tit    = fromMaybe ""  $ pAttr "title" e+   let mbpid  = pAttr "pageid" e+   return emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=mbpid}
+ MediaWiki/API/Query/Images.hs view
@@ -0,0 +1,49 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.Images+-- Description : Representing 'images' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'images' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.Images where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data ImagesRequest+ = ImagesRequest+     { imLimit        :: Maybe Int+     , imContinueFrom :: Maybe String+     }++instance APIRequest ImagesRequest where+  queryKind _ = QProp "images"+  showReq r = +   [ mbOpt "imlimit" show (imLimit r)+   , mbOpt "imcontinue" id (imContinueFrom r)+   ]++emptyImagesRequest :: ImagesRequest+emptyImagesRequest = ImagesRequest+  { imLimit        = Nothing+  , imContinueFrom = Nothing+  }+  +data ImagesResponse+ = ImagesResponse+     { imLinks    :: [(PageTitle,[PageTitle])]+     , imContinue :: Maybe String+     }+     +emptyImagesResponse :: ImagesResponse+emptyImagesResponse = ImagesResponse+  { imLinks    = []+  , imContinue = Nothing+  }
+ MediaWiki/API/Query/Images/Import.hs view
@@ -0,0 +1,42 @@+module MediaWiki.API.Query.Images.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.Images++import Text.XML.Light.Types++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) ImagesResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe ImagesResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "pages" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "imageinfo" "iistart"+  return emptyImagesResponse{imLinks=ps,imContinue=cont}++xmlPage :: Element -> Maybe (PageTitle,[PageTitle])+xmlPage e = do+  guard (elName e == nsName "page")+  let pid     = fmap read $ pAttr "pageid" e+  let ns      = fromMaybe mainNamespace $ pAttr "ns" e+  let tit     = fromMaybe ""  $ pAttr "title" e+  let es = children e+  ls <- fmap (mapMaybe xmlIm) (fmap children $ pNode "images" es)+  let pg = emptyPageTitle{pgNS=ns,pgMbId=pid,pgTitle=tit}+  return (pg, ls)++xmlIm :: Element -> Maybe PageTitle+xmlIm e = do+   guard (elName e == nsName "im")+   let ns     = fromMaybe ns_IMAGE $  pAttr "ns" e+   let ti     = fromMaybe "" $ pAttr "title" e+   let pid    = pAttr "pageid" e+   return emptyPageTitle{pgNS=ns,pgTitle=ti,pgMbId=pid}
+ MediaWiki/API/Query/Info.hs view
@@ -0,0 +1,90 @@+--------------------------------------------------------------------
+-- |
+-- Module      : MediaWiki.API.Query.Info
+-- Description : Representing 'info' requests.
+-- Copyright   : (c) Sigbjorn Finne, 2008
+-- License     : BSD3
+--
+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>
+-- Stability : provisional
+-- Portability: portable
+--
+-- Representing 'info' requests.
+-- 
+--------------------------------------------------------------------
+module MediaWiki.API.Query.Info where
+
+import MediaWiki.API.Types
+import MediaWiki.API.Utils
+
+data InfoRequest
+ = InfoRequest
+     { inProps  :: [String]
+     , inTokens :: [String]
+     }
+
+instance APIRequest InfoRequest where
+  queryKind _ = QProp "info"
+  showReq r = 
+   [ opt1 "inprop" (inProps r)
+   , opt1 "intoken" (inTokens r)
+   ]
+
+emptyInfoRequest :: InfoRequest
+emptyInfoRequest = InfoRequest
+     { inProps  = []
+     , inTokens = []
+     }
+
+data InfoResponse
+ = InfoResponse
+     { infPages :: [InfoPage]
+     }
+     
+data InfoPage
+ = InfoPage
+     { infPage       :: PageTitle
+     , infTouched    :: TimeString
+     , infLastRevId  :: RevID
+     , infCounter    :: Integer
+     , infLength     :: Integer
+     , infIsRedirect :: Bool
+     , infIsNew      :: Bool
+     , infEditTok    :: Maybe Token
+     , infDeleteTok  :: Maybe Token
+     , infProtectTok :: Maybe Token
+     , infMoveTok    :: Maybe Token
+     , infProtection :: [PageRestriction]
+     }
+
+emptyInfoResponse :: InfoResponse
+emptyInfoResponse =
+   InfoResponse{ infPages= []
+               }
+
+emptyInfoPage :: InfoPage
+emptyInfoPage =
+   InfoPage
+     { infPage       = emptyPageTitle
+     , infTouched    = ""
+     , infLastRevId  = ""
+     , infCounter    = 0
+     , infLength     = 0
+     , infIsRedirect = False
+     , infIsNew      = False
+     , infEditTok    = Nothing
+     , infDeleteTok  = Nothing
+     , infProtectTok = Nothing
+     , infMoveTok    = Nothing
+     , infProtection = []
+     }
+
+data PageRestriction
+ = PageRestriction
+     { prPageId  :: PageID
+     , prSource  :: PageName
+     , prType    :: String
+     , prLevel   :: Integer
+     , prExpiry  :: TimeString
+     , prCascade :: Bool
+     }
+ MediaWiki/API/Query/Info/Import.hs view
@@ -0,0 +1,54 @@+module MediaWiki.API.Query.Info.Import where
+
+import MediaWiki.API.Types
+import MediaWiki.API.Utils
+import MediaWiki.API.Query.Info
+
+import Text.XML.Light.Types
+
+import Control.Monad
+import Data.Maybe
+
+stringXml :: String -> Either (String,[{-Error msg-}String]) InfoResponse
+stringXml s = parseDoc xml s
+
+xml :: Element -> Maybe InfoResponse
+xml e = do
+  guard (elName e == nsName "api")
+  let es1 = children e
+  p  <- pNode "query" es1
+  let es = children p
+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "pages" es)
+  return emptyInfoResponse{infPages=ps}
+
+xmlPage :: Element -> Maybe InfoPage
+xmlPage e = do
+  guard (elName e == nsName "page")
+  let touched = fromMaybe "" $ pAttr "touched" e
+  let rvid    = fromMaybe "0"  $ pAttr "lastrevid" e
+  let cnt     = fromMaybe 0  $ (pAttr "counter" e >>= readMb)
+  let len     = fromMaybe 0  $ (pAttr "length" e  >>= readMb)
+  let ns      = fromMaybe "0" $ pAttr "ns" e
+  let tit     = fromMaybe ""  $ pAttr "title" e
+  let pid     = pAttr "pageid" e
+  let miss    = fromMaybe False  $ fmap (const True) $ pAttr "missing" e
+  let red     = fromMaybe False  $ fmap (const True) $ pAttr "redirect" e
+  let new     = fromMaybe False  $ fmap (const True) $ pAttr "new" e
+  let edTok   = pAttr "edittoken" e
+  let deTok   = pAttr "deletetoken" e
+  let prTok   = pAttr "protecttoken" e
+  let moTok   = pAttr "movetoken" e
+  return emptyInfoPage
+    { infPage = emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid,pgMissing=miss}
+    , infTouched   = touched
+    , infLastRevId = rvid
+    , infCounter   = cnt
+    , infLength    = len
+    , infIsRedirect = red
+    , infIsNew      = new
+    , infEditTok    = edTok
+    , infDeleteTok  = deTok
+    , infProtectTok  = prTok
+    , infMoveTok     = moTok
+    , infProtection  = []
+    }
+ MediaWiki/API/Query/LangLinks.hs view
@@ -0,0 +1,62 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.LangLinks+-- Description : Representing 'langlinks' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'langlinks' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.LangLinks where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data LangLinksRequest+ = LangLinksRequest+     { llLimit        :: Maybe Int+     , llContinueFrom :: Maybe String+     }++instance APIRequest LangLinksRequest where+  queryKind _ = QProp "langlinks"+  showReq r+    = [ mbOpt "lllimit" show (llLimit r)+      , mbOpt "llcontinue" id (llContinueFrom r)+      ]++emptyLangLinksRequest :: LangLinksRequest+emptyLangLinksRequest = LangLinksRequest+  { llLimit        = Nothing+  , llContinueFrom = Nothing+  }+  +data LangLinksResponse+ = LangLinksResponse+     { llPages    :: [(PageTitle,[LangPageInfo])]+     , llContinue :: Maybe String+     }+     +emptyLangLinksResponse :: LangLinksResponse+emptyLangLinksResponse = LangLinksResponse+  { llPages    = []+  , llContinue = Nothing+  }++data LangPageInfo+ = LangPageInfo+     { langName  :: LangName+     , langTitle :: Maybe String+     }+     +emptyLangPageInfo :: LangPageInfo+emptyLangPageInfo = LangPageInfo+ { langName  = "en"+ , langTitle = Nothing+ }+  
+ MediaWiki/API/Query/LangLinks/Import.hs view
@@ -0,0 +1,45 @@+module MediaWiki.API.Query.LangLinks.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.LangLinks++import Text.XML.Light.Types+import Text.XML.Light.Proc   ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) LangLinksResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe LangLinksResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "pages" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "langlinks" "llcontinue"+  return emptyLangLinksResponse+          { llPages = ps+	  , llContinue = cont+	  }++xmlPage :: Element -> Maybe (PageTitle,[LangPageInfo])+xmlPage e = do+  guard (elName e == nsName "page")+  let pid     = fmap read $ pAttr "pageid" e+  let ns      = fromMaybe mainNamespace $ pAttr "ns" e+  let tit     = fromMaybe ""  $ pAttr "title" e+  let es = children e+  ls <- fmap (mapMaybe xmlLangLink) (fmap children $ pNode "langlinks" es)+  let pg = emptyPageTitle{pgNS=ns,pgMbId=pid,pgTitle=tit}+  return (pg, ls)++xmlLangLink :: Element -> Maybe LangPageInfo+xmlLangLink e = do+   guard (elName e == nsName "ll")+   let la     = fromMaybe "en" $  pAttr "lang" e+   let tit    = case strContent e of { "" -> Nothing ; xs -> Just xs}+   return emptyLangPageInfo{langName=la,langTitle=tit}
+ MediaWiki/API/Query/Links.hs view
@@ -0,0 +1,55 @@+--------------------------------------------------------------------
+-- |
+-- Module      : MediaWiki.API.Query.Links
+-- Description : Representing 'links' requests.
+-- Copyright   : (c) Sigbjorn Finne, 2008
+-- License     : BSD3
+--
+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>
+-- Stability : provisional
+-- Portability: portable
+--
+-- Representing 'links' requests.
+-- 
+--------------------------------------------------------------------
+module MediaWiki.API.Query.Links where
+
+import MediaWiki.API.Types
+import MediaWiki.API.Utils
+
+data LinksRequest
+ = LinksRequest
+    { plNamespaces   :: [NamespaceID]
+    , plLimit        :: Maybe Int
+    , plContinueFrom :: Maybe String
+    }
+
+instance APIRequest LinksRequest where
+  queryKind _ = QProp "links"
+  showReq r
+   = [ opt1 "plnamespace" (plNamespaces r)
+     , mbOpt "pllimit" show (plLimit r)
+     , mbOpt "plcontinue" id (plContinueFrom r)
+     ]
+
+
+emptyLinksRequest :: LinksRequest
+emptyLinksRequest 
+ = LinksRequest
+    { plNamespaces   = []
+    , plLimit        = Nothing
+    , plContinueFrom = Nothing
+    }
+
+data LinksResponse
+ = LinksResponse
+    { plPages    :: [(PageTitle,[PageTitle])]
+    , plContinue :: Maybe String
+    }
+
+emptyLinksResponse :: LinksResponse
+emptyLinksResponse = LinksResponse
+    { plPages = []
+    , plContinue = Nothing
+    }
+    
+ MediaWiki/API/Query/Links/Import.hs view
@@ -0,0 +1,45 @@+module MediaWiki.API.Query.Links.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.Links++import Text.XML.Light.Types++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) LinksResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe LinksResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "pages" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "langlinks" "llcontinue"+  return emptyLinksResponse+          { plPages = ps+	  , plContinue = cont+	  }++xmlPage :: Element -> Maybe (PageTitle,[PageTitle])+xmlPage e = do+  guard (elName e == nsName "page")+  let pid     = fmap read $ pAttr "pageid" e+  let ns      = fromMaybe mainNamespace $ pAttr "ns" e+  let tit     = fromMaybe ""  $ pAttr "title" e+  let es = children e+  ls <- fmap (mapMaybe xmlPageLink) (fmap children $ pNode "links" es)+  let pg = emptyPageTitle{pgNS=ns,pgMbId=pid,pgTitle=tit}+  return (pg,ls)++xmlPageLink :: Element -> Maybe PageTitle+xmlPageLink e = do+   guard (elName e == nsName "pl")+   let ns      = fromMaybe mainNamespace $ pAttr "ns" e+   let tit     = fromMaybe ""  $ pAttr "title" e+   let pid     = pAttr "pageid" e+   return emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}
+ MediaWiki/API/Query/LogEvents.hs view
@@ -0,0 +1,114 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.LogEvents+-- Description : Representing 'logevents' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'logevents' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.LogEvents where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data LogEventsRequest+ = LogEventsRequest+    { leProp        :: [String]+    , leType        :: [String]+    , leStart       :: Maybe Timestamp+    , leEnd         :: Maybe Timestamp+    , leDir         :: Maybe TimeArrow+    , leUser        :: Maybe UserID+    , leTitle       :: Maybe PageName+    , leLimit      :: Maybe Int+    }++instance APIRequest LogEventsRequest where+  queryKind _ = QList "logevents"+  showReq r = +    [ opt1 "leprop" (leProp r)+    , opt1 "letype" (leType r)+    , mbOpt "lestart" id (leStart r)+    , mbOpt "leend"   id (leEnd r)+    , mbOpt "ledir" (\ x -> if x==Earlier then "older" else "newer") (leDir r)+    , mbOpt "leuser" id (leUser r)+    , mbOpt "letitle" id (leTitle r)+    , mbOpt "lelimit" show (leLimit r)+    ]++emptyLogEventsRequest :: LogEventsRequest+emptyLogEventsRequest = LogEventsRequest+    { leProp        = []+    , leType        = []+    , leStart       = Nothing+    , leEnd         = Nothing+    , leDir         = Nothing+    , leUser        = Nothing+    , leTitle       = Nothing+    , leLimit       = Nothing+    }++data LogEventsResponse+ = LogEventsResponse+    { leEvents   :: [LogEvent]+    , leContinue :: Maybe String+    }++emptyLogEventsResponse :: LogEventsResponse+emptyLogEventsResponse = LogEventsResponse+    { leEvents   = []+    , leContinue = Nothing+    }+    +data LogEvent+ = LogEvent+    { levLogId     :: Maybe String+    , levPage      :: PageTitle+    , levType      :: Maybe String+    , levAction    :: Maybe String+    , levParams    :: [LogEventParam]+    , levUser      :: Maybe String+    , levTimestamp :: Maybe Timestamp+    , levComment   :: Maybe String+    }+    +emptyLogEvent :: LogEvent+emptyLogEvent + = LogEvent+    { levLogId     = Nothing+    , levPage      = emptyPageTitle+    , levType      = Nothing+    , levAction    = Nothing+    , levParams    = []+    , levUser      = Nothing+    , levTimestamp = Nothing+    , levComment   = Nothing+    }++data LogEventParam+ = LogEventMove+     { levMovePage  :: PageTitle }+ | LogEventPatrol +     { levPatrolCurrent  :: Maybe String+     , levPatrolPrevious :: Maybe String+     , levPatrolAuto     :: Maybe String+     }+ | LogEventRights+     { levRightsOld      :: Maybe String+     , levRightsNew      :: Maybe String+     }+ | LogEventBlock+     { levBlockDuration  :: Maybe String+     , levBlockFlags     :: Maybe String+     }+ | LogEventParam {levParamValue :: String }+ | LogEventOther +    { levParamName    :: String+    , levParamAttrs   :: [(String,String)]+    }
+ MediaWiki/API/Query/LogEvents/Import.hs view
@@ -0,0 +1,81 @@+module MediaWiki.API.Query.LogEvents.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.LogEvents++import Text.XML.Light.Types+import Text.XML.Light.Proc   ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) LogEventsResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe LogEventsResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "logevents" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "logevents" "lestart"+  return emptyLogEventsResponse+          { leEvents = ps+	  , leContinue = cont+	  }++xmlPage :: Element -> Maybe LogEvent+xmlPage e = do+  guard (elName e == nsName "item")+  let pid     = pAttr "pageid" e+  let ns      = fromMaybe mainNamespace $ pAttr "ns" e+  let tit     = fromMaybe ""  $ pAttr "title" e+  let ty      = pAttr "type" e+  let act     = pAttr "action" e+  let usr     = pAttr "user" e+  let ts      = pAttr "timestamp" e+  let co      = pAttr "comment" e+  let lid     = pAttr "logid" e+  let ps = mapMaybe xmlParam (children e)+  let pg = emptyPageTitle{pgNS=ns,pgMbId=pid,pgTitle=tit}+  return emptyLogEvent+              { levLogId = lid+	      , levPage  = pg+	      , levType  = ty+	      , levAction = act+	      , levParams = ps+	      , levUser   = usr+	      , levTimestamp = ts+	      , levComment = co+	      }++xmlParam :: Element -> Maybe LogEventParam+xmlParam e = do+  case qName (elName e) of+    "move" -> do+      let ns  = fromMaybe mainNamespace $ pAttr "new_ns" e+      let tit = fromMaybe "" $ pAttr "new_title" e+      let pid = pAttr "new_pageid" e+      return (LogEventMove emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid})+    "patrol" -> do+      let cur  = pAttr "cur"  e+      let pre  = pAttr "prev" e+      let auto = pAttr "auto" e+      return (LogEventPatrol{levPatrolCurrent=cur,levPatrolPrevious=pre,levPatrolAuto=auto})+    "rights" -> do+      let old  = pAttr "old"  e+      let new  = pAttr "new"  e+      return (LogEventRights{levRightsOld=old,levRightsNew=new})+    "block" -> do+      let dur = pAttr "duration" e+      let fla = pAttr "flags" e+      return (LogEventBlock{levBlockDuration=dur,levBlockFlags=fla})+    "param" -> return (LogEventParam (strContent e))+    tg -> return $+      LogEventOther{ levParamName  = tg+                   , levParamAttrs = map (\a -> (qName $ attrKey a,attrVal a))+		                         (elAttribs e)}+    +
+ MediaWiki/API/Query/Random.hs view
@@ -0,0 +1,47 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.Random+-- Description : Representing 'random' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'random' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.Random where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data RandomPagesRequest+ = RandomPagesRequest+    { rnNamespaces :: [NamespaceID]+    , rnLimit      :: Maybe Int+    }++instance APIRequest RandomPagesRequest where+  queryKind _ = QList "random"+  showReq r = [ opt1  "rnnamespace" (rnNamespaces r)+              , mbOpt "rnlimit" show (rnLimit r)+	      ]++emptyRandomPagesRequest :: RandomPagesRequest+emptyRandomPagesRequest = RandomPagesRequest+    { rnNamespaces = []+    , rnLimit      = Nothing+    }++data RandomPagesResponse+ = RandomPagesResponse+    { rnPages :: [PageTitle]+    }+    +emptyRandomPagesResponse :: RandomPagesResponse+emptyRandomPagesResponse+ = RandomPagesResponse+    { rnPages = []+    }
+ MediaWiki/API/Query/Random/Import.hs view
@@ -0,0 +1,31 @@+module MediaWiki.API.Query.Random.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.Random++import Text.XML.Light.Types+import Text.XML.Light.Proc   ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) RandomPagesResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe RandomPagesResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "random" es)+  return emptyRandomPagesResponse{rnPages=ps}++xmlPage :: Element -> Maybe PageTitle+xmlPage e = do+   guard (elName e == nsName "page")+   let ns     = fromMaybe "0" $ pAttr "ns" e+   let tit    = fromMaybe ""  $ pAttr "title" e+   let pid    = pAttr "pageid" e+   return emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}
+ MediaWiki/API/Query/RecentChanges.hs view
@@ -0,0 +1,110 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.RecentChanges+-- Description : Representing 'recentchanges' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'recentchanges' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.RecentChanges where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data RecentChangesRequest+ = RecentChangesRequest+    { rcStart      :: Maybe Timestamp+    , rcEnd        :: Maybe Timestamp+    , rcDir        :: Maybe TimeArrow+    , rcNamespaces :: [NamespaceID]+    , rcTitles     :: [PageName]+    , rcProp       :: [String]+    , rcShow       :: [String]+    , rcLimit      :: Maybe Int+    , rcType       :: [String]  -- edit,new,log+    }++instance APIRequest RecentChangesRequest where+  queryKind _ = QList "recentchanges"+  showReq r =+    [ mbOpt "rcstart" id (rcStart r)+    , mbOpt "rcend"   id (rcEnd r)+    , mbOpt "rcdir" (\ x -> if x == Earlier then "older" else "newer") (rcDir r)+    , opt1  "rcnamespace" (rcNamespaces r)+    , opt1  "rctitles" (rcTitles r)+    , opt1  "rcprop"   (rcProp r)+    , opt1  "rcshow"   (rcShow r)+    , mbOpt "rclimit" show (rcLimit r)+    , opt1  "rctype" (rcType r)+    ]++emptyRecentChangesRequest :: RecentChangesRequest+emptyRecentChangesRequest = RecentChangesRequest+    { rcStart      = Nothing+    , rcEnd        = Nothing+    , rcDir        = Nothing+    , rcNamespaces = []+    , rcTitles     = []+    , rcProp       = []+    , rcShow       = []+    , rcLimit      = Nothing+    , rcType       = []+    }+++data RecentChangesResponse+ = RecentChangesResponse+    { rchChanges :: [RecentChange]+    , rchContinue :: Maybe String+    }+    +emptyRecentChangesResponse :: RecentChangesResponse+emptyRecentChangesResponse = RecentChangesResponse+    { rchChanges  = []+    , rchContinue = Nothing+    }++data RecentChange+ = RecentChange+    { rchType      :: Maybe String+    , rchPage      :: PageTitle+    , rchPageTo    :: Maybe PageTitle+    , rchRcId      :: Maybe RevID+    , rchRevId     :: Maybe RevID+    , rchRevOldId  :: Maybe RevID+    , rchUser      :: Maybe UserName+    , rchIsAnon    :: Bool+    , rchIsBot     :: Bool+    , rchIsNew     :: Bool+    , rchIsMinor   :: Bool+    , rchLength    :: Maybe Int+    , rchLengthOld :: Maybe Int+    , rchTimestamp :: Maybe String+    , rchComment   :: Maybe String+    }+    +emptyRecentChange :: RecentChange+emptyRecentChange+ = RecentChange+    { rchType      = Nothing+    , rchPage      = emptyPageTitle+    , rchPageTo    = Nothing+    , rchRcId      = Nothing+    , rchRevId     = Nothing+    , rchRevOldId  = Nothing+    , rchUser      = Nothing+    , rchIsAnon    = False+    , rchIsBot     = False+    , rchIsNew     = False+    , rchIsMinor   = False+    , rchLength    = Nothing+    , rchLengthOld = Nothing+    , rchTimestamp = Nothing+    , rchComment   = Nothing+    }
+ MediaWiki/API/Query/RecentChanges/Import.hs view
@@ -0,0 +1,80 @@+module MediaWiki.API.Query.RecentChanges.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.RecentChanges++import Text.XML.Light.Types+import Text.XML.Light.Proc   ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) RecentChangesResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe RecentChangesResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "recentchanges" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "recentchanges" "rcstart"+  return emptyRecentChangesResponse+          { rchChanges  = ps+	  , rchContinue = cont+	  }++xmlPage :: Element -> Maybe RecentChange+xmlPage e = do+  guard (elName e == nsName "rc")+  let ty  = pAttr "type" e+  let ns  = fromMaybe mainNamespace $ pAttr "ns" e+  let tit = fromMaybe "" $ pAttr "title" e+  let pid = pAttr "pageid" e+  let ns_t = pAttr "new_ns" e+  let tit_t = pAttr "new_title" e+  let pid_t = pAttr "new_pageid" e+  let pg_to +       | any isJust [ns_t,tit_t,pid_t] +       = Just+          emptyPageTitle{ pgNS=fromMaybe mainNamespace ns_t+                        , pgTitle=fromMaybe "" tit_t+		        , pgMbId=pid_t+		        }+       | otherwise = Nothing+  let rcid = pAttr "rcid" e+  let revid = pAttr "revid" e+  let revido = pAttr "old_revid" e+  let usr = pAttr "user" e+  let isa = isJust (pAttr "anon" e)+  let isb = isJust (pAttr "bot" e)+  let isn = isJust (pAttr "new" e)+  let ism = isJust (pAttr "minor" e)+  let len = pAttr "newlen" e >>= readMb+  let leno = pAttr "oldlen" e >>= readMb+  let ts  = pAttr "timestamp" e+  let co  = pAttr "comment" e+  return emptyRecentChange+           { rchType = ty+	   , rchPage = emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}+	   , rchPageTo = pg_to+	   , rchRcId   = rcid+	   , rchRevId  = revid+	   , rchRevOldId = revido+	   , rchUser = usr+	   , rchIsAnon = isa+	   , rchIsBot  = isb+	   , rchIsNew  = isn+	   , rchIsMinor = ism+	   , rchLength = len+	   , rchLengthOld = leno+	   , rchTimestamp = ts+	   , rchComment = co+	   }+	   ++  +  +
+ MediaWiki/API/Query/Revisions.hs view
@@ -0,0 +1,110 @@+--------------------------------------------------------------------
+-- |
+-- Module      : MediaWiki.API.Query.Revisions
+-- Description : Representing 'revisions' requests.
+-- Copyright   : (c) Sigbjorn Finne, 2008
+-- License     : BSD3
+--
+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>
+-- Stability : provisional
+-- Portability: portable
+--
+-- Representing 'revisions' requests.
+-- 
+--------------------------------------------------------------------
+module MediaWiki.API.Query.Revisions where
+
+import MediaWiki.API.Types
+import MediaWiki.API.Utils
+
+data RevisionRequest
+ = RevisionRequest
+    { rvProp            :: [String]
+    , rvLimit           :: Maybe Int
+    , rvStartID         :: Maybe RevID
+    , rvEndID           :: Maybe RevID
+    , rvStart           :: Maybe TimeString
+    , rvEnd             :: Maybe TimeString
+    , rvDir             :: Maybe Direction
+    , rvUser            :: Maybe UserName
+    , rvExcludeUser     :: Maybe UserName
+    , rvExpandTemplates :: Maybe Bool
+    , rvSection         :: Maybe String
+    , rvTokens          :: [String]
+    }
+
+instance APIRequest RevisionRequest where
+  queryKind _ = QProp "revisions"
+  showReq r =
+    [ opt1 "rvprop" (rvProp r)
+    , mbOpt "rvlimit" show (rvLimit r)
+    , mbOpt "rvstartid" id (rvStartID r)
+    , mbOpt "rvendid" id (rvEndID r)
+    , mbOpt "rvstart" id (rvStart r)
+    , mbOpt "rvend"   id (rvEnd r)
+    , mbOpt "rvdir" (\ x -> if x == Up then "ascending" else "descending")
+                    (rvDir r)
+    , mbOpt "rvuser" id (rvUser r)
+    , mbOpt "rvexcludeuser" id (rvExcludeUser r)
+    , optB  "rvexpandtemplates" (fromMaybe False (rvExpandTemplates r))
+    , mbOpt "rvsection" id (rvSection r)
+    , opt1  "rvtoken"  (rvTokens r)
+    ]
+
+
+emptyRevisionRequest :: RevisionRequest
+emptyRevisionRequest = RevisionRequest
+    { rvProp            = []
+    , rvLimit           = Nothing
+    , rvStartID         = Nothing
+    , rvEndID           = Nothing
+    , rvStart           = Nothing
+    , rvEnd             = Nothing
+    , rvDir             = Nothing
+    , rvUser            = Nothing
+    , rvExcludeUser     = Nothing
+    , rvExpandTemplates = Nothing
+    , rvTokens          = []
+    , rvSection         = Nothing
+    }
+
+data RevisionsResponse
+ = RevisionsResponse
+    { rvPages    :: [(PageTitle,[Revision])]
+    , rvContinue :: Maybe String
+    }
+    
+emptyRevisionsResponse :: RevisionsResponse
+emptyRevisionsResponse 
+ = RevisionsResponse
+    { rvPages    = []
+    , rvContinue = Nothing
+    }
+
+data Revision
+ = Revision
+    { revPage          :: PageTitle
+    , revRevId         :: RevID
+    , revIsMinor       :: Bool
+    , revUser          :: String
+    , revIsAnon        :: Bool
+    , revTimestamp     :: TimeString
+    , revSize          :: Integer
+    , revComment       :: Maybe String
+--    , revRollbackToken :: Maybe Token
+    , revContent       :: Maybe String
+    }
+
+emptyRevision :: PageTitle -> Revision
+emptyRevision pg
+ = Revision
+    { revPage          = pg
+    , revRevId         = nullRevId
+    , revIsMinor       = False
+    , revUser          = nullUser
+    , revIsAnon        = False
+    , revTimestamp     = nullTimestamp
+    , revSize          = 0
+    , revComment       = Nothing
+    , revContent       = Nothing
+    }
+ MediaWiki/API/Query/Revisions/Import.hs view
@@ -0,0 +1,62 @@+module MediaWiki.API.Query.Revisions.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.Revisions++import Text.XML.Light.Types+import Text.XML.Light.Input ( parseXMLDoc )+import Text.XML.Light.Proc  ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) RevisionsResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe RevisionsResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "pages" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "revisions" "rvstartid"+  return emptyRevisionsResponse+          { rvPages    = ps+	  , rvContinue = cont+	  }++xmlPage :: Element -> Maybe (PageTitle,[Revision])+xmlPage e = do+  guard (elName e == nsName "page")+  let ns      = fromMaybe mainNamespace $ pAttr "ns" e+  let tit     = fromMaybe "" $ pAttr "title" e+  let pid     = pAttr "pageid" e+  let es = children e  +  p  <- pNode "revisions" es+  let pg = emptyPageTitle{pgNS = ns, pgTitle=tit, pgMbId = pid}+  rs <- fmap (mapMaybe (xmlRevision pg)) (fmap children $ pNode "rev" es)+  return (pg, rs)++xmlRevision :: PageTitle -> Element -> Maybe Revision+xmlRevision pg e = do+  guard (elName e == nsName "page")+  let rid  = fromMaybe "" $ pAttr "revid" e+  let min  = isJust (pAttr "minor" e)+  let usr  = fromMaybe "" $ pAttr "user" e+  let anon = isJust (pAttr "anon" e)+  let ts   = fromMaybe "" $ pAttr "timestamp" e+  let size = fromMaybe 0 (pAttr "size" e >>= readMb)+  let com  = pAttr "comment" e+  let con  = case strContent e of { "" -> Nothing ; xs -> Just xs}+  return (emptyRevision pg)+             { revRevId = rid+	     , revIsMinor = min+	     , revUser = usr+	     , revIsAnon = anon+	     , revTimestamp = ts+	     , revSize = size+	     , revComment = com+	     , revContent = con+	     }
+ MediaWiki/API/Query/Search.hs view
@@ -0,0 +1,62 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.Search+-- Description : Representing 'search' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'search' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.Search where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data SearchRequest+ = SearchRequest+    { srSearch     :: String+    , srNamespaces :: [NamespaceID]+    , srWhat       :: Bool -- True => (full)text search, o/w title search.+    , srRedirects  :: Bool+    , srOffset     :: Maybe String+    , srLimit      :: Maybe Int+    }++instance APIRequest SearchRequest where+  queryKind _ = QList "search"+  showReq r+   = [ mbOpt "srsearch" id (Just (srSearch r))+     , opt1  "srnamespace" (srNamespaces r)+     , opt "srwhat" ((\x -> if x then "text" else "title") (srWhat r))+     , optB  "srredirects" (srRedirects r)+     , mbOpt "sroffset" id (srOffset r)+     , mbOpt "srlimit"  show (srLimit r)+     ]++emptySearchRequest :: String -> SearchRequest+emptySearchRequest s = SearchRequest+    { srSearch     = s+    , srNamespaces = []+    , srWhat       = False+    , srRedirects  = False+    , srOffset     = Nothing+    , srLimit      = Nothing+    }+    +data SearchResponse+ = SearchResponse+    { srPages    :: [PageTitle]+    , srContinue :: Maybe String+    }++emptySearchResponse :: SearchResponse+emptySearchResponse = SearchResponse+    { srPages    = []+    , srContinue = Nothing+    }+    
+ MediaWiki/API/Query/Search/Import.hs view
@@ -0,0 +1,32 @@+module MediaWiki.API.Query.Search.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.Search++import Text.XML.Light.Types+import Text.XML.Light.Proc   ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) SearchResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe SearchResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "search" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "search" "sroffset"+  return emptySearchResponse{srPages=ps,srContinue=cont}++xmlPage :: Element -> Maybe PageTitle+xmlPage e = do+   guard (elName e == nsName "p")+   let ns     = fromMaybe "0" $ pAttr "ns" e+   let tit    = fromMaybe ""  $ pAttr "title" e+   let pid    = pAttr "pageid" e+   return emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}
+ MediaWiki/API/Query/SiteInfo.hs view
@@ -0,0 +1,114 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.SiteInfo+-- Description : Representing 'siteinfo' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'siteinfo' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.SiteInfo where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data SiteInfoRequest+ = SiteInfoRequest+    { siProp       :: [String] -- general,namespaces,namespacealiases,+                               -- specialpagealiases,statistics,interwikimap,+			       -- dbrepllag,usergroups+    , siFilterIW   :: Maybe Bool+    , siShowAllDBs :: Bool+    }++instance APIRequest SiteInfoRequest where+  queryKind _ = QMeta "siteinfo"+  showReq r+   = [ opt1 "siprop" (siProp r)+     , mbOpt "sifilteriw" ( \x -> if x then "local" else "!local") (siFilterIW r)+     , optB "sishowalldb" (siShowAllDBs r)+     ]++emptySiteInfoRequest :: SiteInfoRequest+emptySiteInfoRequest = SiteInfoRequest+    { siProp        = []+    , siFilterIW    = Nothing+    , siShowAllDBs  = False+    }+    +data SiteInfoResponse + = SiteInfoResponse+    { siDBReplInfo         :: [DBInfo]+    , siNamespaces         :: [NamespaceInfo]+    , siGeneral            :: Maybe SiteInfo+    , siNamespaceAliases   :: [NamespaceInfo]+    , siSpecialPageAliases :: [(String,[String])]+    , siStatistics         :: Maybe SiteStatistics+    , siInterwiki          :: [InterwikiEntry]+    , siUserGroups         :: [UserGroup]+    }+    +emptySiteInfoResponse :: SiteInfoResponse+emptySiteInfoResponse = SiteInfoResponse+    { siDBReplInfo         = []+    , siNamespaces         = []+    , siGeneral            = Nothing+    , siNamespaceAliases   = []+    , siSpecialPageAliases = []+    , siStatistics         = Nothing+    , siInterwiki          = []+    , siUserGroups         = []+    }++type Permission = String++data UserGroup+ = UserGroup+    { ugName   :: String+    , ugRights :: [Permission]+    }++data SiteInfo+ = SiteInfo+      { siteMainPage   :: PageName+      , siteBase       :: URLString+      , siteName       :: String+      , siteGenerator  :: String+      , siteLastRevision :: Maybe String+      , siteCase       :: Maybe String+      , siteRightsCode :: Maybe String+      , siteRights     :: Maybe String+      , siteLang       :: Maybe String+      , siteFallbackEncoding :: Maybe String+      , siteWriteAPI   :: Bool+      , siteTimezone   :: Maybe String+      , siteTZOffset   :: Maybe Int+      }++data SiteStatistics+ = SiteStatistics+      { siPages    :: Integer+      , siArticles :: Integer+      , siViews    :: Integer+      , siEdits    :: Integer+      , siImages   :: Integer+      , siUsers    :: Integer+      , siAdmins   :: Integer+      , siJobs     :: Integer+      }++++data DBInfo+ = DBInfo+      { dbHost :: String+      , dbLag  :: String+      }+++
+ MediaWiki/API/Query/SiteInfo/Import.hs view
@@ -0,0 +1,143 @@+module MediaWiki.API.Query.SiteInfo.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.SiteInfo++import Text.XML.Light.Types+import Text.XML.Light.Proc   ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) SiteInfoResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe SiteInfoResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  let dbs  = fromMaybe [] $ fmap (mapMaybe xmlDB) (fmap children $ pNode "dblrepllag" es)+  let nss  = fromMaybe [] $ fmap (mapMaybe xmlNS) (fmap children $ pNode "namespaces" es)+  let nass = fromMaybe [] $ fmap (mapMaybe xmlNS) (fmap children $ pNode "namespacealiases" es)+  let gen  = pNode "general" es >>= xmlSI+  let ss   = fromMaybe [] $ fmap (mapMaybe xmlSS) (fmap children $ pNode "specialpagealiases" es)+  let st   =  pNode "statistics" es >>= xmlStat+  let iws  = fromMaybe [] $ fmap (mapMaybe xmlIW) (fmap children $ pNode "interwikimap" es)+  let ugs  = fromMaybe [] $ fmap (mapMaybe xmlGr) (fmap children $ pNode "usergroups" es)+  return +   emptySiteInfoResponse+    { siDBReplInfo         = dbs+    , siNamespaces         = nss+    , siGeneral            = gen+    , siNamespaceAliases   = nass+    , siSpecialPageAliases = ss+    , siStatistics         = st+    , siInterwiki          = iws+    , siUserGroups         = ugs+    }++xmlDB :: Element -> Maybe DBInfo+xmlDB e = do+   guard (elName e == nsName "db")+   let h    = fromMaybe ""  $ pAttr "host" e+   let l    = fromMaybe ""  $ pAttr "lag" e +   return DBInfo{dbHost=h,dbLag=l}++xmlNS :: Element -> Maybe NamespaceInfo+xmlNS e = do+   guard (elName e == nsName "ns")+   let i    = fromMaybe ""  $ pAttr "id" e+   let t    = strContent e+   let sub  = isJust (pAttr "subpages" e)+   return NamespaceInfo{nsId=i,nsTitle=t,nsSubpages=sub}++xmlGr :: Element -> Maybe UserGroup+xmlGr e = do+   guard (elName e == nsName "group")+   let nm   = fromMaybe ""  $ pAttr "name" e+   rs <- fmap (mapMaybe xmlRi) (fmap children $ pNode "rights" (children e))+   return UserGroup{ugName=nm,ugRights=rs}+ where+  xmlRi p = do+   guard (elName p == nsName "permission")+   return (strContent e)++xmlIW :: Element -> Maybe InterwikiEntry+xmlIW e = do+   guard (elName e == nsName "iw")+   let pre  = fromMaybe ""  $ pAttr "prefix" e+   let url  = fromMaybe ""  $ pAttr "url" e+   let la   = pAttr "lang" e+   let loc  = isJust (pAttr "local" e)+   let tra  = (pAttr "trans" e >>= \x -> readMb x >>= \ y -> return (y /= (0::Int)))+   return InterwikiEntry{iwPrefix=pre,iwLocal=loc,iwTranscludable=tra,iwUrl=url,iwLanguage=la}++xmlSS :: Element -> Maybe (String,[String])+xmlSS e = do+   guard (elName e == nsName "specialpage")+   let es1 = children e+   nss <- fmap (mapMaybe xmlAS) (fmap children $ pNode "aliases" es1)+   let nm   = fromMaybe ""  $ pAttr "realname" e+   return (nm,nss)+ where+  xmlAS p = do+   guard (elName p == nsName "alias")+   return (strContent e)++xmlSI :: Element -> Maybe SiteInfo+xmlSI e = do+   guard (elName e == nsName "general")+   let ma   = fromMaybe ""  $ pAttr "mainpage" e+   let ba   = fromMaybe ""  $ pAttr "base" e+   let nm   = fromMaybe ""  $ pAttr "sitename" e+   let ge   = fromMaybe ""  $ pAttr "generator" e+   let re   = pAttr "revid" e+   let ca   = pAttr "case" e+   let ri   = pAttr "rights" e+   let ric  = pAttr "rightscode" e+   let la   = pAttr "lang" e+   let enc  = pAttr "fallback8bitEncoding" e+   let wr   = isJust (pAttr "writeapi" e)+   let tz   = pAttr "timezone" e+   let tzo  = pAttr "timeoffset" e >>= readMb+   return SiteInfo+      { siteMainPage = ma+      , siteBase     = ba+      , siteName     = nm+      , siteGenerator  = ge+      , siteLastRevision = re+      , siteCase       = ca+      , siteRightsCode = ric+      , siteRights     = ri+      , siteLang       = la+      , siteFallbackEncoding = enc+      , siteWriteAPI   = wr+      , siteTimezone   = tz+      , siteTZOffset   = tzo+      }+      +xmlStat :: Element -> Maybe SiteStatistics+xmlStat e = do+   guard (elName e == nsName "statistics")+   let pgs  = fromMaybe 0  $ pAttr "pages" e >>= readMb+   let arts = fromMaybe 0  $ pAttr "articles" e >>= readMb+   let views = fromMaybe 0  $ pAttr "views" e >>= readMb+   let edits = fromMaybe 0  $ pAttr "edits" e >>= readMb+   let users = fromMaybe 0  $ pAttr "users" e >>= readMb+   let admins = fromMaybe 0  $ pAttr "admins" e >>= readMb+   let jobs = fromMaybe 0  $ pAttr "jobs" e >>= readMb+   let images = fromMaybe 0  $ pAttr "images" e >>= readMb+   return +    SiteStatistics+      { siPages    = pgs+      , siArticles = arts+      , siViews    = views+      , siEdits    = edits+      , siImages   = images+      , siUsers    = users+      , siAdmins   = admins+      , siJobs     = jobs+      }
+ MediaWiki/API/Query/Templates.hs view
@@ -0,0 +1,55 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.Templates+-- Description : Representing 'templates' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'templates' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.Templates where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data TemplatesRequest+ = TemplatesRequest+    { tlNamespaces   :: [NamespaceID]+    , tlLimit        :: Maybe Int+    , tlContinueFrom :: Maybe String+    }++instance APIRequest TemplatesRequest where+  queryKind _ = QProp "templates"+  showReq r+   = [ opt1 "tlnamespace" (tlNamespaces r)+     , mbOpt "tllimit" show (tlLimit r)+     , mbOpt "tlcontinue" id (tlContinueFrom r)+     ]++emptyTemplatesRequest :: TemplatesRequest+emptyTemplatesRequest = TemplatesRequest+    { tlNamespaces = []+    , tlLimit      = Nothing+    , tlContinueFrom = Nothing+    }+    +data TemplatesResponse + = TemplatesResponse+    { tlPages :: [(PageTitle,[PageTitle])]+    , tlContinue :: Maybe String+    }+    +emptyTemplatesResponse :: TemplatesResponse+emptyTemplatesResponse = TemplatesResponse+    { tlPages = []+    , tlContinue = Nothing+    }+    ++
+ MediaWiki/API/Query/Templates/Import.hs view
@@ -0,0 +1,40 @@+module MediaWiki.API.Query.Templates.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.Templates++import Text.XML.Light.Types+import Text.XML.Light.Proc   ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) TemplatesResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe TemplatesResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "pages" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "templates" "tlcontinue"+  return emptyTemplatesResponse{tlPages=ps,tlContinue=cont}++xmlPage :: Element -> Maybe (PageTitle, [PageTitle])+xmlPage e = do+   guard (elName e == nsName "page")+   let ns     = fromMaybe "0" $ pAttr "ns" e+   let tit    = fromMaybe ""  $ pAttr "title" e+   let pid    = pAttr "pageid" e+   ps <- fmap (mapMaybe xmlT) (fmap children $ pNode "templates" (children e))+   return (emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}, ps)+ where+  xmlT p = do+    guard (elName p == nsName "tl")+    let ns     = fromMaybe "0" $ pAttr "ns" p+    let tit    = fromMaybe ""  $ pAttr "title" p+    let pid    = pAttr "pageid" p+    return emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}
+ MediaWiki/API/Query/UserContribs.hs view
@@ -0,0 +1,100 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.UserContribs+-- Description : Representing 'usercontribs' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'usercontribs' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.UserContribs where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data UserContribsRequest + = UserContribsRequest+    { ucLimit      :: Maybe Int+    , ucStart      :: Maybe Timestamp+    , ucEnd        :: Maybe Timestamp+    , ucUser       :: Maybe UserID+    , ucUserPrefix :: Maybe String+    , ucDir        :: Maybe TimeArrow+    , ucNamespaces :: [NamespaceID]+    , ucProp       :: [String]+    , ucShow       :: [String]+    }++instance APIRequest UserContribsRequest where+  queryKind _ = QList "usercontribs"+  showReq r+   = [ mbOpt "uclimit" show (ucLimit r)+     , mbOpt "ucstart" id   (ucStart r)+     , mbOpt "ucend"   id   (ucEnd r)+     , mbOpt "ucuser"  id   (ucUser r)+     , mbOpt "ucuserprefix" id (ucUserPrefix r)+     , mbOpt "ucdir" (\ x -> if x == Earlier then "older" else "newer") (ucDir r)+     , opt1  "ucnamespace" (ucNamespaces r)+     , opt1  "ucprop" (ucProp r)+     , opt1  "ucshow" (ucShow r)+     ]+++emptyUserContribsRequest :: UserContribsRequest+emptyUserContribsRequest = UserContribsRequest+    { ucLimit      = Nothing+    , ucStart      = Nothing+    , ucEnd        = Nothing+    , ucUser       = Nothing+    , ucUserPrefix = Nothing+    , ucDir        = Nothing+    , ucNamespaces = []+    , ucProp       = []+    , ucShow       = []+    }++data UserContribsResponse+ = UserContribsResponse+    { ucPages    :: [UserContrib]+    , ucContinue :: Maybe String+    }++emptyUserContribsResponse :: UserContribsResponse+emptyUserContribsResponse = UserContribsResponse+    { ucPages    = []+    , ucContinue = Nothing+    }++data UserContrib+ = UserContrib+    { ucoUser      :: UserName+    , ucoPage      :: PageTitle+    , ucoRevId     :: RevID+    , ucoTimestamp :: Maybe Timestamp+    , ucoIsNew     :: Bool+    , ucoIsMinor   :: Bool+    , ucoIsTop     :: Bool+    , ucoComment   :: Maybe String+    }+    +emptyUserContrib :: UserContrib+emptyUserContrib  = UserContrib+    { ucoUser  = ""+    , ucoPage  = emptyPageTitle+    , ucoRevId = "0"+    , ucoTimestamp = Nothing+    , ucoIsNew     = False+    , ucoIsMinor   = False+    , ucoIsTop     = False+    , ucoComment   = Nothing+    }+    ++++    
+ MediaWiki/API/Query/UserContribs/Import.hs view
@@ -0,0 +1,48 @@+module MediaWiki.API.Query.UserContribs.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.UserContribs++import Text.XML.Light.Types++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) UserContribsResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe UserContribsResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "usercontribs" es)+  let cont = pNode "query-continue" es1 >>= xmlContinue "usercontribs" "ucstart"+  return emptyUserContribsResponse{ucPages=ps,ucContinue=cont}++xmlPage :: Element -> Maybe UserContrib+xmlPage e = do+   guard (elName e == nsName "item")+   let ns     = fromMaybe "0" $ pAttr "ns" e+   let tit    = fromMaybe ""  $ pAttr "title" e+   let pid    = pAttr "pageid" e+   let usr    = fromMaybe ""  $ pAttr "user" e+   let revid  = fromMaybe "0"  $ pAttr "revid" e+   let ts     = pAttr "timestamp" e+   let isn    = isJust (pAttr "new" e)+   let ism    = isJust (pAttr "minor" e)+   let ist    = isJust (pAttr "top" e)+   let co     = pAttr "comment" e+   return emptyUserContrib+     { ucoUser  = usr+     , ucoPage  = emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}+     , ucoRevId = revid+     , ucoTimestamp = ts+     , ucoIsNew     = isn+     , ucoIsMinor   = ism+     , ucoIsTop     = ist+     , ucoComment   = co+     }+
+ MediaWiki/API/Query/UserInfo.hs view
@@ -0,0 +1,46 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.UserInfo+-- Description : Representing 'userinfo' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'userinfo' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.UserInfo where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data UserInfoRequest+ = UserInfoRequest+    { uiProp       :: [String] +       -- one of (1.13): +       --      blockinfo, hasmsg, groups, rights, options, editcount, ratelimits+    }++instance APIRequest UserInfoRequest where+  queryKind _ = QMeta "userinfo"+  showReq r+   = [ opt1 "uiprop" (uiProp r)+     ]++emptyUserInfoRequest :: UserInfoRequest+emptyUserInfoRequest = UserInfoRequest+    { uiProp       = []+    }++data UserInfoResponse+ = UserInfoResponse+    { uiUser :: UserInfo+    }++emptyUserInfoResponse :: UserInfoResponse+emptyUserInfoResponse = UserInfoResponse+    { uiUser = emptyUserInfo+    }
+ MediaWiki/API/Query/UserInfo/Import.hs view
@@ -0,0 +1,91 @@+module MediaWiki.API.Query.UserInfo.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.UserInfo++import Text.XML.Light.Types+import Text.XML.Light.Proc   ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) UserInfoResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe UserInfoResponse+xml e = do+  guard (elName e == nsName "api")+  p0  <- pNode "query" (children e)+  p   <- pNode "userinfo" (children p0)+  let es = children p+  let grps = mapMaybe xmlGroup es+  let rs = mapMaybe xmlRights es+  let os = mapMaybe xmlOption es+  let rs1 = mapMaybe xmlRateLimit es+  let ec  = pAttr "editcount" p >>= readMb+  let nm  = fromMaybe nullUser $ pAttr "name" p+  let uid = fromMaybe "0" $ pAttr "id" p >>= readMb+  let isa = isJust (pAttr "anon" p)+  let hasm = isJust (pAttr "mesages" p)+  let bi   = xmlBlockInfo p+  let u = emptyUserInfo+            { uiName = nm+	    , uiId   = uid+	    , uiIsAnon = isa+	    , uiHasMessage = hasm+	    , uiBlocked = bi+	    , uiGroups = concat grps+	    , uiRights = concat rs+	    , uiOptions = concat os+	    , uiRateLimits = concat rs1+	    , uiEditCount = ec+	    }+  return emptyUserInfoResponse{uiUser=u}++xmlBlockInfo :: Element -> Maybe (String,String)+xmlBlockInfo e = do+  b <- pAttr "blockedby" e+  c <- pAttr "blockreason" e+  return (b,c)++xmlGroup :: Element -> Maybe [String]+xmlGroup e = do+   guard (elName e == nsName "groups")+   let es = children e+   let gs = mapMaybe xmlG es+   return gs+ where+  xmlG g = do+   guard (elName e == nsName "g")+   return (strContent g)++xmlRights :: Element -> Maybe [String]+xmlRights e = do+   guard (elName e == nsName "rights")+   let es = children e+   let gs = mapMaybe xmlR es+   return gs+  where+   xmlR g = do+    guard (elName e == nsName "r")+    return (strContent g)++xmlRateLimit :: Element -> Maybe [RateLimit]+xmlRateLimit e = do+   guard (elName e == nsName "ratelimits")+   let es = children e+   let gs = mapMaybe xmlR es+   return gs+ where+  xmlR g = do+   let es = children g+   p <- pNode "ip" es+   let hi = fromMaybe 0 $ pAttr "hits" p >>= readMb+   let se = fromMaybe 0 $ pAttr "seconds" p >>= readMb+   return RateLimit{rlName=qName (elName e),rlHits=hi,rlSeconds=se}++xmlOption :: Element -> Maybe [(String,String)]+xmlOption e = do+   guard (elName e == nsName "options")+   return (map (\a -> (qName (attrKey a), attrVal a)) (elAttribs e))
+ MediaWiki/API/Query/Users.hs view
@@ -0,0 +1,66 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.Users+-- Description : Representing 'users' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'users' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.Users where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data UsersRequest+ = UsersRequest+    { usProp       :: [String]+    , usUsers      :: [UserID]+    }++instance APIRequest UsersRequest where+  queryKind _ = QList "users"+  showReq r = [ opt1 "usprop"  (usProp r)+              , opt1 "ususers" (usUsers r)+	      ]++emptyUsersRequest :: UsersRequest+emptyUsersRequest = UsersRequest+    { usProp       = []+    , usUsers      = []+    }++data UsersResponse+ = UsersResponse+    { usrUsers    :: [UsersInfo]+    }+    +emptyUsersResponse :: UsersResponse+emptyUsersResponse+ = UsersResponse+    { usrUsers    = []+    }++data UsersInfo+ = UsersInfo+    { usName :: Maybe UserName+    , usEditCount :: Maybe Int+    , usRegDate :: Maybe Timestamp+    , usGroups :: [String]+    , usBlock  :: Maybe (UserName,String)+    }+    +emptyUsersInfo :: UsersInfo+emptyUsersInfo = UsersInfo+    { usName = Nothing+    , usEditCount = Nothing+    , usRegDate = Nothing+    , usGroups = []+    , usBlock  = Nothing+    }+  
+ MediaWiki/API/Query/Users/Import.hs view
@@ -0,0 +1,47 @@+module MediaWiki.API.Query.Users.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.Users++import Text.XML.Light.Types+import Text.XML.Light.Proc   ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) UsersResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe UsersResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  ps <- fmap (mapMaybe xmlPage) (fmap children $ pNode "users" es)+  return emptyUsersResponse{usrUsers=ps}++xmlPage :: Element -> Maybe UsersInfo+xmlPage e = do+   guard (elName e == nsName "user")+   let nm     = pAttr "name" e+   let ec     = pAttr "editcount" e >>= readMb+   let re     = pAttr "registration" e+   let bl1    = pAttr "blockedby" e+   let bl2    = pAttr "blockreason" e+   let bl     = case (bl1,bl2) of { (Just a, Just b) -> Just (a,b) ; _ -> Nothing}+   let gs = fromMaybe [] $ fmap (mapMaybe xmlG) (fmap children $ pNode "groups" (children e))+   return emptyUsersInfo+            { usName = nm+	    , usEditCount = ec+	    , usRegDate = re+	    , usBlock = bl+	    , usGroups = gs+	    }+  where+   xmlG p = do+     guard (elName p == nsName "g")+     return (strContent p)+	    +
+ MediaWiki/API/Query/WatchList.hs view
@@ -0,0 +1,100 @@+--------------------------------------------------------------------+-- |+-- Module      : MediaWiki.API.Query.WatchList+-- Description : Representing 'watchlist' requests.+-- Copyright   : (c) Sigbjorn Finne, 2008+-- License     : BSD3+--+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>+-- Stability : provisional+-- Portability: portable+--+-- Representing 'watchlist' requests.+-- +--------------------------------------------------------------------+module MediaWiki.API.Query.WatchList where++import MediaWiki.API.Types+import MediaWiki.API.Utils++data WatchListRequest+ = WatchListRequest+    { wlAllRev     :: Bool+    , wlStart      :: Maybe Timestamp+    , wlEnd        :: Maybe Timestamp+    , wlNamespaces :: [NamespaceID]+    , wlDir        :: Maybe TimeArrow+    , wlLimit      :: Maybe Int+    , wlProp       :: [String]+    , wlShow       :: [String]+    }++instance APIRequest WatchListRequest where+  queryKind _ = QList "watchlist"+  showReq r+   = [ optB "wlallrev" (wlAllRev r)+     , mbOpt "wlstart" id (wlStart r)+     , mbOpt "wlend" id   (wlEnd r)+     , opt1  "wlnamespace" (wlNamespaces r)+     , mbOpt "wldir" (\ x -> if x==Earlier then "older" else "newer")+                     (wlDir r)+     , mbOpt "wllimit" show (wlLimit r)+     , opt1  "wlprop"  (wlProp r)+     , opt1  "wlshow"  (wlShow r)+     ]++emptyWatchListRequest :: WatchListRequest+emptyWatchListRequest = WatchListRequest+    { wlAllRev     = False+    , wlStart      = Nothing+    , wlEnd        = Nothing+    , wlNamespaces = []+    , wlDir        = Nothing+    , wlLimit      = Nothing+    , wlProp       = []+    , wlShow       = []+    }++data WatchListResponse + = WatchListResponse+    { wlWatch    :: WatchList+    , wlContinue :: Maybe String+    }++emptyWatchListResponse :: WatchListResponse+emptyWatchListResponse = WatchListResponse+   { wlWatch = emptyWatchList+   , wlContinue = Nothing+   }++data WatchList+ = WatchList+    { wlPage   :: PageTitle+    , wlRevId  :: Maybe RevID+    , wlUser   :: Maybe UserName+    , wlIsAnon :: Bool+    , wlIsNew  :: Bool+    , wlIsMinor :: Bool+    , wlIsPatrolled :: Bool+    , wlTimestamp :: Maybe Timestamp+    , wlLength  :: Maybe Int+    , wlOldLength :: Maybe Int+    , wlComment :: Maybe String+    }+    +emptyWatchList :: WatchList+emptyWatchList+ = WatchList+    { wlPage   = emptyPageTitle+    , wlRevId  = Nothing+    , wlUser   = Nothing+    , wlIsAnon = False+    , wlIsNew  = False+    , wlIsMinor = False+    , wlIsPatrolled = False+    , wlTimestamp = Nothing+    , wlLength    = Nothing+    , wlOldLength = Nothing+    , wlComment   = Nothing+    }+    
+ MediaWiki/API/Query/WatchList/Import.hs view
@@ -0,0 +1,56 @@+module MediaWiki.API.Query.WatchList.Import where++import MediaWiki.API.Types+import MediaWiki.API.Utils+import MediaWiki.API.Query.WatchList++import Text.XML.Light.Types+import Text.XML.Light.Proc   ( strContent )++import Control.Monad+import Data.Maybe++stringXml :: String -> Either (String,[{-Error msg-}String]) WatchListResponse+stringXml s = parseDoc xml s++xml :: Element -> Maybe WatchListResponse+xml e = do+  guard (elName e == nsName "api")+  let es1 = children e+  p  <- pNode "query" es1+  let es = children p+  wl <- pNode "watchlist" es >>= xmlWatchList+  let cont = pNode "query-continue" es1 >>= xmlContinue "watchlist" "wlstart"+  return emptyWatchListResponse{wlWatch=wl,wlContinue=cont}++xmlWatchList :: Element -> Maybe WatchList+xmlWatchList e = do+   guard (elName e == nsName "watchlist")+   let ns     = fromMaybe "0" $ pAttr "ns" e+   let tit    = fromMaybe ""  $ pAttr "title" e+   let pid    = pAttr "pageid" e+   let rid    = pAttr "revid" e+   let usr    = pAttr "user" e+   let isa    = isJust (pAttr "anon" e)+   let isn    = isJust (pAttr "new" e)+   let ism    = isJust (pAttr "minor" e)+   let isp    = isJust (pAttr "patrolled" e)+   let ts     = pAttr "timestamp" e+   let len    = pAttr "newlen" e >>= readMb+   let leno   = pAttr "oldlen" e >>= readMb+   let co     = pAttr "comment" e+   let pg = emptyPageTitle{pgNS=ns,pgTitle=tit,pgMbId=pid}+   return emptyWatchList+    { wlPage   = pg+    , wlRevId  = rid+    , wlUser   = usr+    , wlIsAnon = isa+    , wlIsNew  = isn+    , wlIsMinor = ism+    , wlIsPatrolled = isp+    , wlTimestamp = ts+    , wlLength  = len+    , wlOldLength = leno+    , wlComment = co+    }+   
+ MediaWiki/API/Types.hs view
@@ -0,0 +1,241 @@+--------------------------------------------------------------------
+-- |
+-- Module      : MediaWiki.API.Types
+-- Description : Basic MediaWiki API types
+-- Copyright   : (c) Sigbjorn Finne, 2008
+-- License     : BSD3
+--
+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>
+-- Stability : provisional
+-- Portability: portable
+--
+-- Basic MediaWiki API types
+-- 
+--------------------------------------------------------------------
+module MediaWiki.API.Types where
+
+-- base types
+type UserName = String
+type NamespaceID = String
+type TimeString = String
+data Direction = Up | Down deriving ( Eq )
+type RevID = String
+type PageName = String
+type UserID = String
+data TimeArrow = Earlier | Later deriving ( Eq )
+type Timestamp = String
+type Redirect = String
+type SortKind = String
+type CatName = String
+type GroupName = String
+type FilterLang = String
+type WithRedirects = String
+type URLString = String
+type Token = String
+type LangName = String
+
+nullRevId :: RevID
+nullRevId = "0"
+
+nullTimestamp :: Timestamp
+nullTimestamp = ""
+
+nullUser :: UserName
+nullUser = ""
+
+data PageTitle 
+ = PageTitle { pgNS    :: NamespaceID
+             , pgTitle :: Title 
+	     , pgMbId  :: Maybe PageID
+	     , pgMissing :: Bool
+	     }
+
+emptyPageTitle :: PageTitle
+emptyPageTitle
+ = PageTitle { pgNS    = mainNamespace
+             , pgTitle = ""
+	     , pgMbId  = Nothing
+	     , pgMissing = False
+	     }
+
+mainNamespace :: NamespaceID
+mainNamespace  = "0"
+
+ns_MAIN :: NamespaceID
+ns_MAIN = mainNamespace
+
+ns_IMAGE :: NamespaceID
+ns_IMAGE = "6"
+
+data Format
+ = Format 
+     { formatKind      :: FormatKind
+     , formatFormatted :: Bool
+     }
+
+emptyFormat :: Format
+emptyFormat = Format{formatKind=FormatXML, formatFormatted=True}
+
+xmlFormat :: Format
+xmlFormat = emptyFormat{formatKind=FormatXML, formatFormatted=False}
+
+data FormatKind
+ = FormatJSON
+ | FormatPHP 
+ | FormatWDDX
+ | FormatXML
+ | FormatYAML
+ | FormatTxt
+ | FormatDbg
+
+type User     = String
+type Password = String
+type LoginToken = String
+type SessionID = String
+type SessionToken = String
+type ValueName = (String,String)
+
+data UserInfo
+ = UserInfo
+    { uiName      :: UserName
+    , uiId        :: UserID
+    , uiIsAnon    :: Bool
+    , uiHasMessage :: Bool
+    , uiBlocked   :: Maybe (UserName,String)
+    , uiGroups    :: [String]
+    , uiRights    :: [String]
+    , uiOptions   :: [(String,String)]
+    , uiRateLimits :: [RateLimit]
+    , uiEditCount  :: Maybe Int
+    }
+
+emptyUserInfo :: UserInfo
+emptyUserInfo = UserInfo
+    { uiName      = nullUser
+    , uiId        = "0"
+    , uiIsAnon    = True
+    , uiHasMessage = False
+    , uiBlocked   = Nothing
+    , uiGroups    = []
+    , uiRights    = []
+    , uiOptions   = []
+    , uiRateLimits = []
+    , uiEditCount  = Nothing
+    }
+
+data RateLimit
+ = RateLimit
+    { rlName    :: String
+    , rlHits    :: Int
+    , rlSeconds :: Int
+    }
+
+
+data NamespaceInfo
+ = NamespaceInfo
+      { nsId       :: String
+      , nsTitle    :: String
+      , nsSubpages :: Bool
+      }
+
+data InterwikiEntry
+ = InterwikiEntry
+      { iwPrefix        :: String
+      , iwLocal         :: Bool
+      , iwTranscludable :: Maybe Bool
+      , iwUrl           :: String
+      , iwLanguage      :: Maybe String
+      }
+
+data UserSession
+ = UserSession
+    { sessUserId    :: UserID
+    , sessUserName  :: UserName
+    , sessPassword  :: Maybe Password  -- not sure; could leave out.
+    , sessCookiePrefix :: Maybe String
+    , sessSessionId :: Maybe SessionID
+    , sessToken     :: LoginToken
+    }
+
+data HelpRequest
+ = HelpRequest
+    { helpVersion :: Maybe Bool
+    }
+
+type Title  = String   -- Q: what kind of encoding/escaping can be assumed here?
+type PageID = String   -- numeric ID, so arguably wrong Haskell type.
+type RevisionID = String -- ditto.
+
+newtype PropKind 
+ = PropKind { prKind :: String }
+    {- Not deemed worthy to try to enumerate them all.
+    -- Three major reasons: 
+    --    - supportd properties are likely to evolve with MW API.
+    --    - fields support subsets of the type, so using a union type
+    --      for these is imprecise.
+    --    - development of queries are driven by reading the API documentation
+    --      from the MW API help page, so transliterations ought to be
+    --      accommodated.
+    --    - being too lazy to write them out is not a reason; did
+    --      have such an enum type defined at one point :-)
+    -}
+
+newtype MetaKind
+ = MetaKind { meKind :: String } -- likely values: siteinfo, userinfo, allmessages
+
+newtype ListKind
+ = ListKind { liKind :: String }
+
+newtype GeneratorKind
+ = GeneratorKind { genKind :: String }
+
+class APIRequest a where
+  showReq    :: a -> [Maybe (String,String)]
+  isPostable :: a -> Bool
+  isPostable _ = False
+  
+  queryKind :: a -> QueryKind
+  queryKind _ = QProp ""
+
+
+data QueryKind 
+ = QProp String | QMeta String | QList String | QGen String
+   deriving ( Eq )
+
+data QueryRequest
+ = QueryRequest
+     { quTitles          :: [Title]
+     , quPageIds         :: [PageID]
+     , quRevIds          :: [RevisionID]
+     , quProps           :: [PropKind]
+     , quLists           :: [ListKind]
+     , quMetas           :: [MetaKind]
+     , quGenerator       :: Maybe GeneratorKind
+     , quFollowRedirects :: Maybe Bool
+     , quIndexPageIds    :: Maybe Bool
+     }
+
+emptyQuery :: QueryRequest
+emptyQuery = QueryRequest
+     { quTitles          = []
+     , quPageIds         = []
+     , quRevIds          = []
+     , quProps           = []
+     , quLists           = []
+     , quMetas           = []
+     , quGenerator       = Nothing
+     , quFollowRedirects = Nothing
+     , quIndexPageIds    = Nothing
+     }
+{-
+data MetaKindProp
+ = SiteInfoProp
+ | UserInfoProp
+ | AllMessagesProp
+ | ExpandTemplatesProp
+ | ParseProp
+ | OpenSearchProp
+ | FeedWatchlistProp
+ | HelpProp
+ | ParamInfoProp
+ -}
+ MediaWiki/API/Utils.hs view
@@ -0,0 +1,94 @@+--------------------------------------------------------------------
+-- |
+-- Module      : MediaWiki.API.Utils
+-- Description : MediaWiki API internal utility functions.
+-- Copyright   : (c) Sigbjorn Finne, 2008
+-- License     : BSD3
+--
+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>
+-- Stability : provisional
+-- Portability: portable
+--
+-- MediaWiki API internal utility functions.
+-- 
+--------------------------------------------------------------------
+module MediaWiki.API.Utils 
+       ( module MediaWiki.API.Utils
+       , fromMaybe
+       ) where
+
+import Text.XML.Light as XML
+import Data.Maybe
+import Data.List
+import Control.Monad
+
+import MediaWiki.Util.Codec.URLEncoder ( encodeString )
+
+pNodes       :: String -> [XML.Element] -> [XML.Element]
+pNodes x es   = filter ((nsName x ==) . elName) es
+
+pNode        :: String -> [XML.Element] -> Maybe XML.Element
+pNode x es    = listToMaybe (pNodes x es)
+
+pLeaf        :: String -> [XML.Element] -> Maybe String
+pLeaf x es    = strContent `fmap` pNode x es
+
+pAttr        :: String -> XML.Element -> Maybe String
+pAttr x e     = lookup (nsName x) [ (k,v) | Attr k v <- elAttribs e ]
+
+pMany        :: String -> (XML.Element -> Maybe a) -> [XML.Element] -> [a]
+pMany p f es  = mapMaybe f (pNodes p es)
+
+children     :: XML.Element -> [XML.Element]
+children e    = onlyElems (elContent e)
+
+nsName :: String -> QName
+nsName x = QName{qName=x,qURI=Nothing,qPrefix=Nothing}
+
+without :: [String] -> [XML.Attr] -> [XML.Attr]
+without xs as = filter (\ a -> not (attrKey a `elem` qxs)) as
+ where
+  qxs = map nsName xs
+
+parseDoc :: (Element -> Maybe a) -> String -> Either (String,[{-error msg-}String]) a
+parseDoc f s = 
+  case parseXMLDoc s of
+    Nothing -> Left (s, ["not valid XML content"])
+    Just d  ->
+      case f d of
+        Nothing -> Left (s,["unexpected XML response"])
+	Just x  -> Right x
+
+xmlContinue :: String -> String -> Element -> Maybe String
+xmlContinue tgName atName e = do
+  guard (elName e == nsName "query-continue")
+  let es1 = children e
+  p  <- pNode tgName es1
+  pAttr atName p
+
+mbDef :: a -> Maybe a -> Maybe a
+mbDef x Nothing = Just x
+mbDef _ v = v
+
+readMb :: Read a => String -> Maybe a
+readMb x = case reads x of
+             ((v,_):_) -> Just v
+	     _ -> Nothing
+
+piped :: [String] -> String
+piped xs = intercalate "|" xs
+
+opt :: String -> String -> Maybe (String,String)
+opt a b = Just (a, encodeString b)
+
+optB :: String -> Bool -> Maybe (String,String)
+optB _ False = Nothing
+optB a _ = Just (a,"")
+
+opt1 :: String -> [String] -> Maybe (String,String)
+opt1 _ [] = Nothing
+opt1 a b = Just (a,encodeString $ piped b)
+
+mbOpt :: String -> (a -> String) -> Maybe a -> Maybe (String,String)
+mbOpt  _ _ Nothing = Nothing
+mbOpt tg f (Just x) = Just (tg,encodeString $ f x)
+ MediaWiki/Util/Codec/Percent.hs view
@@ -0,0 +1,59 @@+{- |+ +  Module      :  MediaWiki.Util.Codec.Percent+  Copyright   :  (c) 2008++  Maintainer  : sof@forkIO.com++  License     : See the file LICENSE++  Status      : Coded+  Stability   : provisional+  portability : portable++  Codec for de/encoding URI strings via percent encodings+ (cf. RFC 3986.)+-}+module MediaWiki.Util.Codec.Percent where++import Data.Char ( chr, isAlphaNum )+import Numeric   ( readHex, showHex )++getEncodedString :: String -> String+getEncodedString "" = ""+getEncodedString (x:xs) = +  case getEncodedChar x of+    Nothing -> x : getEncodedString xs+    Just ss -> ss ++ getEncodedString xs++getDecodedString :: String -> String+getDecodedString "" = ""+getDecodedString ls@(x:xs) = +  case getDecodedChar ls of+    Nothing -> x : getDecodedString xs+    Just (ch,xs1) -> ch : getDecodedString xs1++getEncodedChar :: Char -> Maybe String+getEncodedChar x+ | isAlphaNum x || +   x `elem` "-_.~" = Nothing+ | xi < 0xff       = Just ('%':showHex (xi `div` 16) (showHex (xi `mod` 16) ""))+ | otherwise       = -- ToDo: import utf8 lib+   error "getEncodedChar: can only handle 8-bit chars right now."+ where+  xi :: Int+  xi = fromEnum x++getDecodedChar :: String -> Maybe (Char, String)+getDecodedChar str =+ case str of+   ""          -> Nothing+   (x:xs) +    | x /= '%'  -> Nothing+    | otherwise -> do+       case xs of+         (b1:b2:bs) -> +	    case readHex [b1,b2] of+	      ((v,_):_) -> Just (Data.Char.chr v, bs)+	      _ -> Nothing+	 _ -> Nothing
+ MediaWiki/Util/Codec/URLEncoder.hs view
@@ -0,0 +1,33 @@+{-+ Codec for de/encoding form data shipped in URL query strings+ or in POST request bodies. (application/x-www-form-urlencoded)+ (cf. RFC 3986.)+-}+module MediaWiki.Util.Codec.URLEncoder +       ( encodeString+       , decodeString+       ) where++import qualified Codec.Binary.UTF8.String as UTF8 ( encodeString )+import MediaWiki.Util.Codec.Percent ( getEncodedChar, getDecodedChar )++encodeString :: String -> String+encodeString str = go (UTF8.encodeString str)+ where+  go "" = ""+  go (' ':xs) = '+':go xs+  go ('\r':'\n':xs) = '%':'0':'D':'%':'0':'A':go xs+  go ('\r':xs) = go ('\r':'\n':xs)+  go ('\n':xs) = go ('\r':'\n':xs)+  go (x:xs) = +    case getEncodedChar x of+      Nothing -> x : go xs+      Just ss -> ss ++ go xs+      +decodeString :: String -> String+decodeString "" = ""+decodeString ('+':xs) = ' ':decodeString xs+decodeString ls@(x:xs) = +  case getDecodedChar ls of+    Nothing -> x : decodeString xs+    Just (ch,xs1) -> ch : decodeString xs1
+ MediaWiki/Util/Fetch.hs view
@@ -0,0 +1,136 @@+--------------------------------------------------------------------
+-- |
+-- Module    : MediaWiki.Util.Fetch
+-- Copyright : (c) Sigbjorn Finne, 2008
+-- License   : BSD3
+--
+-- Maintainer: Sigbjorn Finne <sof@forkIO.com>
+-- Stability : provisional
+-- Portability: so-so
+-- 
+-- Simple GET\/de-ref of URLs; abstracting out networking backend\/package.
+--
+module MediaWiki.Util.Fetch 
+       ( readContentsURL
+       , readUserContentsURL
+       
+       , postContentsURL
+
+--       , URLString
+       , User(..)
+       ) where
+       
+--import Network.Curl
+import Network.Browser
+import Network.HTTP
+import Network.URI
+
+type URLString = String
+
+data User
+ = User { userName :: String
+        , userPass :: String
+	}
+
+readContentsURL :: URLString -> IO String
+readContentsURL u = do
+  req <- 
+    case parseURI u of
+      Nothing -> fail ("ill-formed URL: " ++ u)
+      Just ur -> return (defaultGETRequest ur)
+    -- don't like doing this, but HTTP is awfully chatty re: cookie handling..
+  let nullHandler _ = return ()
+  (_u, resp) <- browse $ setOutHandler nullHandler >> request req
+  case rspCode resp of
+    (2,_,_) -> return (rspBody resp)
+    _ -> fail ("Failed reading URL " ++ show u ++ " code: " ++ show (rspCode resp))
+
+{- Curl version:
+readContentsURL :: URLString -> IO String
+readContentsURL u = do
+  let opts = [ CurlFollowLocation True
+	     ]
+  (_,xs) <- curlGetString u opts
+  return xs
+-}
+
+readUserContentsURL :: User -> URLString -> IO String
+readUserContentsURL usr us = do -- readContentsURL u
+  req <- 
+    case parseURI us of
+      Nothing -> fail ("ill-formed URL: " ++ us)
+      Just ur -> return (defaultGETRequest ur)
+    -- don't like doing this, but HTTP is awfully chatty re: cookie handling..
+  let nullHandler _ = return ()
+  (u, resp) <- browse $ do 
+                  setOutHandler nullHandler
+                  setAllowBasicAuth True
+		  setAuthorityGen (\ _ _ -> return (Just (userName usr,userPass usr)))
+{-
+                  addAuthority AuthBasic{ auUsername = userName usr
+                                        , auPassword = userPass usr
+                                        , auRealm    = ""
+                                        , auSite     = nullURI{uriPath="/"}
+                                        }
+-}
+                  request req
+  case rspCode resp of
+    (2,_,_) -> return (rspBody resp)
+    _ -> fail ("Failed reading URL " ++ show u ++ " code: " ++ show (rspCode resp))
+
+
+postContentsURL :: Maybe User -> URLString -> [(String,String)] -> String -> IO ([(String,String)], String)
+postContentsURL mbU u hdrs body = do
+  let hs = 
+       case parseHeaders $ map (\ (x,y) -> x++": " ++ y) hdrs of
+         Left{} -> []
+	 Right xs -> xs
+  req0 <- 
+    case parseURI u of
+      Nothing -> fail ("ill-formed URL: " ++ u)
+      Just ur -> return (defaultGETRequest ur)
+  let req = req0{rqMethod=POST
+                ,rqBody=body
+		,rqHeaders=hs
+	        }
+  let nullHandler _ = return ()
+  (_,rsp) <- browse $ do
+     setOutHandler nullHandler
+     case mbU of
+       Nothing -> return ()
+       Just usr -> do
+         setAllowBasicAuth True
+         setAuthorityGen (\ _ _ -> return (Just (userName usr,userPass usr)))
+		   
+     request req
+  case rspCode rsp of
+    (2,_,_) -> return (map toP (rspHeaders rsp), rspBody rsp)
+    x -> fail ("POST failed - code: " ++ show x ++ ", URL: " ++ u)
+ where
+  toP (Header k v) = (show k, v)
+
+{- Curl versions:
+readUserContentsURL :: User -> URLString -> IO String
+readUserContentsURL u url = do
+  let opts = [ CurlHttpAuth [HttpAuthAny]
+             , CurlUserPwd (userName u ++ 
+	                    case userPass u of {"" -> ""; p -> ':':p })
+             , CurlFollowLocation True
+	     ] 
+  (_,xs) <- curlGetString url opts
+  return xs
+     
+postContentsURL :: URLString -> [(String,String)] -> String -> IO String
+postContentsURL u hdrs body = do
+  let opts = [ CurlCustomRequest "POST"
+             , CurlFollowLocation True
+	     , CurlPost True
+	     , CurlPostFields [body]
+	     , CurlHttpTransferDecoding False
+	     ] ++ [CurlHttpHeaders (map ( \ (x,y) -> (x ++ ':':y)) hdrs)]
+  rsp <- curlGetResponse u opts
+  case respStatus rsp `div` 100 of
+    2 -> return (respBody rsp)
+    x -> fail ("POST failed - code: " ++ show x ++ ", URL: " ++ u)
+
+-}
+ Setup.hs view
@@ -0,0 +1,7 @@+module Main where
+
+import Distribution.Simple
+
+
+main :: IO ()
+main = defaultMain
+ examples/ListCat.hs view
@@ -0,0 +1,133 @@+{-
+  Example of how to query for category members, demonstrating
+  the modules, types and steps used to interact with the API:
+  
+  foo$ listCat "Functional programming"
+  ...
+  foo$ 
+-}
+module Main(main) where
+
+import MediaWiki.API.Base
+import MediaWiki.API.Types ( PageTitle(..) )
+import MediaWiki.API
+import MediaWiki.API.Query.CategoryMembers as CatMem
+import MediaWiki.API.Query.CategoryMembers.Import as CatMem
+
+import Util.GetOpts
+import System.IO
+import System.Environment
+import System.Exit
+
+import Control.Monad
+--import Data.Maybe ( fromMaybe )
+import Data.List
+
+-- begin option handling
+data Options
+ = Options
+    { optWiki    :: String
+    , optUser    :: Maybe String
+    , optPass    :: Maybe String
+    , optCat     :: Maybe String
+    }
+
+nullOptions :: Options
+nullOptions = Options
+    { optWiki    = "http://en.wikipedia.org/w/"
+    , optUser    = Nothing
+    , optPass    = Nothing
+    , optCat     = Nothing
+    }
+
+option_descr :: [OptDescr (Options -> Options)]
+option_descr = 
+  [ Option ['u'] ["user"]
+           (ReqArg (\ x o -> o{optUser=Just x}) "USER")
+	   "Wiki user name to login as"
+  , Option ['p'] ["pass"]
+           (ReqArg (\ x o -> o{optPass=Just x}) "PASSWORD")
+	   "user's password credentials to supply if logging in"
+  , Option ['w'] ["wiki"]
+           (ReqArg (\ x o -> o{optWiki=x}) "WIKI")
+	   "the Wiki to access"
+  , Option ['c'] ["cat"]
+           (ReqArg (\ x o -> o{optCat=Just x}) "CAT")
+	   "the Wiki category to query for"
+  ]
+
+
+parseOptions :: [String] -> (Options, [String], [String])
+parseOptions argv = getOpt2 Permute option_descr argv nullOptions
+
+processOptions :: IO (Options, [String])
+processOptions = do
+  ls <- getArgs
+  let (opts, ws, es) = parseOptions ls
+  when (not $ null es) $ do
+    hPutStrLn stderr (unlines es)
+    hPutStrLn stderr ("(try '--help' for list of options supported.)")
+    exitFailure
+  return (opts, ws)
+
+-- end option handling
+
+queryCat :: URLString -> String -> IO [PageTitle]
+queryCat url catName = queryCat' url catName' req []
+ where 
+  catName'
+    | "Category:" `isPrefixOf` catName = wikify catName
+    | otherwise = "Category:"++wikify catName
+
+  req = categoryMembersRequest{cmTitle=Just catName'}
+
+  wikify "" = ""
+  wikify (' ':xs) = '_':wikify xs
+  wikify (x:xs) = x : wikify xs
+
+
+queryCat' :: URLString -> String -> CategoryMembersRequest -> [PageTitle] -> IO [PageTitle]
+queryCat' url catName cReq acc = do
+  let req = emptyXmlRequest (mkQueryAction (queryPage catName) cReq)
+  mb <- webGetXml CatMem.stringXml url req
+  case mb of
+    Nothing -> fail ("Failed to fetch pages for category " ++ catName ++ " from " ++ url)
+    Just c  -> do
+      let acc' = (acc ++ cmPages c)
+      case cmContinue c of
+        Nothing -> return acc'
+	Just x  -> queryCat' url catName cReq{cmContinueFrom=Just x} acc'
+
+main :: IO ()
+main = do
+  (opts, fs) <- processOptions
+  let url = optWiki opts
+    -- not needed here, but left in to show how to login to a Wiki.
+  case (optUser opts, optPass opts) of
+    (Just u, Just p) -> do
+       x <- loginWiki url u p
+       case x of
+         Nothing -> putStrLn ("Unable to login to: " ++ url)
+         Just lg -> print (lgSuccess lg)
+    _ -> return ()
+  case mbCons (optCat opts) fs of
+    [] -> putStrLn "No categories specified!"
+    xs -> mapM_ (showCat url) xs
+
+showCat :: URLString -> String -> IO ()
+showCat url cat = do
+  ps <- queryCat url cat
+  putStrLn ("Members of category `" ++ cat ++ "'")
+  mapM_ (putStrLn.toTitle) ps
+ where
+  toTitle pg = ' ':pgTitle pg
+{- NS prefix seems to be included in title..
+    case pgNS pg of
+      "" -> pgTitle pg
+      xs -> xs ++ ':':pgTitle pg
+-}
+
+mbCons :: Maybe a -> [a] -> [a]
+mbCons Nothing xs = xs
+mbCons (Just x) xs = x:xs
+
+ mediawiki.cabal view
@@ -0,0 +1,123 @@+Name:               mediawiki
+Version:            0.2
+License:            BSD3
+License-file:       LICENSE
+Category:           Web
+Synopsis:           Interfacing with the MediaWiki API
+Description:        A complete Haskell binding to the MediaWiki API
+Author:             Sigbjorn Finne <sof@forkIO.com>
+Maintainer:         Sigbjorn Finne <sof@forkIO.com>
+Cabal-version:   >= 1.2
+build-type: Simple
+
+flag new-base
+  description: Build with new smaller base library
+  default: False
+
+library
+    Exposed-Modules: MediaWiki.API.Types,
+                     MediaWiki.API.Output,
+                     MediaWiki.API, 
+                     MediaWiki.API.Base, 
+                     MediaWiki.API.Utils, 
+                     MediaWiki.API.Query.AllCategories,
+                     MediaWiki.API.Query.AllCategories.Import,
+                     MediaWiki.API.Query.AllImages,
+                     MediaWiki.API.Query.AllImages.Import,
+                     MediaWiki.API.Query.AllLinks,
+                     MediaWiki.API.Query.AllLinks.Import,
+                     MediaWiki.API.Query.AllMessages,
+                     MediaWiki.API.Query.AllMessages.Import,
+                     MediaWiki.API.Query.AllPages,
+                     MediaWiki.API.Query.AllPages.Import,
+                     MediaWiki.API.Query.AllUsers,
+                     MediaWiki.API.Query.AllUsers.Import,
+                     MediaWiki.API.Query.BackLinks,
+                     MediaWiki.API.Query.BackLinks.Import,
+                     MediaWiki.API.Query.Blocks,
+                     MediaWiki.API.Query.Blocks.Import,
+                     MediaWiki.API.Query.Categories,
+                     MediaWiki.API.Query.Categories.Import,
+                     MediaWiki.API.Query.CategoryInfo,
+                     MediaWiki.API.Query.CategoryInfo.Import,
+                     MediaWiki.API.Query.CategoryMembers,
+                     MediaWiki.API.Query.CategoryMembers.Import,
+                     MediaWiki.API.Query.DeletedRevisions,
+                     MediaWiki.API.Query.DeletedRevisions.Import,
+                     MediaWiki.API.Query.EmbeddedIn,
+                     MediaWiki.API.Query.EmbeddedIn.Import,
+                     MediaWiki.API.Query.ExternalLinks
+                     MediaWiki.API.Query.ExternalLinks.Import,
+                     MediaWiki.API.Query.ExternalURLUsage
+                     MediaWiki.API.Query.ExternalURLUsage.Import,
+                     MediaWiki.API.Query.ImageInfo,
+                     MediaWiki.API.Query.ImageInfo.Import,
+                     MediaWiki.API.Query.Images,
+                     MediaWiki.API.Query.Images.Import,
+                     MediaWiki.API.Query.ImageUsage,
+                     MediaWiki.API.Query.ImageUsage.Import,
+                     MediaWiki.API.Query.Info,
+                     MediaWiki.API.Query.Info.Import,
+                     MediaWiki.API.Query.LangLinks,
+                     MediaWiki.API.Query.LangLinks.Import,
+                     MediaWiki.API.Query.Links,
+                     MediaWiki.API.Query.Links.Import,
+                     MediaWiki.API.Query.LogEvents,
+                     MediaWiki.API.Query.LogEvents.Import,
+                     MediaWiki.API.Query.Random,
+                     MediaWiki.API.Query.Random.Import,
+                     MediaWiki.API.Query.RecentChanges,
+                     MediaWiki.API.Query.RecentChanges.Import,
+                     MediaWiki.API.Query.Revisions,
+                     MediaWiki.API.Query.Revisions.Import,
+                     MediaWiki.API.Query.Search,
+                     MediaWiki.API.Query.Search.Import,
+                     MediaWiki.API.Query.SiteInfo,
+                     MediaWiki.API.Query.SiteInfo.Import,
+                     MediaWiki.API.Query.Templates,
+                     MediaWiki.API.Query.Templates.Import,
+                     MediaWiki.API.Query.UserContribs,
+                     MediaWiki.API.Query.UserContribs.Import,
+                     MediaWiki.API.Query.UserInfo,
+                     MediaWiki.API.Query.UserInfo.Import,
+                     MediaWiki.API.Query.Users,
+                     MediaWiki.API.Query.Users.Import,
+                     MediaWiki.API.Query.WatchList,
+                     MediaWiki.API.Query.WatchList.Import,
+                     MediaWiki.API.Action.Sitematrix,
+                     MediaWiki.API.Action.Login,
+                     MediaWiki.API.Action.Login.Import,
+                     MediaWiki.API.Action.ParamInfo,
+                     MediaWiki.API.Action.Parse,
+                     MediaWiki.API.Action.Parse.Import,
+                     MediaWiki.API.Action.Rollback,
+                     MediaWiki.API.Action.Delete,
+                     MediaWiki.API.Action.Undelete,
+                     MediaWiki.API.Action.Protect,
+                     MediaWiki.API.Action.Block,
+                     MediaWiki.API.Action.Unblock,
+                     MediaWiki.API.Action.Move,
+                     MediaWiki.API.Action.Edit,
+                     MediaWiki.API.Action.EmailUser,
+                     MediaWiki.API.Action.Watch,
+                     MediaWiki.API.Action.OpenSearch,
+                     MediaWiki.API.Action.FeedWatchlist,
+                     MediaWiki.API.Action.ExpandTemplates,
+                     MediaWiki.API.Action.ExpandTemplates.Import,
+                     MediaWiki.Util.Fetch,
+                     MediaWiki.Util.Codec.Percent,
+                     MediaWiki.Util.Codec.URLEncoder
+    Ghc-Options:     -Wall -O2 
+    Build-Depends:   base, xml, HTTP, network, mime, utf8-string
+
+executable main {
+  build-depends:        base
+  main-is:              Main.hs
+  ghc-options:          -Wall -fglasgow-exts
+}
+
+executable listCat {
+  build-depends:        base, pretty
+  main-is:              examples/ListCat.hs
+  ghc-options:          -Wall -fglasgow-exts -iexamples
+}