changeset 26:d0a8677457db

Add mediawiki mode
author Jordi Gutiérrez Hermoso <jordigh@gmail.com>
date Thu, 29 Jul 2010 14:58:17 -0500
parents 67a96731dbab
children 8763b5053360
files plugins/mediawiki.el
diffstat 1 files changed, 2047 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/plugins/mediawiki.el
@@ -0,0 +1,2047 @@
+;;; mediawiki.el --- mediawiki frontend
+
+;; Copyright (C) 2008, 2009, 2010 Mark A. Hershberger
+
+;; Original Authors: Jerry <unidevel@yahoo.com.cn>,
+;;      Chong Yidong <cyd at stupidchicken com> for wikipedia.el,
+;;      Uwe Brauer <oub at mat.ucm.es> for wikimedia.el
+;; Author: Mark A. Hershberger <mah@everybody.org>
+;; Version: 2.2.1
+;; Created: Sep 17 2004
+;; Keywords: mediawiki wikipedia network wiki
+;; URL: http://launchpad.net/mediawiki-el
+;; Last Modified: <2010-07-11 04:02:16 mah>
+
+(defconst mediawiki-version "2.2.1"
+  "Current version of mediawiki.el")
+
+;; This file is NOT (yet) part of GNU Emacs.
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This version of mediawiki.el represents a merging of
+;; wikipedia-mode.el (maintained by Uwe Brauer <oub at mat.ucm.es>)
+;; from http://www.emacswiki.org/emacs/wikipedia-mode.el for its
+;; font-lock code, menu, draft mode, replying and convenience
+;; functions to produce mediawiki.el 2.0.
+
+;;; Installation
+
+;; If you use ELPA (http://tromey.com/elpa), you can install via the
+;; M-x package-list-packages interface. This is preferrable as you
+;; will have access to updates automatically.
+
+;; Otherwise, just make sure this file is in your load-path (usually
+;; ~/.emacs.d is included) and put (require 'mediawiki.el) in your
+;; ~/.emacs or ~/.emacs.d/init.el file.
+
+;;; Howto:
+;;  M-x customize-group RET mediawiki RET
+;;  *dink* *dink*
+;;  M-x mediawiki-site RET Wikipedia RET
+;;
+;; Open a wiki file:    M-x mediawiki-open
+;; Save a wiki buffer:  C-x C-s
+;; Save a wiki buffer with a different name:  C-x C-w
+
+;;; TODO:
+;;  * Optionally use org-mode formatting for editing and translate
+;;    that to mw
+;;  * Move url-* methods to url-http
+;;  * Use the MW API to support searching, etc.
+;;  * Clean up and thoroughly test imported wikimedia.el code
+;;  * Improve language support.  Currently there is a toggle for
+;;    English or German.  This should probably just be replaced with
+;;    customizable words given MediaWiki's wide language support.
+
+;;; History
+
+;; From the News section of wikipedia.el comes this bit, kept here for
+;; reference later.
+;;     (4) "Draft", "send" and "reply" (for discussion pages)
+;;         abilities `based' on ideas of John Wigleys remember.el: see
+;;         the functions wikipedia-draft-*
+;;         RATIONALE: This comes handy in 2 situations
+;;            1. You are editing articles which various authors (this I
+;;               think is the usual case), you then want not to submit
+;;               your edit immediately but want to copy it somewhere and
+;;               to continue later. You can use the following functions
+;;               for doing that:
+;;               wikipedia-draft-buffer \C-c\C-b
+;;               wikipedia-draft-region \C-c\C-r
+;;               then the buffer/region will be appended to the
+;;               wikipedia-draft-data-file (default is
+;;               "~/Wiki/discussions/draft.wiki", which you can visit via
+;;               wikipedia-draft-view-draft) and it will be
+;;               surrounded by the ^L marks in order to set a page.
+;;               moreover on top on that a section header == will be
+;;               inserted, which consists of the Word Draft, a subject
+;;               you are asked for and a date stamp.
+;;
+;;               Another possibility consists in using the function
+;;               wikipedia-draft, bound to \C-c \C-m then a new buffer
+;;               will opened already in wikipedia mode. You edit and then
+;;               either can send the content of the buffer to the
+;;               wikipedia-draft-data-file in the same manner as
+;;               described above using the function
+;;               wikipedia-draft-buffer (bound to \C-c\C-k)
+;;
+;;               BACK: In order to copy/send the content of temporary
+;;               buffer or of a page in the wikipedia-draft-data-file
+;;               back in to your wikipedia file, use the function
+;;               wikipedia-send-draft-to-mozex bound to "\C-c\C-c". You
+;;               will be asked to which buffer to copy your text!
+;;
+;;
+;;            2. You want to reply  in a discussion page to a specific
+;;               contribution, you can use either the function
+;;
+;;               \\[wikipedia-reply-at-point-simple] bound to [(meta shift r)]
+;;               which inserts a newline, a hline, and the signature of
+;;               the author. Or can use
+;;               \\[wikipedia-draft-reply] bound  [(meta r)]
+;;               which does the same as wikipedia-reply-at-point-simple
+;;               but in a temporary draft buffer.
+;;
+;;               BACK: In order to copy/send the content of that buffer
+;;               back in to your wikipedia file, use the function
+;;               \\[wikipedia-send-draft-to-mozex] bound to "\C-c\C-c". You
+;;               will be asked to which buffer to copy your text! If
+;;               you want a copy to be send to your draft file, use
+;;               the variable  wikipedia-draft-send-archive
+;;
+
+;;; Code:
+
+(require 'url-http)
+(require 'mml)
+(require 'mm-url)
+(require 'ring)
+(eval-when-compile (require 'cl))
+
+;; As of 2010-06-22, these functions are in Emacs
+(unless (fboundp 'url-user-for-url)
+  (require 'url-parse)
+  (defmacro url-bit-for-url (method lookfor url)
+    (when (fboundp 'auth-source-user-or-password)
+      `(let* ((urlobj (url-generic-parse-url url))
+              (bit (funcall ,method urlobj))
+              (methods (list 'url-recreate-url
+                             'url-host)))
+         (while (and (not bit) (> (length methods) 0))
+           (setq bit
+                 (auth-source-user-or-password
+                  ,lookfor (funcall (pop methods) urlobj) (url-type urlobj))))
+         bit)))
+
+  (defun url-user-for-url (url)
+    "Attempt to use .authinfo to find a user for this URL."
+    (url-bit-for-url 'url-user "login" url))
+
+  (defun url-password-for-url (url)
+    "Attempt to use .authinfo to find a password for this URL."
+    (url-bit-for-url 'url-password "password" url)))
+
+(if (string= "GET / HTTP/1.0
\nMIME-Version: 1.0
\nConnection: close
\nHost: example.com
\nAccept: */*
\nUser-Agent: URL/Emacs
\nContent-length: 4
\n
\ntest"
+        (let ((url-http-target-url (url-generic-parse-url "http://example.com/"))
+              (url-http-data "test") (url-http-version "1.0")
+              url-http-method url-http-attempt-keepalives url-extensions-header
+              url-http-extra-headers url-http-proxy url-mime-charset-string)
+         (url-http-create-request)))
+    (defun url-http-create-request (&optional ref-url)
+      "Create an HTTP request for `url-http-target-url', referred to by REF-URL."
+      (declare (special proxy-info
+                        url-http-method url-http-data
+                        url-http-extra-headers))
+      (let* ((extra-headers)
+             (request nil)
+             (no-cache (cdr-safe (assoc "Pragma" url-http-extra-headers)))
+             (using-proxy url-http-proxy)
+             (proxy-auth (if (or (cdr-safe (assoc "Proxy-Authorization"
+                                                  url-http-extra-headers))
+                                 (not using-proxy))
+                             nil
+                           (let ((url-basic-auth-storage
+                                  'url-http-proxy-basic-auth-storage))
+                             (url-get-authentication url-http-target-url nil 'any nil))))
+             (real-fname (concat (url-filename url-http-target-url)
+                                 (url-recreate-url-attributes url-http-target-url)))
+             (host (url-host url-http-target-url))
+             (auth (if (cdr-safe (assoc "Authorization" url-http-extra-headers))
+                       nil
+                     (url-get-authentication (or
+                                              (and (boundp 'proxy-info)
+                                                   proxy-info)
+                                              url-http-target-url) nil 'any nil))))
+        (if (equal "" real-fname)
+            (setq real-fname "/"))
+        (setq no-cache (and no-cache (string-match "no-cache" no-cache)))
+        (if auth
+            (setq auth (concat "Authorization: " auth "\r\n")))
+        (if proxy-auth
+            (setq proxy-auth (concat "Proxy-Authorization: " proxy-auth "\r\n")))
+
+        ;; Protection against stupid values in the referer
+        (if (and ref-url (stringp ref-url) (or (string= ref-url "file:nil")
+                                               (string= ref-url "")))
+            (setq ref-url nil))
+
+        ;; We do not want to expose the referer if the user is paranoid.
+        (if (or (memq url-privacy-level '(low high paranoid))
+                (and (listp url-privacy-level)
+                     (memq 'lastloc url-privacy-level)))
+            (setq ref-url nil))
+
+        ;; url-http-extra-headers contains an assoc-list of
+        ;; header/value pairs that we need to put into the request.
+        (setq extra-headers (mapconcat
+                             (lambda (x)
+                               (concat (car x) ": " (cdr x)))
+                             url-http-extra-headers "\r\n"))
+        (if (not (equal extra-headers ""))
+            (setq extra-headers (concat extra-headers "\r\n")))
+
+        ;; This was done with a call to `format'.  Concatting parts has
+        ;; the advantage of keeping the parts of each header together and
+        ;; allows us to elide null lines directly, at the cost of making
+        ;; the layout less clear.
+        (setq request
+              ;; We used to concat directly, but if one of the strings happens
+              ;; to being multibyte (even if it only contains pure ASCII) then
+              ;; every string gets converted with `string-MAKE-multibyte' which
+              ;; turns the 127-255 codes into things like latin-1 accented chars
+              ;; (it would work right if it used `string-TO-multibyte' instead).
+              ;; So to avoid the problem we force every string to be unibyte.
+              (mapconcat
+               ;; FIXME: Instead of `string-AS-unibyte' we'd want
+               ;; `string-to-unibyte', so as to properly signal an error if one
+               ;; of the strings contains a multibyte char.
+               'string-as-unibyte
+               (delq nil
+                     (list
+                      ;; The request
+                      (or url-http-method "GET") " "
+                      (if using-proxy (url-recreate-url url-http-target-url) real-fname)
+                      " HTTP/" url-http-version "\r\n"
+                      ;; Version of MIME we speak
+                      "MIME-Version: 1.0\r\n"
+                      ;; (maybe) Try to keep the connection open
+                      "Connection: " (if (or using-proxy
+                                             (not url-http-attempt-keepalives))
+                                         "close" "keep-alive") "\r\n"
+                                         ;; HTTP extensions we support
+                                         (if url-extensions-header
+                                             (format
+                                              "Extension: %s\r\n" url-extensions-header))
+                                         ;; Who we want to talk to
+                                         (if (/= (url-port url-http-target-url)
+                                                 (url-scheme-get-property
+                                                  (url-type url-http-target-url) 'default-port))
+                                             (format
+                                              "Host: %s:%d\r\n" host (url-port url-http-target-url))
+                                           (format "Host: %s\r\n" host))
+                                         ;; Who its from
+                                         (if url-personal-mail-address
+                                             (concat
+                                              "From: " url-personal-mail-address "\r\n"))
+                                         ;; Encodings we understand
+                                         (if url-mime-encoding-string
+                                             (concat
+                                              "Accept-encoding: " url-mime-encoding-string "\r\n"))
+                                         (if url-mime-charset-string
+                                             (concat
+                                              "Accept-charset: " url-mime-charset-string "\r\n"))
+                                         ;; Languages we understand
+                                         (if url-mime-language-string
+                                             (concat
+                                              "Accept-language: " url-mime-language-string "\r\n"))
+                                         ;; Types we understand
+                                         "Accept: " (or url-mime-accept-string "*/*") "\r\n"
+                                         ;; User agent
+                                         (url-http-user-agent-string)
+                                         ;; Proxy Authorization
+                                         proxy-auth
+                                         ;; Authorization
+                                         auth
+                                         ;; Cookies
+                                         (url-cookie-generate-header-lines host real-fname
+                                                                           (equal "https" (url-type url-http-target-url)))
+                                         ;; If-modified-since
+                                         (if (and (not no-cache)
+                                                  (member url-http-method '("GET" nil)))
+                                             (let ((tm (url-is-cached url-http-target-url)))
+                                               (if tm
+                                                   (concat "If-modified-since: "
+                                                           (url-get-normalized-date tm) "\r\n"))))
+                                         ;; Whence we came
+                                         (if ref-url (concat
+                                                      "Referer: " ref-url "\r\n"))
+                                         extra-headers
+                                         ;; Length of data
+                                         (if url-http-data
+                                             (concat
+                                              "Content-length: " (number-to-string
+                                                                  (length url-http-data))
+                                              "\r\n"))
+                                         ;; End request
+                                         "\r\n"
+                                         ;; Any data
+                                         url-http-data "\r\n"))
+               ""))
+        (url-http-debug "Request is: \n%s" request)
+        request)))
+
+(unless (fboundp 'mm-url-encode-multipart-form-data)
+  (defun mm-url-encode-multipart-form-data (pairs &optional boundary)
+    "Return PAIRS encoded in multipart/form-data."
+    ;; RFC1867
+
+    ;; Get a good boundary
+    (unless boundary
+      (setq boundary (mml-compute-boundary '())))
+
+    (concat
+
+     ;; Start with the boundary
+     "--" boundary "\r\n"
+
+     ;; Create name value pairs
+     (mapconcat
+      'identity
+      ;; Delete any returned items that are empty
+      (delq nil
+            (mapcar (lambda (data)
+                      (when (car data)
+                        ;; For each pair
+                        (concat
+
+                         ;; Encode the name
+                         "Content-Disposition: form-data; name=\""
+                         (car data) "\"\r\n"
+                         "Content-Type: text/plain; charset=utf-8\r\n"
+                         "Content-Transfer-Encoding: binary\r\n\r\n"
+
+                         (cond ((stringp (cdr data))
+                                (cdr data))
+                               ((integerp (cdr data))
+                                (int-to-string (cdr data))))
+
+                         "\r\n")))
+                    pairs))
+      ;; use the boundary as a separator
+      (concat "--" boundary "\r\n"))
+
+     ;; put a boundary at the end.
+     "--" boundary "--\r\n")))
+
+;; Not defined in my Xemacs
+(unless (fboundp 'assoc-string)
+  (defun assoc-string (key list &optional case-fold)
+    (if case-fold
+	(assoc-ignore-case key list)
+      (assoc key list))))
+
+(defun url-compat-retrieve (url post-process bufname callback cbargs)
+  (cond ((boundp 'url-be-asynchronous) ; Sniff w3 lib capability
+	 (if callback
+	     (setq url-be-asynchronous t
+		   url-current-callback-data cbargs
+		   url-current-callback-func callback)
+	   (setq url-be-asynchronous nil))
+	 (url-retrieve url t)
+	 (when (not url-be-asynchronous)
+	   (let ((result (funcall post-process bufname)))
+	     result)))
+	(t (if callback
+	       (url-retrieve url post-process
+			     (list bufname callback cbargs))
+	     (with-current-buffer (url-retrieve-synchronously url)
+	       (funcall post-process bufname))))))
+
+(defvar url-http-get-post-process 'url-http-response-post-process)
+(defun url-http-get (url &optional headers bufname callback cbargs)
+  "Convenience method to use method 'GET' to retrieve URL"
+  (let* ((url-request-extra-headers (if headers headers
+                                      (if url-request-extra-headers
+                                          url-request-extra-headers
+                                        (cons nil nil))))
+         (url-request-method "GET"))
+
+    (when (url-basic-auth url)
+      (add-to-list 'url-request-extra-headers
+                   (cons "Authorization" (url-basic-auth url))))
+    (url-compat-retrieve url url-http-get-post-process
+			 bufname callback cbargs)))
+
+(defvar url-http-post-post-process 'url-http-response-post-process)
+(defun url-http-post (url parameters &optional multipart headers bufname
+                          callback cbargs)
+  "Convenience method to use method 'POST' to retrieve URL"
+
+  (let* ((url-request-extra-headers
+          (if headers headers
+            (if url-request-extra-headers url-request-extra-headers
+              (cons nil nil))))
+         (boundary (int-to-string (random)))
+         (cs 'utf-8)
+         (content-type
+          (if multipart
+              (concat "multipart/form-data, boundary=" boundary)
+            (format "application/x-www-form-urlencoded; charset=%s" cs)))
+         (url-request-method "POST")
+         (url-request-coding-system cs)
+         (url-request-data
+          (if multipart
+              (mm-url-encode-multipart-form-data
+               parameters boundary)
+            (mm-url-encode-www-form-urlencoded (delq nil parameters)))))
+    (mapc
+     (lambda (pair)
+       (let ((key (car pair))
+             (val (cdr pair)))
+         (if (assoc key url-request-extra-headers)
+             (setcdr (assoc key url-request-extra-headers) val)
+           (add-to-list 'url-request-extra-headers
+                        (cons key val)))))
+     (list
+      (cons "Connection" "close")
+      (cons "Content-Type" content-type)))
+
+    (message "Posting to: %s" url)
+    (url-compat-retrieve url url-http-post-post-process
+			 bufname callback cbargs)))
+
+(defun url-http-response-post-process (status &optional bufname
+                                              callback cbargs)
+  "Post process on HTTP response."
+  (declare (special url-http-end-of-headers))
+  (let ((kill-this-buffer (current-buffer)))
+    (when (and (integerp status) (not (< status 300)))
+      (kill-buffer kill-this-buffer)
+      (error "Oops! Invalid status: %d" status))
+
+    (when (or (not (boundp 'url-http-end-of-headers))
+              (not url-http-end-of-headers))
+      (kill-buffer kill-this-buffer)
+      (error "Oops! Don't see end of headers!"))
+
+    ;; FIXME: need to limit redirects
+    (if (and (listp status)
+             (eq (car status) :redirect))
+        (progn
+          (message (concat "Redirecting to " (cadr status)))
+          (url-http-get (cadr status) nil bufname callback cbargs))
+
+      (goto-char url-http-end-of-headers)
+      (forward-line)
+
+      (let ((str (decode-coding-string
+                  (buffer-substring-no-properties (point) (point-max))
+                  'utf-8)))
+        (kill-buffer (current-buffer))
+        (when bufname
+          (set-buffer bufname)
+          (insert str)
+          (goto-char (point-min))
+          (set-buffer-modified-p nil))
+        (when callback
+          (apply callback (list str cbargs)))
+        (when (not (or callback bufname))
+          str)))))
+
+(defgroup mediawiki nil
+  "A mode for editting pages on MediaWiki sites."
+  :tag "MediaWiki"
+  :group 'applications)
+
+(defcustom mediawiki-site-default "Wikipedia"
+  "The default mediawiki site to point to.  Set here for the
+default and use `mediawiki-site' to set it per-session
+later."
+  :type 'string
+  :tag "MediaWiki Site Default"
+  :group 'mediawiki)
+
+(defcustom mediawiki-site-alist '(("Wikipedia"
+                                   "http://en.wikipedia.org/w/"
+                                   "username"
+                                   "password"
+				   "Main Page"))
+  "A list of MediaWiki websites."
+  :group 'mediawiki
+  :type '(alist :tag "Site Name"
+                :key-type (string :tag "Site Name")
+                :value-type (list :tag "Parameters"
+                                  (string :tag "URL")
+                                  (string :tag "Username")
+                                  (string :tag "Password")
+                                  (string :tag "First Page"
+                                          :description "First page to open when `mediawiki-site' is called for this site"))))
+
+(defcustom mediawiki-pop-buffer-hook '()
+  "List of functions to execute after popping to a buffer.  Can
+be used to to open the whole buffer."
+  :options '(delete-other-windows)
+  :type 'hook
+  :group 'mediawiki)
+
+(defvar mediawiki-enumerate-with-terminate-paragraph nil
+"*Before insert enumerate/itemize do \\[mediawiki-terminate-paragraph].")
+
+(defvar mediawiki-english-or-german t
+  "*Variable in order to set the english (t) or german (nil) environment.")
+
+(defvar mediawiki-user-simplify-signature t
+  "*Simple varible in order to threat complicated signatures of users, which uses
+fonts and other makeup.")
+
+(defgroup mediawiki-draft nil
+  "A mode to mediawiki-draft information."
+  :group 'mediawiki)
+
+;;; User Variables:
+
+(defcustom mediawiki-draft-mode-hook nil
+  "*Functions run upon entering mediawiki-draft-mode."
+  :type 'hook
+  :group 'mediawiki-draft)
+
+(defcustom mediawiki-draft-register ?R
+  "The register in which the window configuration is stored."
+  :type 'character
+  :group 'mediawiki-draft)
+
+(defcustom mediawiki-draft-filter-functions nil
+  "*Functions run to filter mediawiki-draft data.
+All functions are run in the mediawiki-draft buffer."
+  :type 'hook
+  :group 'mediawiki-draft)
+
+(defcustom mediawiki-draft-handler-functions '(mediawiki-draft-append-to-file)
+  "*Functions run to process mediawiki-draft data.
+Each function is called with the current buffer narrowed to what the
+user wants mediawiki-drafted.
+If any function returns non-nil, the data is assumed to have been
+recorded somewhere by that function. "
+  :type 'hook
+  :group 'mediawiki-draft)
+
+(defcustom mediawiki-draft-data-file "~/Wiki/discussions/draft.wiki"
+  "*The file in which to store the wikipedia drafts."
+  :type 'file
+  :group 'mediawiki-draft)
+
+(defcustom mediawiki-draft-reply-register ?M
+  "The register in which the window configuration is stored."
+  :type 'character
+  :group 'mediawiki-draft)
+
+(defcustom mediawiki-draft-page ?S		;Version:1.37
+  "The register in which the a page of the wiki draft file is stored."
+  :type 'character
+  :group 'mediawiki-draft)
+
+
+(defcustom mediawiki-draft-leader-text "== "
+  "*The text used to begin each mediawiki-draft item."
+  :type 'string
+  :group 'mediawiki-draft)
+
+(defvar mediawiki-reply-with-hline nil
+"*Whether to use a hline as a header seperator in the reply.")
+
+(defvar mediawiki-reply-with-quote nil
+  "*Whether to use a quotation tempalate or not.")
+
+(defvar mediawiki-imenu-generic-expression
+  (list '(nil "^==+ *\\(.*[^\n=]\\)==+" 1))
+  "Imenu expression for `mediawiki-mode'.  See `imenu-generic-expression'.")
+
+(defvar mediawiki-login-success "pt-logout"
+  "A string that should be present on login success on all
+mediawiki sites.")
+
+(defvar mediawiki-permission-denied
+  "[^;]The action you have requested is limited"
+  "A string that will indicate permission has been denied, Note
+that it should not match the mediawiki.el file itself since it
+is sometimes put on MediaWiki sites.")
+
+(defvar mediawiki-view-source
+  "ca-viewsource"
+  "A string that will indicate you can only view source on this
+page.")
+
+(defvar mediawiki-site nil
+  "The current mediawiki site from `mediawiki-site-alist'.  If
+not set, defaults to `mediawiki-site-default'.")
+
+(defvar mediawiki-argument-pattern "?title=%s&action=%s"
+  "Format of the string to append to URLs.  Two string arguments
+are expected: first is a title and then an action.")
+
+(defvar mediawiki-URI-pattern
+  "http://\\([^/:]+\\)\\(:\\([0-9]+\\)\\)?/"
+  "Pattern matching a URI like this:
+	http://mediawiki.sf.net/index.php
+Password not support yet")
+
+(defvar mediawiki-page-uri nil
+  "The URI of the page corresponding to the current buffer, thus defining
+the base URI of the wiki engine as well as group and page name.")
+
+(defvar mediawiki-page-title nil
+  "The title of the page corresponding to the current buffer")
+
+(defvar mediawiki-edittoken nil
+  "The edit token for this page.")
+(defvar mediawiki-starttimestamp nil
+  "The starttimestamp for this page.")
+(defvar mediawiki-basetimestamp nil
+  "The base timestamp for this page.")
+
+(defvar mediawiki-page-ring nil
+  "Ring that holds names of buffers we navigate through.")
+
+(defvar mediawiki-page-ring-index 0)
+
+(defvar font-mediawiki-sedate-face 'font-mediawiki-sedate-face
+  "Face to use for mediawiki  minor keywords.")
+(defvar font-mediawiki-italic-face 'font-mediawiki-italic-face
+  "Face to use for mediawiki italics.")
+(defvar font-mediawiki-bold-face 'font-mediawiki-bold-face
+  "Face to use for mediawiki bolds.")
+(defvar font-mediawiki-math-face 'font-mediawiki-math-face
+  "Face to use for mediawiki math environments.")
+(defvar font-mediawiki-string-face 'font-mediawiki-string-face
+  "Face to use for strings.")
+(defvar font-mediawiki-verbatim-face 'font-mediawiki-verbatim-face
+  "Face to use for text in verbatim macros or environments.")
+
+(defface font-mediawiki-bold-face
+  (let ((font (cond ((assq :inherit custom-face-attributes) '(:inherit bold))
+		    ((assq :weight custom-face-attributes) '(:weight bold))
+		    (t '(:bold t)))))
+    `((((class grayscale) (background light))
+       (:foreground "DimGray" ,@font))
+      (((class grayscale) (background dark))
+       (:foreground "LightGray" ,@font))
+      (((class color) (background light))
+       (:foreground "DarkOliveGreen" ,@font))
+      (((class color) (background dark))
+       (:foreground "OliveDrab" ,@font))
+      (t (,@font))))
+  "Face used to highlight text to be typeset in bold."
+  :group 'font-mediawiki-highlighting-faces)
+
+(defface font-mediawiki-italic-face
+  (let ((font (cond ((assq :inherit custom-face-attributes) '(:inherit italic))
+		    ((assq :slant custom-face-attributes) '(:slant italic))
+		    (t '(:italic t)))))
+    `((((class grayscale) (background light))
+       (:foreground "DimGray" ,@font))
+      (((class grayscale) (background dark))
+       (:foreground "LightGray" ,@font))
+      (((class color) (background light))
+       (:foreground "DarkOliveGreen" ,@font))
+      (((class color) (background dark))
+       (:foreground "OliveDrab" ,@font))
+      (t (,@font))))
+  "Face used to highlight text to be typeset in italic."
+  :group 'font-mediawiki-highlighting-faces)
+
+(defface font-mediawiki-math-face
+  (let ((font (cond ((assq :inherit custom-face-attributes)
+		     '(:inherit underline))
+		    (t '(:underline t)))))
+    `((((class grayscale) (background light))
+       (:foreground "DimGray" ,@font))
+      (((class grayscale) (background dark))
+       (:foreground "LightGray" ,@font))
+      (((class color) (background light))
+       (:foreground "SaddleBrown"))
+      (((class color) (background dark))
+       (:foreground "burlywood"))
+      (t (,@font))))
+  "Face used to highlight math."
+  :group 'font-mediawiki-highlighting-faces)
+
+(defface font-mediawiki-sedate-face
+  '((((class grayscale) (background light)) (:foreground "DimGray"))
+    (((class grayscale) (background dark))  (:foreground "LightGray"))
+    (((class color) (background light)) (:foreground "DimGray"))
+    (((class color) (background dark))  (:foreground "LightGray"))
+   ;;;(t (:underline t))
+    )
+  "Face used to highlight sedate stuff."
+  :group 'font-mediawiki-highlighting-faces)
+
+(defface font-mediawiki-string-face
+  (let ((font (cond ((assq :inherit custom-face-attributes) '(:inherit italic))
+		    ((assq :slant custom-face-attributes) '(:slant italic))
+		    (t '(:italic t)))))
+    `((((type tty) (class color))
+       (:foreground "green"))
+      (((class grayscale) (background light))
+       (:foreground "DimGray" ,@font))
+      (((class grayscale) (background dark))
+       (:foreground "LightGray" ,@font))
+      (((class color) (background light))
+       (:foreground "RosyBrown"))
+      (((class color) (background dark))
+       (:foreground "LightSalmon"))
+      (t (,@font))))
+  "Face used to highlight strings."
+  :group 'font-mediawiki-highlighting-faces)
+
+(defface font-mediawiki-warning-face
+  (let ((font (cond ((assq :inherit custom-face-attributes) '(:inherit bold))
+		    ((assq :weight custom-face-attributes) '(:weight bold))
+		    (t '(:bold t)))))
+    `((((class grayscale)(background light))
+       (:foreground "DimGray" ,@font))
+      (((class grayscale)(background dark))
+       (:foreground "LightGray" ,@font))
+      (((class color)(background light))
+       (:foreground "red" ,@font))
+      (((class color)(background dark))
+       (:foreground "red" ,@font))
+      (t (,@font))))
+  "Face for important keywords."
+  :group 'font-mediawiki-highlighting-faces)
+
+(defface font-mediawiki-verbatim-face
+  (let ((font (if (and (assq :inherit custom-face-attributes)
+		       (if (fboundp 'find-face)
+			   (find-face 'fixed-pitch)
+			 (facep 'fixed-pitch)))
+		  '(:inherit fixed-pitch)
+		'(:family "courier"))))
+    `((((class grayscale) (background light))
+       (:foreground "DimGray" ,@font))
+      (((class grayscale) (background dark))
+       (:foreground "LightGray" ,@font))
+      (((class color) (background light))
+       (:foreground "SaddleBrown" ,@font))
+      (((class color) (background dark))
+       (:foreground "burlywood" ,@font))
+      (t (,@font))))
+  "Face used to highlight TeX verbatim environments."
+  :group 'font-mediawiki-highlighting-faces)
+
+(defvar mediawiki-simple-tags
+  '("b" "big" "blockquote" "br" "caption" "code" "center" "cite" "del"
+    "dfn" "dl" "em" "i" "ins" "kbd" "math" "nowiki" "ol" "pre" "samp"
+    "small" "strike" "strong" "sub" "sup" "tt" "u" "ul" "var")
+  "Tags that do not accept arguments.")
+
+(defvar mediawiki-complex-tags
+  '("a" "div" "font" "table" "td" "th" "tr")
+  "Tags that accept arguments.")
+
+(defvar mediawiki-url-protocols
+  '("ftp" "gopher" "http" "https" "mailto" "news")
+  "Valid protocols for URLs in Wikipedia articles.")
+
+(defvar mediawiki-draft-buffer "*MW-Draft*"
+  "The name of the wikipedia-draft (temporary) data entry buffer.")
+
+(defvar mediawiki-edit-form-vars nil)
+
+(defvar mediawiki-font-lock-keywords
+  (list
+
+   ;; Apostrophe-style text markup
+   (cons "''''\\([^']\\|[^']'\\)*?\\(''''\\|\n\n\\)"
+         'font-lock-builtin-face)
+   (cons "'''\\([^']\\|[^']'\\)*?\\('''\\|\n\n\\)"
+                                        ;'font-lock-builtin-face)
+         'font-mediawiki-bold-face)
+   (cons "''\\([^']\\|[^']'\\)*?\\(''\\|\n\n\\)"
+         'font-mediawiki-italic-face)
+
+   ;; Headers and dividers
+   (list "^\\(==+\\)\\(.*\\)\\(\\1\\)"
+         '(1 font-lock-builtin-face)
+                                        ;'(2 mediawiki-header-face)
+         '(2 font-mediawiki-sedate-face)
+         '(3 font-lock-builtin-face))
+   (cons "^-----*" 'font-lock-builtin-face)
+
+   ;; Bare URLs and ISBNs
+   (cons (concat "\\(^\\| \\)" (regexp-opt mediawiki-url-protocols t)
+                 "://[-A-Za-z0-9._\/~%+&#?!=()@]+")
+         'font-lock-variable-name-face)
+   (cons "\\(^\\| \\)ISBN [-0-9A-Z]+" 'font-lock-variable-name-face)
+
+   ;; Colon indentation, lists, definitions, and tables
+   (cons "^\\(:+\\|[*#]+\\||[}-]?\\|{|\\)" 'font-lock-builtin-face)
+   (list "^\\(;\\)\\([^:\n]*\\)\\(:?\\)"
+         '(1 font-lock-builtin-face)
+         '(2 font-lock-keyword-face)
+         '(3 font-lock-builtin-face))
+
+   ;; Tags and comments
+   (list (concat "\\(</?\\)"
+                 (regexp-opt mediawiki-simple-tags t) "\\(>\\)")
+         '(1 font-lock-builtin-face t t)
+         '(2 font-lock-function-name-face t t)
+         '(3 font-lock-builtin-face t t))
+   (list (concat "\\(</?\\)"
+                 (regexp-opt mediawiki-complex-tags t)
+                 "\\(\\(?: \\(?:[^\"'/><]\\|\"[^\"]*\"\\|'[^']*'\\)*\\)?\\)\\(>\\)")
+         '(1 font-lock-builtin-face t t)
+         '(2 font-lock-function-name-face t t)
+         '(3 font-lock-keyword-face t t)
+         '(4 font-lock-builtin-face t t))
+   (cons (concat "<!-- \\([^->]\\|>\\|-\\([^-]\\|-[^>]\\)\\)*-->")
+         '(0 font-lock-comment-face t t))
+
+   ;; External Links
+   (list (concat "\\(\\[\\)\\(\\(?:"
+                 (regexp-opt mediawiki-url-protocols)
+                 "\\)://[-A-Za-z0-9._\/~%-+&#?!=()@]+\\)\\(\\(?: [^]\n]*\\)?\\)\\(\\]\\)")
+         '(1 font-lock-builtin-face t t)
+         '(2 font-lock-variable-name-face t t)
+         '(3 font-lock-keyword-face t t)
+         '(4 font-lock-builtin-face t t))
+
+   ;; Wiki links
+   '("\\(\\[\\[\\)\\([^]\n|]*\\)\\(|?\\)\\([^]\n]*\\)\\(\\]\\]\\)"
+     (1 font-lock-builtin-face t t)
+     (2 font-lock-variable-name-face t t)
+     (3 font-lock-builtin-face t t)
+     (4 font-lock-keyword-face t t)
+     (5 font-lock-builtin-face t t))
+
+   ;; Semantic relations
+   '("\\(\\[\\[\\)\\([^]\n|]*\\)\\(::\\)\\([^]\n|]*\\)\\(|?\\)\\([^]\n]*\\)\\(\\]\\]\\)"
+     (1 font-lock-builtin-face t t)
+     (2 font-lock-variable-name-face t t)
+     (3 font-lock-builtin-face t t)
+     (4 font-lock-constant-face t t)
+     (5 font-lock-builtin-face t t)
+     (6 font-lock-keyword-face t t)
+     (7 font-lock-builtin-face t t))
+
+   ;; Wiki variables
+   '("\\({{\\)\\(.+?\\)\\(}}\\)"
+     (1 font-lock-builtin-face t t)
+     (2 font-lock-variable-name-face t t)
+     (3 font-lock-builtin-face t t))
+
+   ;; Semantic variables
+   '("\\({{{\\)\\(.+?\\)\\(}}}\\)"
+     (1 font-lock-builtin-face t t)
+     (2 font-lock-variable-name-face t t)
+     (3 font-lock-builtin-face t t))
+
+   ;; Character entity references
+   (cons "&#?[a-zA-Z0-9]+;" '(0 font-lock-type-face t t))
+
+   ;; Preformatted text
+   (cons "^ .*$" '(0 font-lock-constant-face t t))
+
+   ;; Math environment (uniform highlight only, no TeX markup)
+   (list "<math>\\(\\(\n?.\\)*\\)</math>"
+         '(1 font-lock-keyword-face t t))))
+
+(defvar mediawiki-draft-send-archive t
+  "*Archive the reply.")
+
+(defvar mediawiki-draft-mode-map ())
+
+(defun mediawiki-make-api-url (&optional sitename)
+  (format (concat (mediawiki-site-url (or sitename mediawiki-site))
+                  "api.php")))
+
+(defun mediawiki-api-call (sitename action args)
+  (let* ((raw (url-http-post (mediawiki-make-api-url sitename)
+;;               (concat (mediawiki-make-api-url sitename) "?"
+;;                       (mm-url-encode-www-form-urlencoded
+                        (delq nil
+                              (append args (list (cons "format" "xml")
+                                                 (cons "action" action))))))
+         (result (assoc 'api
+                            (with-temp-buffer
+                              (insert raw)
+                              (xml-parse-region (point-min) (point-max))))))
+    (unless result
+      (error "There was an error parsing the result of the API call"))
+
+    (when (assq 'error (cddr result))
+      (let* ((err (cadr (assq 'error (cddr result))))
+             (err-code (cdr (assq 'code err)))
+             (err-info (cdr (assq 'info err))))
+        (error "The server encountered an error: (%s) %s" err-code err-info)))
+
+
+    (if (cddr result)
+        (let ((action-res (assq (intern action) (cddr result))))
+          (unless action-res
+            (error "Didn't see action name in the result list"))
+
+          action-res)
+      t)))
+
+(defun mediawiki-make-url (title action &optional sitename)
+  (format (concat (mediawiki-site-url (or sitename mediawiki-site))
+                  (if action
+                      mediawiki-argument-pattern
+                    "?title=%s"))
+	  (mm-url-form-encode-xwfu title)
+	  action))
+
+(defun mediawiki-open (name)
+  "Open a wiki page specified by NAME from the mediawiki engine"
+  (interactive "sWiki Page: ")
+  (when (or (not (stringp name))
+            (string-equal "" name))
+    (error "Need to specify a name"))
+  (mediawiki-edit mediawiki-site name))
+
+(defun mediawiki-reload ()
+  (interactive)
+  (let ((title mediawiki-page-title))
+    (if title
+	(mediawiki-open title)
+      (error "Error: %s is not a mediawiki document" (buffer-name)))))
+
+(defun mediawiki-edit (site title)
+  "Edit wiki file with the name of title"
+  (when (not (ring-p mediawiki-page-ring))
+    (setq mediawiki-page-ring (make-ring 30)))
+
+  (with-current-buffer (get-buffer-create
+                        (concat site ": " title))
+    (ring-insert mediawiki-page-ring (current-buffer))
+    (delete-region (point-min) (point-max))
+    (mediawiki-mode)
+    (set-buffer-file-coding-system 'utf-8)
+    (insert (or (mediawiki-get site title) ""))
+
+    (set-buffer-modified-p nil)
+    (setq buffer-undo-list t)
+    (buffer-enable-undo)
+    (mediawiki-pop-to-buffer (current-buffer))
+    (setq mediawiki-page-title title)
+    (goto-char (point-min))))
+
+(defun mediawiki-get-edit-form-vars (str bufname)
+  "Extract the form variables from a page.  This should only be
+called from a buffer in mediawiki-mode as the variables it sets
+there will be local to that buffer."
+
+  (let ((args (mediawiki-get-form-vars str "id" "editform")))
+    (if args
+	(with-current-buffer bufname
+	  (setq mediawiki-edit-form-vars args))
+      (cond
+       ((string-match mediawiki-permission-denied str)
+	(message "Permission Denied"))
+       ((string-match mediawiki-view-source str)
+	(message "Editing of this page is disabled, here is the source"))))))
+
+(defun mediawiki-get-form-vars (str attr val)
+  ;; Find the form
+  (when (string-match
+         (concat "<form [^>]*" attr "=[\"']" val "['\"][^>]*>")
+         str)
+
+    (let* ((start-form (match-end 0))
+           (end-form (when (string-match "</form>" str start-form)
+                       (match-beginning 0)))
+           (form (substring str start-form end-form))
+           (start (string-match
+                   "<input \\([^>]*name=[\"']\\([^\"']+\\)['\"][^>]*\\)>"
+                   form))
+           (vars '(nil)))
+
+      ;; Continue until we can't find any more input elements
+      (while start
+
+        ;; First, capture the place where we'll start next.  Have
+        ;; to do this here since match-end doesn't seem to let you
+        ;; specify the string you were matching against, unlike
+        ;; match-string
+        (setq start (match-end 0))
+
+        ;; Capture the string that defines this element
+        (let ((el (match-string 1 form))
+              ;; get the element name
+              (el-name (match-string 2 form)))
+
+          ;; figure out if this is a submit button and skip it if it is.
+          (when (not (string-match "type=[\"']submit['\"]" el))
+            (add-to-list 'vars
+                         (if (string-match "value=[\"']\\([^\"']*\\)['\"]" el)
+                             (cons el-name (match-string 1 el))
+                           (cons el-name nil)))))
+
+        (setq start
+              (string-match
+               "<input \\([^>]*name=[\"']\\([^\"']+\\)['\"][^>]*\\)>"
+               form start)))
+      vars)))
+
+(defun mediawiki-logged-in-p ()
+  "Returns t if we are logged in already."
+  (not (eq nil mediawiki-site)))         ; FIXME should check cookies
+
+(defun mediawiki-pop-to-buffer (bufname)
+  "Pop to buffer and then execute a hook."
+  (pop-to-buffer bufname)
+  (run-hooks 'mediawiki-pop-buffer-hook))
+
+(defun mediawiki-api-param (v)
+  "Concat a list into a bar-separated string, turn an integer
+into a string, or just return the string"
+  (cond
+   ((integerp v) (int-to-string v))
+   ((stringp v) v)
+   ((listp v) (mapconcat 'identity v "|"))
+   (t (error "Don't know what to do with %s" v))))
+
+(defun mediawiki-api-query-revisions (site titles props &optional limit)
+  "Get a list of revisions and properties for a given page."
+  (cddr (mediawiki-api-call site "query"
+                      (list (cons "prop" (mediawiki-api-param (list "info" "revisions")))
+                            (cons "intoken" (mediawiki-api-param "edit"))
+                            (cons "titles" (mediawiki-api-param titles))
+                            (when limit
+                              (cons "rvlimit" (mediawiki-api-param limit)))
+                            (cons "rvprop" (mediawiki-api-param props))))))
+
+(defun mediawiki-page-get-title (page)
+  "Given a page from a pagelist structure, extract the title."
+  (cdr (assq 'title (cadr page))))
+
+(defun mediawiki-page-get-revision (page rev &optional bit)
+  "Extract a revision from the pagelist structure."
+  (let ((rev (cdr (nth rev (cddr (assq 'revisions (cddr page)))))))
+    (cond
+     ((eq bit 'content)
+      (cadr rev))
+     ((assoc bit (car rev))
+      (cdr (assoc bit (car rev))))
+     (t rev))))
+
+(defun mediawiki-pagelist-find-page (pagelist title)
+  "Extract a page from a pagelist returned by mediawiki"
+  (let ((pl (cddr (assq 'pages pagelist)))
+        page current)
+    (while (and (not page)
+                (setq current (pop pl)))
+      (when (string= (mediawiki-page-get-title current)
+                     title)
+        (setq page current)))
+    page))
+
+(defun mediawiki-api-query-title (site title)
+  "Retrieve the current content of the page."
+  (let* ((pagelist (mediawiki-api-query-revisions
+                    site title
+                    (list "ids" "timestamp" "flags" "comment" "user" "content"))))
+    (mediawiki-pagelist-find-page pagelist title)))
+
+(defun mediawiki-get (site title)
+  (let ((page (mediawiki-api-query-title site title)))
+    (mediawiki-save-metadata site page)
+    (mediawiki-page-get-revision page 0 'content)))
+
+(defun mediawiki-page-get-metadata (page item)
+  (cdr (assoc item (cadr page))))
+
+(defun mediawiki-save-metadata (site page)
+  (setq mediawiki-site site)
+  (setq mediawiki-page-title
+        (mediawiki-page-get-metadata page 'title))
+  (setq mediawiki-edittoken
+        (mediawiki-page-get-metadata page 'edittoken))
+  (setq mediawiki-basetimestamp
+        (mediawiki-page-get-revision page 0 'timestamp))
+  (setq mediawiki-starttimestamp
+        (mediawiki-page-get-metadata page 'starttimestamp)))
+
+(defun mediawiki-save (&optional summary)
+  (interactive "sSummary: ")
+  (if mediawiki-page-title
+      (mediawiki-save-page
+       mediawiki-site
+       mediawiki-page-title
+       summary
+       (buffer-substring-no-properties (point-min) (point-max)))
+    (error "Error: %s is not a mediawiki document" (buffer-name))))
+
+(defun mediawiki-save-and-bury (&optional summary)
+  (interactive "sSummary: ")
+  (mediawiki-save summary)
+  (bury-buffer))
+
+(defun mediawiki-site-extract (sitename index)
+  (let ((bit (nth index (assoc sitename mediawiki-site-alist))))
+    (cond
+     ((eq nil sitename)
+      (error "Sitename isn't set"))
+     ((eq nil bit)
+      (error "Couldn't find a site named: %s" sitename))
+     ((string-match "[^ \t\n]" bit) bit)
+     (nil))))
+
+(defun mediawiki-site-url (sitename)
+  "Get the url for a given site."
+  (mediawiki-site-extract sitename 1))
+
+(defun mediawiki-site-username (sitename)
+  "Get the username for a given site."
+  (or (mediawiki-site-extract sitename 2)
+      (url-user-for-url (mediawiki-site-url sitename))))
+
+(defun mediawiki-site-password (sitename)
+  "Get the password for a given site."
+  (or (mediawiki-site-extract sitename 3)
+      (url-password-for-url (mediawiki-site-url sitename))))
+
+(defun mediawiki-site-first-page (sitename)
+  "Get the password for a given site."
+  (mediawiki-site-extract sitename 4))
+
+(defun mediawiki-do-login (&optional sitename username password)
+  "Use USERNAME and PASSWORD to log into the MediaWiki site and
+get a cookie."
+  (interactive)
+  (when (not sitename)
+    (setq sitename (mediawiki-prompt-for-site)))
+
+  (setq mediawiki-site nil)             ; This wil be set once we are
+                                        ; logged in
+
+  ;; Possibly save info once we have it, eh?
+  (lexical-let* ((user (or (mediawiki-site-username sitename)
+                           username
+                           (read-string "Username: ")))
+                 (pass (or (mediawiki-site-password sitename)
+                           password
+                           (read-passwd "Password: ")))
+                 (sitename sitename)
+                 (args (list (cons "lgname" user)
+                             (cons "lgpassword" pass)))
+                 (result (cadr (mediawiki-api-call sitename "login" args))))
+    (when (string= (cdr (assq 'result result)) "NeedToken")
+      (setq result
+            (cadr (mediawiki-api-call
+                   sitename "login"
+                   (append
+                    args (list (cons "lgtoken"
+                                     (cdr (assq 'token result)))))))))
+    result))
+
+(defun mediawiki-do-logout (&optional sitename)
+  (interactive)
+  (when (not sitename)
+    (setq sitename (mediawiki-prompt-for-site)))
+
+  (mediawiki-api-call sitename "logout" nil)
+  (setq mediawiki-site nil))
+
+(defun mediawiki-save-page (site title summary content)
+  "Save the current page to a MediaWiki wiki."
+  ;; FIXME error checking, conflicts!
+  (mediawiki-api-call site "edit" (list (cons "title" title)
+                                        (cons "text" content)
+                                        (cons "summary" summary)
+                                        (cons "token" mediawiki-edittoken)
+                                        (cons "basetimestamp"
+                                              (or mediawiki-basetimestamp ""))
+                                        (cons "starttimestamp"
+                                              (or mediawiki-starttimestamp ""))))
+  (set-buffer-modified-p nil))
+
+(defun mediawiki-browse (&optional buf)
+  "Open the buffer BUF in a browser. If BUF is not given,
+the current buffer is used."
+  (interactive)
+  (if mediawiki-page-title
+      (browse-url (mediawiki-make-url mediawiki-page-title "view"))))
+
+(defun mediawiki-prompt-for-site ()
+  (let* ((prompt (concat "Sitename"
+                         (when mediawiki-site
+                           (format " (default %s)" mediawiki-site))
+                         ": "))
+         (answer (completing-read prompt mediawiki-site-alist nil t)))
+    (if (string= "" answer)
+        mediawiki-site
+      answer)))
+
+(defun mediawiki-site (&optional site)
+  "Set up mediawiki.el for a site.  Without an argument, use
+`mediawiki-site-default'.  Interactively, prompt for a site."
+  (interactive)
+  (when (not site)
+    (setq site (mediawiki-prompt-for-site)))
+  (when (or (eq nil mediawiki-site)
+            (not (string-equal site mediawiki-site)))
+    (mediawiki-do-login site)
+    (setq mediawiki-site site))
+  (mediawiki-edit site (mediawiki-site-first-page site)))
+
+(defun mediawiki-open-page-at-point ()
+  "Open a new buffer with the page at point."
+  (interactive)
+  (mediawiki-open (mediawiki-page-at-point)))
+
+(defun mediawiki-page-at-point ()
+  "Return the page name under point.  Typically, this means
+anything enclosed in [[PAGE]]."
+  (let ((pos (point))
+        (eol (point-at-eol))
+        (bol (point-at-bol)))
+    (save-excursion
+      (let* ((start  (when (search-backward "[[" bol t)
+                       (+ (point) 2)))
+             (end    (when (search-forward "]]" eol t)
+                       (- (point) 2)))
+             (middle (progn
+                       (goto-char start)
+                       (when (search-forward  "|" end t)
+                         (1- (point)))))
+             (pagename (when (and
+                              (not (eq nil start))
+                              (not (eq nil end))
+                              (<= pos end)
+                              (>= pos start))
+                         (buffer-substring-no-properties
+                          start (or middle end)))))
+        (if (string= "/"
+                     (substring pagename 0 1))
+            (concat mediawiki-page-title pagename)
+          pagename)))))
+
+(defun mediawiki-next-header ()
+  "Move point to the end of the next section header."
+  (interactive)
+  (let ((oldpoint (point)))
+    (end-of-line)
+    (if (re-search-forward "\\(^==+\\).*\\1" (point-max) t)
+        (beginning-of-line)
+      (goto-char oldpoint)
+      (message "No section headers after point."))))
+
+(defun mediawiki-prev-header ()
+  "Move point to the start of the previous section header."
+  (interactive)
+  (unless (re-search-backward "\\(^==+\\).*\\1" (point-min) t)
+    (message "No section headers before point.")))
+
+(defun mediawiki-terminate-paragraph ()	;Version:1.58
+  "In a list, start a new list item. In a paragraph, start a new
+paragraph; if the current paragraph is colon indented, the new
+paragraph will be indented in the same way."
+  (interactive)
+  (let (indent-chars)
+    (save-excursion
+      (beginning-of-line)
+      (while (cond ((looking-at "^$") nil)
+                   ((looking-at "^\\(\\(?: \\|:+\\|[#*]+\\) *\\)")
+                    (setq indent-chars (match-string 1)) nil)
+                   ((eq (point) (point-min)) nil)
+                   ((progn (forward-line -1) t)))
+        t))
+    (newline) (if (not indent-chars) (newline)
+		(insert indent-chars))))
+
+(defun mediawiki-terminate-paragraph-and-indent ()
+  "In a list, start a new list item. In a paragraph, start a new
+paragraph but *,# will be ignored; if the current paragraph is colon
+; indented, the new paragraph will be indented in the same way."
+  (interactive)
+  (let (indent-chars)
+    (save-excursion
+      (beginning-of-line)
+      (while (cond ((looking-at "^$") nil)
+                   ((looking-at "^\\(\\(?: \\|:+\\) *\\)")
+                    (setq indent-chars (match-string 1)) nil)
+                   ((eq (point) (point-min)) nil)
+                   ((progn (forward-line -1) t)))
+        t))
+    (newline)
+    (if (not indent-chars) (newline)
+      (insert indent-chars))))
+
+
+(defun mediawiki-link-fill-nobreak-p ()
+  "When filling, don't break the line for preformatted (fixed-width)
+text or inside a Wiki link.  See `fill-nobreak-predicate'."
+  (save-excursion
+    (let ((pos (point)))
+      (or (eq (char-after (line-beginning-position)) ? )
+          (if (re-search-backward "\\[\\[" (line-beginning-position) t)
+              ;; Break if the link is really really long.
+              ;; You often get this with captioned images.
+              (null (or (> (- pos (point)) fill-column)
+                        (re-search-forward "\\]\\]" pos t))))))))
+
+(defun mediawiki-fill-article ()
+  "Fill the entire article."
+  (interactive)
+  (save-excursion
+    (fill-region (point-min) (point-max))))
+
+(defun mediawiki-unfill-article ()
+  "Undo filling, deleting stand-alone newlines (newlines that do not
+end paragraphs, list entries, etc.)"
+  (interactive)
+  (save-excursion
+    (goto-char (point-min))
+    (while (re-search-forward ".\\(\n\\)\\([^# *;:|!\n]\\|----\\)" nil t)
+      (replace-match " " nil nil nil 1)))
+  (message "Stand-alone newlines deleted"))
+
+(defun mediawiki-draft-reply ()
+  "Open a temporary buffer in mediawiki mode for editing an
+mediawiki draft, with an arbitrary piece of data. After finishing
+the editing |]]:either use \"C-c C-k\" \\[mediawiki-draft-buffer]
+to send the data into the mediawiki-draft-data-file, or send the
+buffer \"C-c\C-c\", to the current article. Check the variable
+mediawiki-draft-send-archive."
+  (interactive)
+  (mediawiki-reply-at-point-simple)
+  (beginning-of-line 1)
+  (kill-line nil)
+  (save-excursion
+	(window-configuration-to-register mediawiki-draft-register)
+	(let ((buf (get-buffer-create mediawiki-draft-buffer)))
+	  (switch-to-buffer-other-window buf)
+	  (mediawiki-mode)
+	  (if mediawiki-reply-with-quote
+              (progn
+		(insert "{{Quotation|")
+		(yank)
+		(insert "'''Re: ")
+		(insert-register mediawiki-draft-reply-register 1)
+		(insert "''' |~~~~}}")
+		(backward-char 7))
+            (when mediawiki-reply-with-hline
+              (insert "----")
+              (newline 1))
+            (yank)
+            (end-of-line 1))
+	  (message " C-c C-k sends to draft, C-c C-c sends to org buffer."))))
+
+(defun mediawiki-reply-at-point-simple ()
+  "Very simple function to reply to posts in the discussion forum. You have to set
+the point around the signature, then the functions inserts the following
+:'''Re: [[User:foo]]'''."
+  (interactive)
+  (beginning-of-line 1)
+  (if mediawiki-english-or-german
+      (progn
+        (search-forward "(UTC)")
+        (search-backward "[[User:"))
+    (search-forward "(CET)")
+    (search-backward "[[Benutzer:"))
+  (if mediawiki-user-simplify-signature
+      (mark-word 2)
+    (mark-word 3))
+  (copy-to-register mediawiki-draft-reply-register (region-beginning) (region-end) nil)
+  (end-of-line 1)
+  (mediawiki-terminate-paragraph-and-indent)
+  (insert ":'''Re: ")
+  (insert-register mediawiki-draft-reply-register 1)
+  (if mediawiki-user-simplify-signature
+      (insert "|]]''' ")
+    (insert "]]''' ")))
+
+(defmacro mediawiki-goto-relative-page (direction)
+  `(let ((buff (ring-ref mediawiki-page-ring
+                        (setq mediawiki-page-ring-index
+                              (,direction mediawiki-page-ring-index 1)))))
+     (while (not (buffer-live-p buff))
+       (setq buff
+             (ring-ref mediawiki-page-ring
+                       (setq mediawiki-page-ring-index
+                             (,direction mediawiki-page-ring-index 1)))))
+     (mediawiki-pop-to-buffer buff)))
+
+(defun mediawiki-goto-previous-page ()
+  "Pop up the previous page being editted."
+  (interactive)
+  (mediawiki-goto-relative-page -))
+
+(defun mediawiki-goto-next-page ()
+  "Pop up the previous page being editted."
+  (interactive)
+  (mediawiki-goto-relative-page +))
+
+(defun mediawiki-goto-relative-link (&optional backward)
+  "Move point to a link.  If backward is t, will search backwards."
+  (let* ((search (if backward 're-search-backward
+                   're-search-forward))
+         (limitfunc (if backward 'point-min
+                      'point-max))
+         (point (funcall search "\\[\\[.+\\]\\]" (funcall limitfunc) t)))
+    (when point
+      (let ((point (match-beginning 0)))
+        (goto-char (+ point 2))))))
+
+(defun mediawiki-goto-next-link ()
+  (interactive)
+  (mediawiki-goto-relative-link))
+
+(defun mediawiki-goto-prev-link ()
+  (interactive)
+  (mediawiki-goto-relative-link t))
+
+(defvar wikipedia-enumerate-with-terminate-paragraph nil
+"*Before insert enumerate/itemize do \\[wikipedia-terminate-paragraph].")
+
+(defun mediawiki-insert-enumerate ()
+"Primitive Function for inserting enumerated items, check the
+variable wikipedia-enumerate-with-terminate-paragraph. Note however
+that the function \\[wikipedia-terminate-paragraph] does not work very
+well will longlines-mode."
+  (interactive)
+  (if mediawiki-enumerate-with-terminate-paragraph
+      (progn
+        (mediawiki-terminate-paragraph)
+        (insert "#"))
+    (newline nil)
+    (insert ":#")))
+
+(defun mediawiki-insert-itemize ()
+  "Primitive Function for inserting no enumerated items, check
+the variable mediawiki-enumerate-with-terminate-paragraph. Note
+however that the function \\[mediawiki-terminate-paragraph] does
+not work very well will longlines-mode."
+  (interactive)
+  (if mediawiki-enumerate-with-terminate-paragraph
+      (progn
+        (mediawiki-terminate-paragraph)
+        (insert "*"))
+    (newline nil)
+    (insert ":*")))
+
+(defun mediawiki-insert (pre post)
+  (if (or (and (boundp 'zmacs-region-active-p) zmacs-region-active-p)
+          (and (boundp 'transient-mark-mode) transient-mark-mode mark-active))
+      (let ((beg (region-beginning))
+            (end (region-end)))
+        (save-excursion
+          (goto-char beg)
+          (insert pre)
+          (goto-char (+ end (string-width pre)))
+          (insert post)))
+    (insert (concat pre " " post))
+    (backward-char (+ 1 (string-width post)))))
+
+(defun mediawiki-insert-strong-emphasis ()
+  "Insert strong emphasis italics via four
+apostrophes (e.g. ''''FOO''''.) When mark is active, surrounds
+region."
+  (interactive)
+  (mediawiki-insert "''''" "''''"))
+
+(defun mediawiki-insert-bold ()
+  "Insert bold via three apostrophes (e.g. '''FOO'''.)
+When mark is active, surrounds region."
+  (interactive)
+  (mediawiki-insert "'''" "'''"))
+
+
+(defun mediawiki-insert-italics ()
+  "Insert bold via TWO apostrophes (e.g. ''FOO''.) When mark is active,
+surrounds region."
+  (interactive)
+  (mediawiki-insert "''" "''"))
+
+(defun mediawiki-insert-quotation-with-signature ()
+  "Insert bold via TWO apostrophes (e.g. ''FOO''.) When mark is active,
+surrounds region."
+  (interactive)
+  (mediawiki-insert "{{Quotation|}}" "{{~~~~}}"))
+
+(defun mediawiki-insert-quotation ()
+  "Quotation box of the form {{Quotation}}{{}}. When mark is active,
+surrounds region."
+  (interactive)
+  (mediawiki-insert "{{Quotation|}}{{" "}}"))
+
+(defun mediawiki-insert-bible-verse-template ()
+  "Insert a template for the quotation of bible verses."
+  (interactive)
+  (insert "({{niv|")
+  (let ((name    (read-string "Name: ")))
+    (insert (concat name "|"))
+    (let ((verse (read-string "Verse: ")))
+      (insert (concat verse "|" name " " verse "}})")))))
+
+(defun mediawiki-insert-user ()
+  "Inserts, interactively a user name [[User:foo]]"
+  (interactive)
+  (if mediawiki-english-or-german
+      (let ((user (read-string "Name of user: " )))
+        (insert (concat "[[User:" user "|" user "]]"))))
+  (let ((user (read-string "Name des Benutzers: " )))
+    (insert (concat "[[Benutzer:" user "|" user "]]"))))
+
+(defun mediawiki-insert-reply-prefix ()
+  "Quotation box of the form {{Quotation}}{{}}. When mark is active,
+surrounds region."
+  (interactive)
+  (beginning-of-line 1)
+  (search-forward "[[")
+  (backward-char 2)
+  (mark-sexp 1)
+  (copy-to-register mediawiki-draft-reply-register (region-beginning) (region-end) nil)
+  (end-of-line 1)
+  (mediawiki-terminate-paragraph)
+  (beginning-of-line 1)
+  (kill-line nil)
+  (insert "----")
+  (newline 1)
+  (yank)
+  (insert ":'''Re: ")
+  (insert-register mediawiki-draft-reply-register 1)
+  (insert "''' ")
+  (end-of-line 1))
+
+(defun mediawiki-insert-header ()
+  "Insert subheader  via  == (e.g. == FOO ==.)"
+  (interactive)
+  (mediawiki-insert "==" "=="))
+
+(defun mediawiki-insert-link ()
+  "Insert link via [[ (e.g. [[FOO]].) When mark is active, surround region."
+  (interactive)
+  (mediawiki-insert "[[" "]]"))
+
+(defun mediawiki-insert-link-www ()
+  "Insert link via [[ (e.g. [http://FOO].) When mark is active, surround region."
+  (interactive)
+  (mediawiki-insert "[http://" "]"))
+
+(defun mediawiki-insert-image ()
+  "Insert link image  [[ (e.g. [[Image:FOO]].) Check the variable
+mediawiki-english-or-german. When mark is active, surround region."
+  (interactive)
+  (mediawiki-insert (if mediawiki-english-or-german
+                        "[[Image:"
+                      "[[Bild:") "]]"))
+
+(defun mediawiki-insert-audio ()
+  "Insert link image  [[ (e.g. [[Image:FOO]].) Check the variable
+mediawiki-english-or-german. When mark is active, surround region."
+  (interactive)
+  (mediawiki-insert (if mediawiki-english-or-german
+                        "[[Media:"
+                      "[[Bild:") "]]"))
+
+(defun mediawiki-insert-signature ()
+  "Insert \"~~~~:\"  "
+  (interactive)
+  (insert "~~~~: "))
+
+(defun mediawiki-insert-hline ()
+  "Insert \"----\"  "
+  (interactive)
+  (insert "\n----\n"))
+
+(defun mediawiki-unfill-paragraph-or-region ()
+  "Unfill region, this function does NOT explicitly search for \"soft newlines\"
+as does mediawiki-unfill-region."
+  (interactive)
+  (set (make-local-variable 'paragraph-start) "[ \t\n\f]")
+  (set (make-local-variable 'paragraph-start)
+       "\\*\\| \\|#\\|;\\|:\\||\\|!\\|$")
+  (set-fill-prefix)
+  (beginning-of-line 1)
+
+  (if use-hard-newlines
+      (progn
+        (set (make-local-variable 'use-hard-newlines) nil)
+        (set (make-local-variable 'sentence-end-double-space) t))
+    (set (make-local-variable 'sentence-end-double-space) nil)
+    (set (make-local-variable 'use-hard-newlines) t))
+  (let ((fill-column (point-max)))
+    (if (fboundp 'fill-paragraph-or-region)
+        (fill-paragraph-or-region nil)
+      (fill-paragraph nil))))
+
+(defun mediawiki-start-paragraph ()
+  (interactive)
+  (set (make-local-variable 'paragraph-start)
+       "\\*\\| \\|#\\|;\\|:\\||\\|!\\|$"))
+
+(defun mediawiki-hardlines ()
+"Set use-hard-newlines to NIL."
+  (interactive)
+  (setq use-hard-newlines nil))
+
+(defun mediawiki-next-long-line ()
+  "Move forward to the next long line with column-width greater
+than `fill-column'.
+
+TODO: When function reaches end of buffer, save-excursion to
+starting point. Generalise to make `previous-long-line'."
+  (interactive)
+  ;; global-variable: fill-column
+  (if (= (forward-line) 0)
+	  (let ((line-length
+			 (save-excursion
+			   (end-of-line)
+			   (current-column))))
+		(if (<= line-length fill-column)
+			(mediawiki-next-long-line)
+		  (message "Long line found")))
+	;; Stop, end of buffer reached.
+ 	(error "Long line not found")))
+
+(defun mediawiki-unfill-paragraph-simple ()
+  "A very simple function for unfilling a paragraph."
+  (interactive)
+  (let ((fill-column (point-max)))
+    (fill-paragraph nil)))
+
+;; See http://staff.science.uva.nl/~dominik/Tools/outline-magic.el
+(defun mediawiki-outline-magic-keys ()
+  (interactive)
+  (unless  (featurep 'xemacs)
+    (local-set-key [(shift iso-lefttab)] 'outline-cycle)
+    (local-set-key [iso-left-tab] 'outline-cycle))
+  (local-set-key [(meta left)]  'outline-promote)
+  (local-set-key [(meta right)] 'outline-demote)
+  (local-set-key [(shift return)] 'newline-and-indent)
+  (local-set-key [(control left)]  'mediawiki-simple-outline-promote)
+  (local-set-key [(control right)] 'mediawiki-simple-outline-demote)
+  (local-set-key [(control up)] 'outline-move-subtree-up)
+  (local-set-key [(control down)] 'outline-move-subtree-down))
+(add-hook 'mediawiki-mode-hook (lambda () (outline-minor-mode nil)))
+(add-hook 'outline-minor-mode-hook 'mediawiki-outline-magic-keys)
+
+(defun mediawiki-enhance-indent ()
+  (interactive)
+  (string-rectangle (region-beginning) (region-end) ":"))
+
+(defun mediawiki-yank-prefix ()
+  (interactive)
+  (string-rectangle (region-beginning) (region-end) ":"))
+
+(defun mediawiki-simple-outline-promote ()
+  "Function simple deletes \"=\" and the end and the beginning of line,
+does not promote the whole tree!"
+  (interactive)
+  (save-excursion
+    (beginning-of-line 1)
+    (search-forward "=")
+    (delete-char 1 nil)
+    (end-of-line 1)
+    (search-backward "=")
+    (delete-char 1 nil)))
+
+(defun mediawiki-simple-outline-demote ()
+  "Function simple adds \"=\" and the end and the beginning of line,
+does not promote the whole tree!"
+  (interactive)
+  (save-excursion
+    (beginning-of-line 1)
+    (search-forward "=")
+    (insert "=")
+    (end-of-line 1)
+    (search-backward "=")
+    (insert "=")))
+
+(defun mediawiki-rename-buffer ()
+  "Make sure that the option UNIQUE is used."
+  (interactive)
+  (rename-buffer (read-string "Name of new buffer (unique): " ) 1))
+
+(defsubst mediawiki-draft-time-to-seconds (time)
+  "Convert TIME to a floating point number."
+  (+ (* (car time) 65536.0)
+     (cadr time)
+     (/ (or (car (cdr (cdr time))) 0) 1000000.0)))
+
+(defsubst mediawiki-draft-mail-date (&optional rfc822-p)
+  "Return a simple date.  Nothing fancy."
+  (if rfc822-p
+      (format-time-string "%a, %e %b %Y %T %z" (current-time))
+    (format-time-string "%c" (current-time))))
+
+(defun mediawiki-draft-buffer-desc ()
+  "Using the first line of the current buffer, create a short description."
+  (buffer-substring (point-min)
+		    (save-excursion
+		      (goto-char (point-min))
+		      (end-of-line)
+		      (if (> (- (point) (point-min)) 60)
+			  (goto-char (+ (point-min) 60)))
+		      (point))))
+
+(defun mediawiki-draft-append-to-file ()
+  "Add a header together with a subject to the text and add it to the
+draft file. It might be better if longlines-mode is off."
+  (let ((text (buffer-string)))
+    (with-temp-buffer
+      (insert (concat "\n\n"  mediawiki-draft-leader-text "Draft: "
+                      (read-string "Enter Subject: ") " "
+                      (current-time-string) " "
+                      mediawiki-draft-leader-text
+                      "\n\n\f\n\n" text "\n\f\n"))
+      (if (not (bolp))
+          (insert "\n\n"))
+      (if (find-buffer-visiting mediawiki-draft-data-file)
+          (let ((mediawiki-draft-text (buffer-string)))
+            (set-buffer (get-file-buffer mediawiki-draft-data-file))
+            (save-excursion
+              (goto-char (point-max))
+              (insert (concat "\n" mediawiki-draft-text "\n"))
+              (save-buffer)))
+        (append-to-file (point-min) (point-max) mediawiki-draft-data-file)))))
+
+;;;###autoload
+(defun mediawiki-draft ()
+  "Open a temporary buffer in wikipedia mode for editing an wikipedia
+ draft, which an arbitrary piece of data. After finishing the editing
+ either use C-c C-k \\[mediawiki-draft-buffer] to send the data into
+ the mediawiki-draft-data-file, or send  the buffer using C-x C-s
+\\[mediawiki-save]  and insert it later into a wikipedia article."
+  (interactive)
+  (window-configuration-to-register mediawiki-draft-register)
+  (let ((buf (get-buffer-create mediawiki-draft-buffer)))
+    (switch-to-buffer-other-window buf)
+    (mediawiki-mode)
+    (message " C-c C-k sends to draft file, C-c C-c sends to org buffer.")))
+
+;;;###autoload
+(defun mediawiki-draft-page ()
+  (interactive)
+  (mark-page)
+  (copy-region-as-kill (region-beginning) (region-end))
+  (mediawiki-draft)
+  (yank nil))
+
+(defun mediawiki-draft-region (&optional beg end)
+  "Mediawiki-Draft the data from BEG to END.
+If called from within the mediawiki-draft buffer, BEG and END are ignored,
+and the entire buffer will be mediawiki-drafted.  If called from any other
+buffer, that region, plus any context information specific to that
+region, will be mediawiki-drafted."
+  (interactive)
+  (let ((b (or beg (min (point) (or (mark) (point-min)))))
+	(e (or end (max (point) (or (mark) (point-max))))))
+    (save-restriction
+      (narrow-to-region b e)
+      (run-hook-with-args-until-success 'mediawiki-draft-handler-functions)
+    (when (equal mediawiki-draft-buffer (buffer-name))
+      (kill-buffer (current-buffer))
+      (jump-to-register mediawiki-draft-register)))))
+
+;;;###autoload
+(defun mediawiki-draft-buffer ()
+  "Mediawiki-draft-buffer sends the contents of the current (temporary)
+buffer to the mediawiki-draft-buffer, see the variable
+mediawiki-draft-data-file."
+  (interactive)
+  (mediawiki-draft-region  (point-min) (point-max)))
+
+(defun mediawiki-draft-clipboard ()
+  "Mediawiki-Draft the contents of the current clipboard.
+Most useful for mediawiki-drafting things from Netscape or other X Windows
+application."
+  (interactive)
+  (with-temp-buffer
+    (insert (x-get-clipboard))
+    (run-hook-with-args-until-success 'mediawiki-draft-handler-functions)))
+
+(defun mediawiki-draft-view-draft ()
+  "Simple shortcut to visit the file, which contains the wikipedia drafts."
+  (interactive)
+  (find-file mediawiki-draft-data-file))
+
+(defun mediawiki-mark-section ()
+  "Set mark at end of current logical section, and point at top."
+  (interactive)
+  (re-search-forward (concat  "== "  "[a-z,A-z \t]*" " =="))
+  (re-search-backward "^")
+  (set-mark (point))
+  (re-search-backward (concat "== "  "[a-z,A-z \t]*" " "))
+  (when (fboundp 'zmacs-activate-region)
+    (zmacs-activate-region)))
+
+(defun mediawiki-mark-signature ()
+  "Set mark at end of current logical section, and point at top."
+  (interactive)
+  (re-search-forward "]]") ;;[[ ]]
+  (re-search-backward "^")
+  (set-mark (point))
+  (re-search-backward "[[")
+  (when (fboundp 'zmacs-activate-region)
+    (zmacs-activate-region)))
+
+(defun mediawiki-draft-copy-page-to-register ()
+  "Copy a page via the mediawiki-draft-register."
+  (interactive)
+  (save-excursion
+    (narrow-to-page nil)
+    (copy-to-register mediawiki-draft-page (point-min) (point-max) nil)
+    (message "draft page copied to wikipedia register mediawiki-draft-page.")
+    (widen)))
+
+(defun mediawiki-draft-yank-page-to-register ()
+  "Insert a page via the mediawiki-draft-register."
+  (interactive)
+  (insert-register mediawiki-draft-page nil))
+
+(defun mediawiki-draft-send (target-buffer)
+  "Copy the current page from the mediawiki draft file to
+TARGET-BUFFER.  Check the variable mediawiki-draft-send-archive.
+If it is t, then additionally the text will be archived in the
+draft.wiki file. Check longlines-mode, it might be better if it
+is set off."
+  (interactive "bTarget buffer: ")
+  (mediawiki-draft-copy-page-to-register)
+  (switch-to-buffer target-buffer)
+  (end-of-line 1)
+  (newline 1)
+  (mediawiki-draft-yank-page-to-register)
+  (message "The page has been sent (copied) to the mozex file!")
+  (switch-to-buffer "*MW-Draft*")
+  (when mediawiki-draft-send-archive
+    (let ((text (buffer-string)))
+      (with-temp-buffer
+	(insert (concat "\n\n" mediawiki-draft-leader-text)
+		(insert-register mediawiki-draft-reply-register 1)
+		(insert (concat " " (current-time-string) " " 
+				mediawiki-draft-leader-text  "\n\n\f\n\n"
+				text "\n\f\n"))
+		(if (not (bolp))
+		    (insert "\n\n"))
+		(if (find-buffer-visiting mediawiki-draft-data-file)
+		    (let ((mediawiki-draft-text (buffer-string)))
+		      (set-buffer (get-file-buffer mediawiki-draft-data-file))
+		      (save-excursion
+			(goto-char (point-max))
+			(insert (concat "\n" mediawiki-draft-text "\n"))
+			(save-buffer)))
+		  (append-to-file (point-min) (point-max)
+				  mediawiki-draft-data-file)))))
+    (when (equal mediawiki-draft-buffer (buffer-name))
+      (kill-buffer (current-buffer)))
+    (switch-to-buffer target-buffer)))
+
+(define-derived-mode mediawiki-draft-mode text-mode "MW-Draft"
+  "Major mode for output from \\[mediawiki-draft].
+\\<mediawiki-draft-mode-map> This buffer is used to collect data that
+you want mediawiki-draft.  Just hit \\[mediawiki-draft-region] when
+you're done entering, and it will go ahead and file the data for
+latter retrieval, and possible indexing.
+\\{mediawiki-draft-mode-map}"
+  (kill-all-local-variables)
+  (indented-text-mode)
+  (define-key mediawiki-draft-mode-map "\C-c\C-k" 'mediawiki-draft-buffer)
+  (define-key mediawiki-draft-mode-map "\C-c\C-d" 'mediawiki-draft-buffer))
+
+(define-derived-mode mediawiki-mode text-mode "MW"
+  "Major mode for editing articles written in the markup language
+used by Mediawiki.
+
+Wikipedia articles are usually unfilled: newline characters are not
+used for breaking paragraphs into lines. Unfortunately, Emacs does not
+handle word wrapping yet. As a workaround, wikipedia-mode turns on
+longlines-mode automatically. In case something goes wrong, the
+following commands may come in handy:
+
+\\[mediawiki-fill-article] fills the buffer.
+\\[mediawiki-unfill-article] unfills the buffer.
+
+Be warned that function can be dead  slow, better use mediawiki-unfill-paragraph-or-region.
+\\[mediawiki-unfill-paragraph-or-region] unfills the paragraph
+\\[mediawiki-unfill-paragraph-simple] doehe same but simpler.
+
+The following commands put in markup structures.
+\\[mediawiki-insert-strong-emphasis] inserts italics
+\\[mediawiki-insert-bold] inserts bold text
+\\[mediawiki-insert-italics] italics
+\\[mediawiki-insert-header] header
+\\[mediawiki-insert-link] inserts a link
+
+The following commands are also defined:
+\\[mediawiki-insert-user] inserts user name
+\\[mediawiki-insert-signature] inserts ~~~~
+\\[mediawiki-insert-enumerate] inserts enumerate type structures
+\\[mediawiki-insert-itemize] inserts itemize type structures
+\\[mediawiki-insert-hline] inserts a hline
+
+The draft functionality
+\\[mediawiki-draft]
+\\[mediawiki-draft-region]
+\\[mediawiki-draft-view-draft]
+\\[mediawiki-draft-page]
+\\[mediawiki-draft-buffer]
+
+Replying and sending functionality
+\\[mediawiki-reply-at-point-simple]
+\\[mediawiki-draft-reply]
+
+The register functionality
+\\[mediawiki-copy-page-to-register]
+\\[defun mediawiki-insert-page-to-register]
+
+Some simple editing commands.
+\\[mediawiki-enhance-indent]
+\\[mediawiki-yank-prefix]
+\\[mediawiki-unfill-paragraph-or-region]
+
+\\[mediawiki-terminate-paragraph]     starts a new list item or paragraph in a context-aware manner.
+\\[mediawiki-next-header]     moves to the next (sub)section header.
+\\[mediawiki-prev-header]     moves to the previous (sub)section header."
+
+  (make-local-variable 'change-major-mode-hook)
+  (make-local-variable 'mediawiki-edittoken)
+  (make-local-variable 'mediawiki-starttimestamp)
+  (make-local-variable 'mediawiki-basetimestamp)
+  (make-local-variable 'mediawiki-site)
+  (make-local-variable 'mediawiki-edit-form-vars)
+  (make-local-variable 'mediawiki-page-title)
+  (set (make-local-variable 'adaptive-fill-regexp) "[ ]*")
+  (set (make-local-variable 'comment-start-skip) "\\(?:<!\\)?-- *")
+  (set (make-local-variable 'comment-end-skip) " *--\\([ \n]*>\\)?")
+  (set (make-local-variable 'comment-start) "<!-- ")
+  (set (make-local-variable 'comment-end) " -->")
+  (set (make-local-variable 'paragraph-start)
+       "\\*\\| \\|#\\|;\\|:\\||\\|!\\|$")
+  (set (make-local-variable 'sentence-end-double-space) nil)
+  (set (make-local-variable 'font-lock-multiline) t)
+  (set (make-local-variable 'font-lock-defaults)
+       '(mediawiki-font-lock-keywords t nil nil nil))
+  (set (make-local-variable 'fill-nobreak-predicate)
+       'mediawiki-link-fill-nobreak-p)
+  (set (make-local-variable 'auto-fill-inhibit-regexp) "^[ *#:|;]")
+
+  ;; Support for outline-minor-mode. No key conflicts, so we'll use
+  ;; the normal outline-mode prefix.
+  (set (make-local-variable 'outline-regexp) "==+")
+  (when (boundp 'outline-minor-mode-prefix)
+    (set (make-local-variable 'outline-minor-mode-prefix) "\C-c\C-o"))
+; (set (make-local-variable 'outline-regexp) "=+")
+; (set (make-local-variable 'outline-regexp) ":")
+
+  ;; Turn on the Imenu automatically.
+  (when menu-bar-mode
+    (set (make-local-variable 'imenu-generic-expression)
+         mediawiki-imenu-generic-expression)
+    (imenu-add-to-menubar "Contents"))
+
+  (let ((map (make-sparse-keymap "mediawiki")))
+    (define-key mediawiki-mode-map [menu-bar mediawiki]
+      (cons "MediaWiki" map))
+    (define-key map [unfill-article]
+      '("Unfill article" . mediawiki-unfill-article))
+    (define-key map [fill-article]
+      '("Fill article" . mediawiki-fill-article))
+    (define-key map [separator-fill] '("--"))
+    (define-key map [next-header]
+      '("Next header" . mediawiki-next-header))
+    (define-key map [prev-header]
+      '("Previous header" . mediawiki-prev-header))
+    (define-key map [separator-header] '("--"))
+    (define-key map [outline]
+      '("Toggle Outline Mode..." . outline-minor-mode))
+
+    (modify-syntax-entry ?< "(>" mediawiki-mode-syntax-table)
+    (modify-syntax-entry ?> ")<" mediawiki-mode-syntax-table)
+
+    (define-key mediawiki-mode-map "\M-n" 'mediawiki-next-header)
+    (define-key mediawiki-mode-map "\C-c\C-n" 'mediawiki-next-long-line)
+    (define-key mediawiki-mode-map "\M-p" 'mediawiki-prev-header)
+    (define-key mediawiki-mode-map [(meta down)] 'mediawiki-next-header)
+    (define-key mediawiki-mode-map [(meta up)]   'mediawiki-prev-header)
+    (define-key mediawiki-mode-map "\C-j" 'mediawiki-terminate-paragraph)
+
+    (define-key mediawiki-mode-map "\C-c\C-q" 'mediawiki-unfill-article)
+    (define-key mediawiki-mode-map "\C-c\M-q" 'mediawiki-fill-article)
+    (define-key mediawiki-mode-map "\M-u" 'mediawiki-unfill-paragraph-or-region)
+    (define-key mediawiki-mode-map "\C-c\C-u" 'mediawiki-unfill-paragraph-simple)
+    (define-key mediawiki-mode-map "\C-c\C-f\C-s" 'mediawiki-insert-strong-emphasis)
+    (define-key mediawiki-mode-map "\C-c\C-f\C-b" 'mediawiki-insert-bold)
+    (define-key mediawiki-mode-map "\C-c\C-f\C-i" 'mediawiki-insert-italics)
+    (define-key mediawiki-mode-map "\C-c\C-f\C-e" 'mediawiki-insert-header)
+    (define-key mediawiki-mode-map "\C-c\C-f\C-l" 'mediawiki-insert-link)
+    (define-key mediawiki-mode-map "\C-c\C-f\C-u" 'mediawiki-insert-user)
+    (define-key mediawiki-mode-map "\C-c\C-f\C-q" 'mediawiki-insert-quotation)
+    (define-key mediawiki-mode-map "\C-c\C-f\C-v" 'mediawiki-insert-bible-verse-template)
+    (define-key mediawiki-mode-map "\C-c\C-w" 'mediawiki-insert-signature)
+    (define-key mediawiki-mode-map "\C-c\C-l" 'mediawiki-insert-hline)
+    (define-key mediawiki-mode-map [(meta f7)] 'mediawiki-draft)
+    (define-key mediawiki-mode-map [(meta f8)] 'mediawiki-reply-at-point-simple)
+    (define-key mediawiki-mode-map [(meta f9)] 'mediawiki-draft-view-draft)
+    (define-key mediawiki-mode-map "\C-c\C-r" 'mediawiki-reply-at-point-simple)
+    (define-key mediawiki-mode-map "\C-cr" 'mediawiki-draft-region)
+    (define-key mediawiki-mode-map [(meta r)] 'mediawiki-draft-reply)
+    (define-key mediawiki-mode-map "\C-c\C-m" 'mediawiki-draft)
+    (define-key mediawiki-mode-map "\C-c\C-b" 'mediawiki-draft-region)
+    (define-key mediawiki-mode-map "\C-c\C-d" 'mediawiki-draft-buffer)
+    (define-key mediawiki-mode-map "\C-c\C-k" 'mediawiki-draft-buffer)
+    (define-key mediawiki-mode-map "\C-c\C-p" 'mediawiki-draft-copy-page-to-register)
+    (define-key mediawiki-mode-map "\C-c\C-c" 'mediawiki-draft-send)
+    (define-key mediawiki-mode-map "\C-c\C-s" 'mediawiki-draft-yank-page-to-register)
+
+    (define-key mediawiki-mode-map [(control meta prior)] 'mediawiki-enhance-indent)
+    (define-key mediawiki-mode-map [(control meta next)] 'mediawiki-yank-prefix)
+    (define-key mediawiki-mode-map [(meta return)] 'mediawiki-insert-enumerate)
+    (define-key mediawiki-mode-map [(meta control return)] 'mediawiki-insert-enumerate-nonewline)
+    ;; private setting
+    (define-key mediawiki-mode-map [(shift return)] 'newline-and-indent)
+    (define-key mediawiki-mode-map "\C-\\" 'mediawiki-insert-itemize)
+    (define-key mediawiki-mode-map [(control return)] 'mediawiki-insert-itemize)
+    (define-key mediawiki-mode-map "\C-ca" 'auto-capitalize-mode)
+    (define-key mediawiki-mode-map "\C-ci" 'set-input-method)
+    (define-key mediawiki-mode-map "\C-ct" 'toggle-input-method)
+
+    (define-key mediawiki-mode-map [(backtab)] 'mediawiki-goto-prev-link)
+    (define-key mediawiki-mode-map [(tab)]     'mediawiki-goto-next-link)
+    (define-key mediawiki-mode-map "\M-g"      'mediawiki-reload)
+    (define-key mediawiki-mode-map "\C-x\C-s"  'mediawiki-save)
+    (define-key mediawiki-mode-map "\C-c\C-c"  'mediawiki-save-and-bury)
+    (define-key mediawiki-mode-map "\C-x\C-w"  'mediawiki-save-as)
+    (define-key mediawiki-mode-map "\C-c\C-o"  'mediawiki-open)
+    (define-key mediawiki-mode-map "\M-p"
+      'mediawiki-goto-previous-page)
+    (define-key mediawiki-mode-map "\M-n"      'mediawiki-goto-next-page)
+    (define-key mediawiki-mode-map [(control return)]
+      'mediawiki-open-page-at-point)))
+
+;; (defvar mw-pagelist-mode-map
+;;   (let ((map (make-sparse-keymap)))
+;;     (suppress-keymap map)
+;;     (define-key map [(return)] 'mw-pl-goto-page-at-point)
+;;     (define-key map "n"        'mw-pl-page-down)
+;;     (define-key map "C-v"      'mw-pl-page-down)
+;;     (define-key map [(next)]  'mw-pl-page-down)
+;;     (define-key map "p"        'mw-pl-page-up)
+;;     (define-key map "M-v"      'mw-pl-page-up)
+;;     (define-key map [(prior)]  'mw-pl-page-up)))
+
+;; (define-derived-mode mw-pagelist-mode special-mode "MW-PageList")
+
+(provide 'mediawiki)
+
+;; Local Variables:
+;; time-stamp-pattern: "20/^;; Last Modified: <%%>$"
+;; End:
+
+;;; mediawiki.el ends here