12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397 |
- ; $Id: post.el,v 2.4 2004/07/23 23:13:17 rreid Exp rreid $
- ;; post.el --- Use (X?)Emacs(client) as an external editor for mail and news.
-
- ;;; Authors: Eric Kidd <eric.kidd@pobox.com>,
- ;;; Dave Pearson <davep@davep.org>,
- ;;; Rob Reid <reid@astro.utoronto.ca>,
- ;;; Roland Rosenfeld <roland@spinnaker.de>
- ;; This is free software distributed under the GPL, yadda, yadda, yadda.
- ;; It has no warranty. See the GNU General Public License for more
- ;; information. Send us your feature requests and patches, and we'll try
- ;; to integrate everything.
- ;;; Maintainer: Rob Reid <reid@astro.utoronto.ca>
- ;;; Keywords: mail
- ;;; Commentary:
- ;; This is a major mode for use with Mutt, the spiffy *nix mailreader du jour
- ;; (See http://www.mutt.org/), slrn, the spiffy *nix newsreader du jour, or
- ;; whatever you can get it to work with. To use this mode, add the following
- ;; line to the .emacs file in your home directory:
- ;;
- ;; (load "/your/local/path/to/this/file/post")
- ;;
- ;; Note that you can omit the ".el" from the file name when calling load.
- ;;
- ;; If you want to make it available to all your users, type \C-h v
- ;; load-path RET, pick an appropriate directory for post.el, and modify
- ;; your sitewide default.el to (require 'post).
- ;;
- ;; You may find the latest version of this mode at
- ;; http://astro.utoronto.ca/~reid/mutt/
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;; BUGS:
- ;;
- ;; Rob: I predict that some buffers (*Original*<2>, *Composing*<2>?)
- ;; will be left behind if you edit more than one message at a time.
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;
- ;;; Thanks
- ;;;
- ;;; Dave Pearson: Code, feature ideas, Mutt experience. Many thanks!
- ;;; Louis Theran: Encouragement to make Mutt mode work like Emacs MUAs.
- ;;; Ronald: Enlightening gripes about what Emacs should do, but doesn't.
- ;;; Robert Napier: Bug reports about font-lock mode, fancy wrapping.
- ;;; Kevin Rodgers: Answered RR's question on gnu.emacs.help on
- ;;; overwriting server-process-filter's annoying message at startup.
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;
- ;;; Revision History
- ;;;
- ;;; $Log: post.el,v $
- ;;; Revision 2.401 2004/07/23 16:27:29 rreid
- ;;; Fixed post-delete-quoted-signatures to not remove sneaky things like quoted
- ;;; double dash arrows. Thanks go to Felix Klee for a clear bug report.
- ;;;
- ;;; Revision 2.4 2002/04/22 22:04:29 reid
- ;;; Tweaked post-emoticon-pattern yet again. Made cl mandatory for all
- ;;; versions of emacs. (Thanks to Eric Dorland and Mike Schiraldi for bug
- ;;; reports.) Fixed post-unquote-region. (Thanks to Mike Schiraldi for the
- ;;; bug report.)
- ;;;
- ;;; Revision 2.3 2002/04/21 20:13:55 reid
- ;;; Improved post-emoticon-pattern.
- ;;;
- ;;; Revision 2.2 2002/04/20 04:12:54 reid
- ;;; Improved post-emoticon-pattern.
- ;;;
- ;;; Revision 2.1 2002/04/20 03:17:48 reid
- ;;; - A major (but not total) synchronization with Dave Pearson's post-mode.
- ;;; header-set-followup-to and header-set-organization should work now.
- ;;; - Syntax highlighting now works for quoted email addresses and URLs.
- ;;; - *bold* words are now highlighted.
- ;;; - Emoticons can now be highlighted, and the default regexp,
- ;;; post-emoticon-pattern, might be too enthusiastic for your taste. In case
- ;;; you're curious, I verified that gnus' smiley-ems.el works with post, but I
- ;;; decided that it wasn't ideal.
- ;;; - post-url-text-pattern changed to post-url-pattern and made more enthusiastic.
- ;;;
- ;;; revision 1.95 2002/04/10 00:06:26 reid
- ;;; Fixed the regexp in post-kill-signature to not delete everything between
- ;;; mutt's standard forwarding lines. post-kill-signature is called indirectly
- ;;; by many functions.
- ;;;
- ;;; Revision 1.9 2002/04/04 22:24:31 reid
- ;;; Applied a patch (not quite verbatim) from The Anarcat
- ;;; <anarcat@anarcat.dyndns.org> to make the entity separating siglets in
- ;;; `post-variable-signature-source' a regexp, `post-signature-sep-regexp'. The
- ;;; default works either either the old post file format or strfiled (fortune)
- ;;; files.
- ;;;;
- ;;; Changed default `post-random-signature-command' to `fortune
- ;;; ~/.mutt/sigs.fortune'.
- ;;;
- ;;; `post-random-signature-command' should now NOT supply a fixed sig portion!
- ;;;
- ;;; (post-el-random-signature) supplied by The Anarcat to do random sig
- ;;; selection purely within Emacs Lisp.
- ;;;
- ;;; Revision 1.8 2002/02/06 22:24:31 eric
- ;;; clean up
- ;;;
- ;;; Revision 1.7.2 2002/02/06 22:17:01 eric
- ;;; tweak regexps, make font-lock-comment-face be post-signature-text-face
- ;;;
- ;;; Revision 1.7.1 2002/02/06 21:58:58 eric
- ;;; tweak regexp, change some types to regexp
- ;;;
- ;;; Revision 1.7.0 2002/02/06 21:36:56 eric
- ;;; hilight signatures, urls and emails
- ;;;
- ;;; Revision 1.6.3.10 1999/10/11 00:29:41 roland
- ;;; Corrected color quoting again: Now allows ">" in the middle of
- ;;; a line which is quoted twice.
- ;;;
- ;;; Revision 1.6.3.9 1999/10/08 10:43:18 roland
- ;;; Add third level of quoting faces.
- ;;; Allow super-cite name prefixes before quote signs.
- ;;;
- ;;; Revision 1.6.3.8 1999/10/08 08:39:00 roland
- ;;; post-font-lock-keywords now detects lines with only "> "in it
- ;;; correctly (merged following line into it before).
- ;;;
- ;;; Revision 1.6.3.7 1999/10/04 10:07:48 roland
- ;;; Add post-quote-region and post-unquote-region commands to quote and
- ;;; unquote a region (one level).
- ;;;
- ;;; Revision 1.6.3.6 1999/09/03 23:13:55 reid
- ;;; Valeriy E. Ushakov <uwe@ptc.spbu.ru> pointed out that (GNU) Emacs <20 has
- ;;; fewer (optional) arguments to (read-string) than what I was using to
- ;;; inherit the input method. I didn't find a way off the top of my head
- ;;; to redefine (read-string) without causing an infinite loop, so I have
- ;;; substituted a macro (string-read prompt) which does the right thing,
- ;;; so please use it instead of read-string.
- ;;;
- ;;; Revision 1.6.3.5 1999/08/29 19:58:49 reid
- ;;; Changed default post-mail-message to handle hostnames with digits.
- ;;; Thanks to Brian D. Winters <brianw@alumni.caltech.edu>.
- ;;;
- ;;; Revision 1.6.3.4 1999/03/20 03:02:05 reid
- ;;; Made post compatible with emacs as far back as 19.28.1, probably
- ;;; farther.
- ;;;
- ;;; Revision 1.6.3.3 1999/03/16 03:14:07 reid
- ;;; Cleaned up post-select-signature-select-sig-from-file code.
- ;;;
- ;;; Revision 1.6.3.2 1999/03/16 03:05:12 reid
- ;;; Fixed alist updating.
- ;;;
- ;;; Revision 1.6.3.1 1999/03/13 02:23:48 reid
- ;;; Added defface to the list of things that get defined if customize
- ;;; hasn't already done it. Thanks to Melissa Binde for the bug report.
- ;;;
- ;;; Modified post-body-says-attach to use a regexp,
- ;;; post-attachment-regexp, so that something like "\(attach\|anbringen\)"
- ;;; can be used by bilingual people like Roland.
- ;;;
- ;;; Revision 1.6.2.1 1999/03/12 10:16:11 roland
- ;;; Added missing () to post-insert-to-auto-mode-alist-on-load.
- ;;;
- ;;; Revision 1.6.2 1999/03/11 15:51 Dave Pearson
- ;;; header-position-on-value fixed to return (point), and
- ;;; defcustom macro provided for Emacs 19 users.
- ;;;
- ;;; Revision 1.6.1.2 1999/03/06 11:24:43 roland
- ;;; Added post-insert-to-auto-mode-alist-on-load.
- ;;;
- ;;; Revision 1.6.1.1 1999/03/06 11:02:27 roland
- ;;; Customized renaming of buffer.
- ;;; Removed different handling for mail, news, news-reply.
- ;;; Fixed problems with easy-menu under XEmacs.
- ;;;
- ;;; Revision 1.6.0 1999/03/04 18:04 Rob Reid
- ;;; Returned post-signature-pattern to using "--" instead of "-- "
- ;;; because some senders have broken MTAs (as Eric reminded me) and
- ;;; some users don't use procmail to compensate. This time all of the
- ;;; functions dealing with signatures have been smartened up to avoid
- ;;; false matches. Unfortunately that means they don't use
- ;;; post-signature-pattern in its raw form.
- ;;;
- ;;; Added post-backup-original so that Dave's post-copy-original can
- ;;; be used.
- ;;;
- ;;; Kevin Rodgers explained how to put this in .emacs to fix the
- ;;; server-process-filter's annoying message problem:
- ;;;
- ;;; Revision 1.1 1999/03/04 18:02:30 reid
- ;;; Initial revision
- ;;;
- ;;; %%%%%%%%%%%% Put in .emacs %%%%%%%%%%%
- ;;;
- ;;; ;;; Email
- ;;; (server-start)
- ;;; (load "/home/reid/.mutt/post")
- ;;; (defadvice server-process-filter (after post-mode-message first activate)
- ;;; "If the buffer is in post mode, overwrite the server-edit
- ;;; message with a post-save-current-buffer-and-exit message."
- ;;; (if (eq major-mode 'post-mode)
- ;;; (message
- ;;; (substitute-command-keys "Type \\[describe-mode] for help composing; \\[post-save-current-buffer-and-exit] when done."))))
- ;;; ; This is also needed to see the magic message. Set to a higher
- ;;; ; number if you have a faster computer or read slower than me.
- ;;; '(font-lock-verbose 1000)
- ;;; ; (setq server-temp-file-regexp "mutt-")
- ;;; (add-hook 'server-switch-hook
- ;;; (function (lambda()
- ;;; (cond ((string-match "Post" mode-name)
- ;;; (post-goto-body))))))
- ;;;
- ;;; %%%%%%%%% We now return to our regular commentary %%%%%%%%%
- ;;;
- ;;; Eric Kidd asked that the name of Headers mode be changed so that
- ;;; it doesn't conflict with mutt-mode's Headers, so I changed it to
- ;;; just Header (no s).
- ;;;
- ;;; Revision 1.5? 1999/02/27 17:30 Rob Reid
- ;;; I had a go at combining Dave Pearson's post mode with Eric Kidd's
- ;;; Mutt mode. Since Dave Pearson's post mode explicitly handles news as
- ;;; well as email, and this should be useful for more than just mutt,
- ;;; I'm calling it post mode. I also added functions for picking
- ;;; random signatures, selecting a signature from a file, and
- ;;; intelligently (IMHO) prompting the user for an attachment when
- ;;; necessary. Changed mutt-save-buffer-and-exit to work better with
- ;;; emacsclient, and some of the key bindings. post-signature-pattern
- ;;; now defaults to use "-- " instead of "--", and I have far less
- ;;; trouble this way (I use procmail to clean up braindead "--"s.). I
- ;;; don't know why Eric warned against trailing whitespace.
- ;;;
- ;;; Revision 1.4 1998/04/11 00:05:46 emk
- ;;; Fixed font-lock bug. Also made mutt-mode a little more careful about
- ;;; saving various bits of Emacs state when moving around the buffer.
- ;;;
- ;;; Revision 1.3 1998/03/25 00:37:36 emk
- ;;; Added support for menus and font-lock mode, plus a few bug fixes.
- ;;;
- ;;; Revision 1.2 1998/03/24 13:19:46 emk
- ;;; Major overhaul--more commands, a minor mode for header editing, and other
- ;;; desirable features. Attaching files seems to be broken, though.
- ;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;
- ;;; Required Packages
- (require 'cl)
- (require 'derived)
- (require 'easymenu)
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;
- ;;; Customization Support
- ;;;
- ;;; Set up our customizable features. You can edit these (and lots of other
- ;;; fun stuff) by typing M-x customize RET. The Post preferences can be
- ;;; found under the [Applications] [Mail] category.
- ;; Make post mode a bit more compatible with older (i.e. <20) versions of emacs.
- ;;; Code:
- (eval-and-compile
- ;; Dumb down read-string if necessary.
- ;; The number of optional arguments for read-string seems to increase
- ;; sharply with (emacs-version). Since old versions of emacs are a large
- ;; source of bug reports it might be worth writing (or looking for)
- ;; (bug-report reid@astro.utoronto.ca) which emails me the result of
- ;; (emacs-version) along with a user supplied description of the problem.
- ;; GNU Emacs 19.28.1 only has INITIAL-STRING as an optional argument.
- ;; 19.34.1 has (read-string PROMPT &optional INITIAL-INPUT HISTORY). 20.2.1
- ;; has (read-string PROMPT &optional INITIAL-INPUT HISTORY DEFAULT-VALUE
- ;; INHERIT-INPUT-METHOD).
- ;; Since I haven't found a way of redefining read-string without causing an
- ;; infinite loop, please use (string-read prompt).
- (if (< (string-to-number (substring (emacs-version)
- (string-match "[0-9]+\.[0-9]"
- (emacs-version) 5))) 20)
- (defmacro string-read (prompt) (` (read-string (, prompt))))
- (defmacro string-read (prompt)
- (` (read-string (, prompt) nil nil nil t))))
- ;; XEmacs gnuserv uses slightly different functions than the GNU Emacs
- ;; server, and some people are still wasting time and CPU cycles by starting
- ;; up a new emacs each time.
- (cond ((fboundp 'server-edit)
- (fset 'post-finish 'server-edit))
- ((fboundp 'gnuserv-kill-buffer-function)
- (fset 'post-finish 'gnuserv-kill-buffer-function))
- (t
- (fset 'post-finish 'save-buffers-kill-emacs)))
-
- ;; If customize isn't available just use defvar instead.
- (unless (fboundp 'defgroup)
- (defmacro defgroup (&rest rest) nil)
- (defmacro defcustom (symbol init docstring &rest rest)
- ; The "extra" braces and whitespace are for emacs < 19.29.
- (` (defvar (, symbol) (, init) (, docstring))))
- (defmacro defface (&rest args) nil))
- (unless (fboundp 'buffer-substring-no-properties)
- (fset 'buffer-substring-no-properties 'buffer-substring)))
- (defgroup post nil
- "Composing e-mail messages with Post.
- Emacs can run as an external editor for Mutt, the spiffy Unix mail reader
- du jour, or slrn, the spiffy Unix news reader du jour. You can get
- Mutt from http://www.mutt.org/."
- :group 'mail)
- (defcustom post-uses-fill-mode t
- "*Specifies whether Post should automatically wrap lines.
- Set this to t to enable line wrapping, and nil to disable line
- wrapping. Note that if a paragraph gets messed up (the line wrapper
- is very primitive), you can type \\[fill-paragraph] to rewrap the paragraph."
- :type 'boolean
- :group 'post)
- (defcustom post-mail-message "mutt-[a-z0-9]+-[0-9]+-[0-9]+\\'"
- "*Regular expression which matches your mailer's temporary files."
- :type 'string
- :group 'post)
- (defcustom post-news-posting "\\.\\(followup\\|letter\\|article\\)$"
- "*Regular expression which matches your news reader's composition files."
- :type 'string
- :group 'post)
- (defcustom post-backup-original nil
- "*Controls whether a pristine backup of the original is kept for reference."
- :type 'boolean
- :group 'post)
- (defcustom post-signature-pattern "\\(--\\|Cheers,\\|\\)"
- "*Pattern signifying the beginning of signatures.
- It should not contain trailing whitespace unless you know what you're doing."
- :type 'regexp
- :group 'post)
- (defcustom post-signature-sep-regexp "^\\(%\\|^L\\|--\\)?\n"
- "*Regular expression delimiting signatures in the signature file.
- This allows the use of classic fortune files as signature files.
- This should normally contain a newline."
- :type 'regexp
- :group 'post)
- (defcustom post-signature-source-is-file t
- "*Toggles the signature source type between file and directory."
- :type 'boolean
- :group 'post)
- (defcustom post-variable-signature-source "~/.mutt/sigs.fortune"
- "*Location of the variable part of your signature.
- Post uses this to locate signatures. It can be either a directory
- with one item per file or a file with items separated by blank lines."
- :type 'string
- :group 'post)
- (defcustom post-fixed-signature-source "~/.fixedsig"
- "*File with the fixed part of your signature."
- :type 'string
- :group 'post)
- (defcustom post-signature-directory "~/.sigs/"
- "*The directory that contains your collection of signature files."
- :type 'string
- :group 'post)
- (defcustom post-signature-wildcard "sig*"
- "*Wildcard for finding signature files in your signature directory."
- :type 'string
- :group 'post)
- (defcustom post-random-signature-command "fortune ~/.mutt/sigs.fortune"
- "*Command to run to get a random signature.
- Examples are available at http://astro.utoronto.ca/~reid/mutt/"
- :type 'string
- :group 'post)
- (defcustom post-kill-quoted-sig t
- "Specifies whether `post-mode' should automatically kill quoted signatures."
- :type 'boolean
- :group 'post)
- (defcustom post-jump-header t
- "Specifies wheather `post-mode' should jump to the body."
- :type 'boolean
- :group 'post)
- (defcustom post-force-pwd-to-home t
- "Specifies whether `post-mode' should cd to your home directory."
- :type 'boolean
- :group 'post)
- (defcustom post-email-address (concat (user-login-name) "@" mail-host-address)
- "*Your email address."
- :type 'string
- :group 'post)
- (defcustom post-should-prompt-for-attachment 'Smart
- "*Controls whether an attachment will be prompted for before saving
- the message and exiting. 'Smart' will prompt only if the body
- contains post-attachment-regexp."
- :type '(choice (const Never)
- (const Smart)
- (const Always))
- :group 'post)
- (defcustom post-attachment-regexp "attach"
- "*This is what post looks for in the body if
- post-should-prompt-for-attachment is 'Smart'."
- :type 'regexp
- :group 'post)
- (defcustom post-news-poster-regexp "^On .*<.*>.*wrote:$"
- "Regular expression used to locate the attribution line of a news posting."
- :type 'regexp
- :group 'post)
- (defcustom post-rename-buffer t
- "Specify whether `post-mode' should rename the buffer to *Composing*."
- :type 'boolean
- :group 'post)
- (defcustom post-insert-to-auto-mode-alist-on-load t
- "Automatically insert `post-mode' with `post-mail-message' to `auto-mode-alist'."
- :type 'boolean
- :group 'post)
- (defcustom post-mode-hook nil
- "List of hooks to be executed on entry to `post-mode'."
- :group 'post)
- (defcustom post-quote-start "> "
- "Pattern which is added (or removed) at the beginning of the line by
- comment-region"
- :group 'post)
- (defcustom post-email-address-pattern
- "[A-Za-z0-9_][-A-Za-z0-9._]*@[-A-Za-z0-9._]*[A-Za-z0-9]"
- "Pattern to detect email addresses."
- :type 'regexp
- :group 'post)
- (defcustom post-url-pattern
- '("\\<\\(\\(https?\\|news\\|mailto\\|ftp\\|gopher\\):\\|\\(www\\|ftp\\)\\.\\)[-~A-Za-z0-9._/%$+?#]+[A-Za-z0-9/#]" "<URL:[^ ]+>")
- "Pattern to detect URL addresses."
- :type '(repeat regexp)
- :group 'post)
- (defcustom post-bold-pattern '("\\*\\w+\\*")
- "*List of regular expressions that define bold text."
- :type '(repeat regexp)
- :group 'post)
- (defcustom post-underline-pattern '("_\\w+_")
- "*List of regular expressions that define underlined text."
- :type '(repeat regexp)
- :group 'post)
- (defcustom post-emoticon-pattern '("[0O(<{}]?[;:8B|][.,]?[-+^*o0O][{<>/\|]?[][)>(<|/\P][)>]?"
- "\\s [(<]?[][)>(<|/\][}<>|]?[-+^*oO0][,.]?[:8][0O>]?"
- "\\s [;:][][P)\/(]" "\\s [][)(P\/][:;]"
- "<[Gg]>" "<[BbSs][Gg]>")
- "*List of regular expressions that define a emoticon."
- :type '(repeat regexp)
- :group 'post)
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;
- ;;; Customizable Faces
- ;;; If you find a more attractive color scheme for dark backgrounds, please
- ;;; email it to reid@astro.utoronto.
- (defgroup post-faces nil
- "Typefaces used for composing messages with Post."
- :group 'post
- :group 'faces)
- (defface post-header-keyword-face
- '((((class color)
- (background light))
- (:foreground "Navy" :bold t))
- (((class color)
- (background dark))
- (:foreground "LightBlue" :bold t))
- (t
- (:bold t)))
- "Face used for displaying keywords (e.g. \"From:\") in header."
- :group 'post-faces)
- (defface post-header-value-face
- '((((class color)
- (background light))
- (:foreground "MidnightBlue"))
- (((class color)
- (background dark))
- (:foreground "LightSteelBlue")))
- "Face used for displaying the values of header."
- :group 'post-faces)
- (defface post-quoted-text-face
- '((((class color)
- (background light))
- (:foreground "Sienna" :italic t))
- (((class color)
- (background dark))
- (:foreground "Wheat" :italic t))
- (t
- (:bold t :italic t)))
- "Face used for displaying text which has been quoted (e.g. \">foo\")."
- :group 'post-faces)
- (defface post-double-quoted-text-face
- '((((class color)
- (background light))
- (:foreground "Firebrick" :italic t))
- (((class color)
- (background dark))
- (:foreground "Tan" :italic t))
- (t
- (:italic t)))
- "Face used for text which has been quoted twice (e.g. \">>foo\")."
- :group 'post-faces)
- (defface post-multiply-quoted-text-face
- '((((class color)
- (background light))
- (:foreground "goldenrod" :italic t))
- (((class color)
- (background dark))
- (:foreground "tan3" :italic t))
- (t
- (:italic t)))
- "Face used for text which has been quoted more than twice (e.g. \">>>foo\")."
- :group 'post-faces)
- (defface post-signature-text-face
- '((((class color)
- (background light))
- (:foreground "red3"))
- (((class color)
- (background dark))
- (:foreground "red1"))
- (t
- (:bold t)))
- "Face used for text that is part of a signature"
- :group 'post-faces)
- (defface post-email-address-text-face
- '((((class color)
- (background light))
- (:foreground "green3"))
- (((class color)
- (background dark))
- (:foreground "green1"))
- (t
- (:italic t)))
- "Face used for email addresses"
- :group 'post-faces)
- (defface post-url-face
- '((((class color)
- (background light))
- (:foreground "green3" :bold t))
- (((class color)
- (background dark))
- (:foreground "green1" :bold t))
- (t
- (:italic t)))
- "Face used for URL addresses"
- :group 'post-faces)
- (defface post-emoticon-face
- '((((class color)
- (background light))
- (:foreground "black" :background "yellow" :bold t))
- (((class color)
- (background dark))
- (:foreground "black" :background "yellow" :bold t))
- (t
- (:bold t)))
- "Face used for text matched by post-emoticon-pattern."
- :group 'post-faces)
- (defface post-bold-face
- '((((class color)
- (background light))
- (:bold t))
- (((class color)
- (background dark))
- (:bold t))
- (t
- (:bold t)))
- "Face used for text matching post-bold-pattern."
- :group 'post-faces)
- (defface post-underline-face
- '((((class color)
- (background light))
- (:underline t))
- (((class color)
- (background dark))
- (:underline t))
- (t
- (:underline t)))
- "Face used for text matching post-underline-pattern."
- :group 'post-faces)
- ; Note: some faces are added later!
- (defvar post-font-lock-keywords
- `(("^\\([A-Z][-A-Za-z0-9.]+:\\)\\(.*\\)$"
- (1 'post-header-keyword-face)
- (2 'post-header-value-face))
- ("^[ \t\f]*\\(>[ \t\f]*\\)\\([-a-zA-Z]*>[ \t\f]*\\)\\([-a-zA-Z]*>.*\\)$"
- (1 'post-quoted-text-face)
- (2 'post-double-quoted-text-face)
- (3 'post-multiply-quoted-text-face))
- ("^[ \t\f]*\\(>[ \t\f]*\\)\\([-a-zA-Z]*>.*\\)$"
- (1 'post-quoted-text-face)
- (2 'post-double-quoted-text-face))
- ("^[ \t\f]*\\(>[ \t\f]*[^ \t\f\n>].*\\)$"
- (1 'post-quoted-text-face))
- ("^[ \t\f]*\\(>[ \t\f]*\\)$"
- (1 'post-quoted-text-face))
- (,post-email-address-pattern
- (0 'post-email-address-text-face)))
- "Highlighting rules for message mode.")
- ;;; Declare global mode variables.
- (defconst post-font-lock-syntactic-keywords
- `((,(concat "^" post-signature-pattern "[ \t\f]*$") 0 '(11))))
- (defun post-font-lock-syntactic-face-function (state)
- "Function for font locking syntactic faces.
- Argument STATE ."
- post-signature-text-face)
- (defvar post-buf nil
- "Name of the composing buffer.")
- (defvar post-select-signature-mode-map nil
- "Local keymap for the select-signature buffer.")
- (defvar post-select-signature-last-buffer nil
- "Pointer to the calling buffer.")
- (defvar post-select-signature-last-point nil
- "Where we were in the calling buffer.")
- (defvar post-has-attachment nil
- "Whether the message has an attachment.")
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;
- ;;; Interactive Commands
- (defun post-save-current-buffer-and-exit ()
- "Save the current buffer and exit Emacs."
- (interactive)
- ;; Should the user be prompted for an attachment?
- (cond (post-has-attachment)
- ((equal post-should-prompt-for-attachment 'Never))
- ((or (equal post-should-prompt-for-attachment 'Always)
- (post-body-says-attach))
- (post-prompt-for-attachment)))
- (basic-save-buffer)
- (if post-backup-original
- (kill-buffer "*Original*"))
- (post-finish)
- ;; Added by Rob Reid 10/13/1998 to prevent accumulating *Composing* buffers
- ;; when using (emacs|gnu)client. Helped by Eric Marsden's Eliza example in
- ;; http://www.ssc.com/lg/issue29/marsden.html
- (kill-buffer post-buf))
- (defun post-goto-body ()
- "Go to the beginning of the message body."
- (interactive)
- (goto-char (point-min))
- ;; If the message has header, slide downward.
- (and header-mode (save-match-data (re-search-forward "^$" nil t))
- (next-line 1)))
- (defun post-goto-signature ()
- "Go to the beginning of the message signature."
- (interactive)
- (goto-char (point-max))
- (and (save-match-data
- (re-search-backward (concat "^" post-signature-pattern
- "[ \t\f]*$")
- nil t))))
- (defun post-delete-quoted-signatures ()
- "Delete quoted signatures from buffer."
- (interactive)
- (goto-char (point-min))
- (flush-lines (concat "^\\([ \t\f]*>[ \t\f>]*\\)"
- post-signature-pattern
- "[ \t\f]*\\(\n\\1.*\\)+")))
- (defun post-kill-signature ()
- "Kill the signature from the buffer.
- Returns the point value for where the signature was or, if there isn't a
- signature, the point value of the end of the buffer"
- (interactive)
- (save-excursion
- (goto-char (point-min))
- ; The .=*+|#@!~$%&()_- is to compensate for people who put ASCII art on the
- ; same line as the sigdashes, and the $ at the end prevents this from deleting
- ; everything between mutt's standard forwarding lines.
- (cond ((search-forward-regexp (concat "^" post-signature-pattern
- "[ \t\f.=*+|#@!~$%&()_-]*$") nil t)
- (beginning-of-line)
- (kill-region (point) (point-max)))
- (t
- (goto-char (point-max))))
- (point)))
- (defun post-delete-old-citations ()
- "Delete citations more than one level deep from buffer."
- (interactive)
- (goto-char (point-min))
- (flush-lines "^[ \t\f]*>[ \t\f]*>[ \t\f>]*"))
- ;;; Functions for messing with the body
- (defun post-make-region-bold (start end)
- "Apply mutt's nroff style bold to a region of text.
- Argument START start of region.
- Argument END end of region."
- (interactive "r")
- (while (< start end)
- (goto-char start)
- (insert (buffer-substring-no-properties start (1+ start)))
- (insert (char-to-string 8))
- (setq start (+ start 3))
- (setq end (+ end 2))))
- (defun post-make-region-underlined (start end)
- "Apply mutt's nroff style underline to a region of text.
- Argument START start of region.
- Argument END end of region."
- (interactive "r")
- (while (< start end)
- (goto-char start)
- (insert "_")
- (insert (char-to-string 8))
- (setq start (+ start 3))
- (setq end (+ end 2))))
- (defun post-quote-region (beg end)
- "Quote a region using the `post-quote-start' variable.
- Argument BEG Beginning of region to be quoted.
- Argument END End of region to be quoted."
- (interactive "r")
- (comment-region beg end))
- (defun post-unquote-region (beg end)
- "Un-quote a region one level using the `post-quote-start' variable.
- Argument BEG Beginning of region to be quoted.
- Argument END End of region to be quoted."
- (interactive "r")
- (uncomment-region beg end))
- ; From Dave Pearson, July 15, 2000
- (defun* split-quoted-paragraph (&optional (quote-string "> "))
- "Split a quoted paragraph at point, keeping the quote."
- (interactive)
- (if (save-excursion
- (beginning-of-line)
- (looking-at (regexp-quote quote-string)))
- (progn
- (let ((spaces (- (point)
- (save-excursion
- (beginning-of-line)
- (point))
- (length quote-string))))
- (save-excursion
- (insert (format "\n\n%s%s" quote-string (make-string spaces ? ))))))
- (error "Can't see a quoted paragraph here")))
- (defun post-random-signature ()
- "Randomize the signature.
- Set it to whatever `post-random-signature-command' spits out followed by the
- content of `post-fixed-signature-source', if available, or a nasty reminder if
- it is not."
- (interactive)
- (save-excursion
- (goto-char (post-kill-signature))
- (insert "-- \n")
- (shell-command post-random-signature-command t)
- (goto-char (point-max))
- (if (file-readable-p post-fixed-signature-source)
- (insert-file-contents post-fixed-signature-source)
- (insert "I really need a `post-fixed-signature-source'!\n"))))
- (defun post-el-random-signature ()
- "Choose a random signature from `post-variable-signature-source'.
- the signatures in `post-variable-signature-source' must be separated by
- `post-signature-sep-regexp'."
- (interactive)
- (let ((sig nil))
- (save-excursion
- (set-buffer (generate-new-buffer "*Post-Select-Signature*"))
- (insert-file post-variable-signature-source)
- (beginning-of-buffer)
- ;; we have 2 lists of marks since seperators are of arbitrary lenght
- (let ((marks-st (list (point-min)))
- (marks-end (list))
- (count 0)) ;nth counts from zero and random is [0,N)
- (while (search-forward-regexp post-signature-sep-regexp nil "a")
- (setq marks-st (cons (match-end 0) marks-st)
- marks-end (cons (match-beginning 0) marks-end)
- count (1+ count)))
- (setq marks-end (cons (point-max) marks-end))
- (let ((r (random (1+ count))))
- (setq sig (buffer-substring-no-properties
- (nth r marks-st) (nth r marks-end))))
- (kill-buffer (current-buffer)))
- (goto-char (post-kill-signature))
- (insert-string "-- \n")
- (insert sig)
- (if (file-readable-p post-fixed-signature-source)
- (insert-file-contents post-fixed-signature-source)
- (insert "I really need a `post-fixed-signature-source'!\n")))))
- (defun post-select-signature-from-file ()
- "*Interactively select a signature from `post-variable-signature-source'."
- (interactive)
- (setq post-select-signature-last-buffer (current-buffer))
- (setq post-select-signature-last-point (point))
- (pop-to-buffer "*Post-Select-Signature*")
- (insert-file post-variable-signature-source)
- (use-local-map post-select-signature-mode-map))
- (defun post-select-signature-select-sig-from-file ()
- "*Chooses the signature the cursor is in from `post-variable-signature-source'."
- (interactive)
- ;; These 2 lines select whatever siglet the cursor is sitting in,
- ;; making it nifty to C-s "word" then C-m (or whatever this is
- ;; bound to).
- (let ((sig-start (point))
- (sig-end (point)))
- (cond ((setq sig-start (search-backward-regexp post-signature-sep-regexp
- nil "a"))
- (forward-line 1)
- (setq sig-start (point))))
- (if (search-forward-regexp post-signature-sep-regexp nil "a")
- (setq sig-end (match-beginning 0))
- (setq sig-end (point-max)))
- (let ((sig (buffer-substring-no-properties sig-start sig-end)))
- (switch-to-buffer post-select-signature-last-buffer)
- (goto-char (post-kill-signature))
- (insert-string "-- \n")
- (insert sig))
- (if (file-readable-p post-fixed-signature-source)
- (insert-file-contents post-fixed-signature-source))
- (post-select-signature-quit)))
- (defun post-select-signature-from-dir ()
- "Select a new signature for an email/post in the current buffer."
- (interactive)
- (setq post-select-signature-last-buffer (current-buffer))
- (setq post-select-signature-last-point (point))
- (pop-to-buffer "*Post-Select-Signature*")
- (list-directory (concat post-signature-directory
- post-signature-wildcard) t)
- (pop-to-buffer "*Directory*")
- (next-line 1)
- (copy-to-buffer "*Post-Select-Signature*" (point) (point-max))
- (kill-buffer "*Directory*")
- (pop-to-buffer "*Post-Select-Signature*")
- (use-local-map post-select-signature-mode-map)
- (toggle-read-only t))
- (defun post-select-signature-select-sig-from-dir ()
- "Set the signature in the calling buffer to the one under the cursor."
- (interactive)
- (let ((sig-start nil)
- (sig-to-load nil))
- (end-of-line)
- (search-backward " ")
- (forward-char)
- (setq sig-start (point))
- (end-of-line)
- (setq sig-to-load (buffer-substring-no-properties sig-start (point)))
- (switch-to-buffer post-select-signature-last-buffer)
- (goto-char (post-kill-signature))
- (insert-string "-- \n")
- (insert-file (concat post-signature-directory sig-to-load))
- (message "Signature set to %s%s" post-signature-directory sig-to-load)
- (post-select-signature-quit)))
- (defun post-select-signature-quit ()
- "Kill the *Post-Select-Signature* frame."
- (interactive)
- (kill-buffer "*Post-Select-Signature*")
- (switch-to-buffer post-select-signature-last-buffer)
- (goto-char post-select-signature-last-point)
- (delete-other-windows))
- ;;; Non-interactive functions
- (defun post-ask-for-address-with-default (header)
- "Prompt for an email address, showing default.
- Argument HEADER the header type."
- (let ((default (if (= (length (post-get-header-value header)) 0)
- post-email-address
- (post-get-header-value header))))
- (read-string (concat header ": ") default)))
- ; From davep@davep.org. RR hasn't tested it.
- (defun post-get-header-value (header)
- "Get the value of a specific mail HEADER."
- (save-excursion
- (let ((value "")
- (start-of-value nil))
- (setf (point) (point-min))
- (when (post-find-header-line header)
- (setq start-of-value (point))
- (end-of-line)
- (setq value (buffer-substring-no-properties start-of-value (point))))
- value)))
- ;;; From davep@davep.org. RR hasn't tested it.
- (defun post-find-header-line (header)
- "Find a HEADER line in the header."
- (let ((old-point (point))
- (end-of-header nil)
- (found-point nil))
- (setf (point) (point-min))
- (search-forward-regexp "^$" nil t)
- (setq end-of-header (point))
- (setf (point) (point-min))
- (cond ((search-forward-regexp (concat "^" header ": ") nil t)
- (cond ((< (point) end-of-header)
- (setq found-point (point)))
- (t
- (setf (point) old-point))))
- (t
- (setf (point) old-point)))
- found-point))
- ;;; Function to make a backup buffer for viewing the original.
- (defun post-copy-original ()
- "Make a copy of the `post-mode' buffer before any editing by the user.
- This way they can refer back to this buffer during a compose session."
- (copy-to-buffer (get-buffer-create "*Original*")
- (point-min) (point-max)))
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;
- ;;; The Heart of Darkness
- ;;;
- ;;; The old post mode (i.e. Dave Pearson's) derived from mail-mode. I
- ;;; prefer deriving from text mode like mutt mode did. - RR
- (define-derived-mode post-mode text-mode "Post"
- "Major mode for composing email or news with an external agent.
- To customize it, type \\[customize] and select [Applications] [Mail] [Post].
- When you finish editing this message, type \\[post-save-current-buffer-and-exit] to save and exit Emacs.
- \\{post-mode-map}"
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;
- ;;; Neat things to do right off the bat.
- (auto-fill-mode (if post-uses-fill-mode 1 0))
- (if post-backup-original (post-copy-original))
- ;; Make Emacs smarter about wrapping citations and paragraphs.
- ;; We probably can't handle Supercited messages, though.
- (make-local-variable 'paragraph-start)
- (make-local-variable 'paragraph-separate)
- (setq paragraph-start
- "\\([ \t\n\f]+[^ \t\n\f>]\\|[ \t\f>]*$\\)"
- paragraph-separate
- "[ \t\f>]*$")
- ;; XEmacs needs easy-menu-add, Emacs does not care
- (easy-menu-add post-mode-menu)
- ;; If headers were passed, activate the necessary commands.
- (when (looking-at "^[-A-Za-z0-9]+:")
- (header-mode 1))
- ;; Our temporary file lives in /tmp. Yuck! Compensate appropriately.
- (make-local-variable 'backup-inhibited)
- (setq backup-inhibited t)
- (if (boundp 'font-lock-defaults)
- (make-local-variable 'font-lock-defaults))
- (flet ((add-syntax-highlight (face regexps)
- (set face face)
- (nconc post-font-lock-keywords
- (loop for regexp in regexps
- collect (list regexp (list 0 face 't))))))
- ; collect (list regexp `(,0 ',face))))))
- (add-syntax-highlight 'post-emoticon-face post-emoticon-pattern)
- (add-syntax-highlight 'post-bold-face post-bold-pattern)
- (add-syntax-highlight 'post-underline-face post-underline-pattern)
- (add-syntax-highlight 'post-url-face post-url-pattern))
- (setq font-lock-defaults
- '(post-font-lock-keywords nil nil nil nil
- (font-lock-syntactic-keywords
- . post-font-lock-syntactic-keywords)
- (font-lock-comment-face
- ; . 'post-signature-text-face)))
- . post-signature-text-face)))
- ;; Force pwd to home directory if so required.
- (cond (post-force-pwd-to-home
- (cd "~")))
- ;; Kill quoted sig if so required.
- (cond (post-kill-quoted-sig
- (post-delete-quoted-signatures)
- (not-modified)))
- ;; Remap signature selection functions according to whether the
- ;; signatures are stored in a file or directory.
- (if post-signature-source-is-file
- (progn
- (defalias 'post-select-signature 'post-select-signature-from-file)
- (defalias 'post-select-signature-select-sig
- 'post-select-signature-select-sig-from-file))
- (progn
- (defalias 'post-select-signature 'post-select-signature-from-dir)
- (defalias 'post-select-signature-select-sig
- 'post-select-signature-select-sig-from-dir)))
- ;; Define mutt/slrn specific key bindings.
- (define-key (current-local-map) "\C-c\C-b" 'post-make-region-bold)
- (define-key (current-local-map) "\C-c\C-u" 'post-make-region-underlined)
- (define-key (current-local-map) "\C-c\C-q" 'post-quote-region)
- (define-key (current-local-map) "\C-c\C-d\C-q" 'post-unquote-region)
- (define-key (current-local-map) "\C-c\C-a" 'post-attach-file)
- (define-key (current-local-map) "\C-c\C-p" 'post-set-return-receipt-to)
- ;; Give the buffer a handy name.
- (if post-rename-buffer
- (setq post-buf (rename-buffer "*Composing*" t)))
-
- ;; If this is a news posting, check the length of the References field.
- (if (post-references-p)
- (header-check-references))
- ;; Define the quote signs as comments to make comment-region usable.
- (make-local-variable 'comment-start)
- (setq comment-start post-quote-start)
- ;; Run any hooks.
- (run-hooks 'post-mode-hook)
- ;; Jump past header if so required.
- (cond (post-jump-header
- (post-goto-body)))
- (unless (fboundp 'server-process-filter)
- (message (substitute-command-keys
- "Type \\[describe-mode] for help composing; \\[post-save-current-buffer-and-exit] when done."))))
- (defun post-references-p ()
- "Is there a References header in this buffer?"
- (save-excursion
- (goto-char (point-min))
- (looking-at "^References: ")))
- (defun post-body-says-attach ()
- "Check if attach appears in the body."
- (post-goto-body)
-
- ;; Aargh it's annoying that how-many returns a string,
- ;; "13 occurences" instead of a number, 13.
- (let ((total-attach (string-to-int (how-many post-attachment-regexp))))
- ;; And this mess is just to catch the unlikely false alarm of
- ;; "attach" being in the signature, but not in the body.
- (if (> total-attach 0)
- (progn (post-goto-signature)
- (> total-attach (string-to-int (how-many
- post-attachment-regexp)))))))
- (defun post-prompt-for-attachment ()
- "Prompt for an attachment."
- (if (y-or-n-p "Do you want to attach anything? ")
- (let ((file (read-file-name "Attach file: " nil nil t nil))
- (description (string-read "Description: ")))
- (header-attach-file file description))))
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;
- ;;; Post Header Mode
- (defvar header-mode nil)
- (defun header-mode (&optional arg)
- "Commands for editing the header of an e-mail or news message.
- \\{header-mode-map}
- Optional argument ARG ."
- (interactive "P")
- (make-local-variable 'header-mode)
- (setq header-mode
- (if (null arg)
- (not header-mode)
- (> (prefix-numeric-value arg) 0)))
- (setq post-has-attachment nil)
- ;; XEmacs needs easy-menu-add, Emacs does not care
- (easy-menu-add header-mode-menu)
- (force-mode-line-update))
- (defvar header-mode-map (make-sparse-keymap)
- "Keymap used for editing RFC822 header.")
- (defun header-position-on-value ()
- "Go to the start of the value part of a header."
- (beginning-of-line)
- (skip-chars-forward "-A-Za-z0-9:")
- ;; XXX - Should make sure we stay on line.
- (forward-char)
- (point))
- (defun header-goto-field (field)
- "Go to FIELD of a header."
- (let ((case-fold-search t))
- (goto-char (point-min))
- (save-match-data
- (when (re-search-forward (concat "^\\($\\|" field ": \\)"))
- (if (looking-at "^$")
- (progn
- (insert-string field ": \n")
- (forward-char -1))
- (header-position-on-value))))))
- (defmacro define-header-goto (name header)
- "Define functions called NAME to go to HEADER."
- `(defun ,name ()
- ,(concat "Position the cursor on the " header ": header.")
- (interactive)
- (header-goto-field ,header)))
- (define-header-goto header-goto-to "To")
- (define-header-goto header-goto-cc "Cc")
- (define-header-goto header-goto-fcc "Fcc")
- (define-header-goto header-goto-summary "Summary")
- (define-header-goto header-goto-keywords "Keywords")
- (define-header-goto header-goto-subject "Subject")
- (define-header-goto header-goto-bcc "Bcc")
- (define-header-goto header-goto-reply-to "Reply-To")
- (define-header-goto header-goto-from "From")
- (define-header-goto header-goto-organization "Organization")
- (defun header-attach-file (file description)
- "Attach a FILE to the current message (works with Mutt).
- Argument DESCRIPTION MIME description."
- (interactive "fAttach file: \nsDescription: ")
- (when (> (length file) 0)
- (save-excursion
- (save-match-data
- (save-restriction
- (widen)
- (goto-char (point-min))
- (search-forward-regexp "^$")
- (insert-string (concat "Attach: " (file-truename file) " "
- description "\n"))
- (message (concat "Attached '" file "'."))
- (setq post-has-attachment t))))))
- (or (assq 'header-mode minor-mode-alist)
- (setq minor-mode-alist
- (cons '(header-mode " Header") minor-mode-alist)))
- (or (assq 'header-mode minor-mode-map-alist)
- (setq minor-mode-map-alist
- (cons (cons 'header-mode header-mode-map)
- minor-mode-map-alist)))
- (defun header-set-return-receipt-to (address)
- "Insert a Return-Receipt-To header into an email.
- Argument ADDRESS email address return receipts should be sent to."
- (interactive (list (post-ask-for-address-with-default "Return-Receipt-To")))
- (save-excursion
- (header-set-value "Return-Receipt-To" address)))
- (defun post-news-posting-p ()
- "Does the buffer look like a news posting?"
- (save-excursion
- (setf (point) (point-min))
- (looking-at "^Newsgroups: ")))
- (defun header-set-followup-to (to)
- "Set the Followup-To: header.
- Argument TO Where followups should go."
- (interactive (list (header-ask-for-value "Followup-To"
- (header-ask-for-value
- "Newsgroups"))))
- (cond ((post-news-posting-p)
- (save-excursion
- (header-set-value "Followup-To" to)))
- (t
- (error
- "Followup-To is for Usenet. Maybe you want Reply-To or Mail-Followup-To"))))
- (defun header-set-organization (org)
- "Set the Organization: header.
- Argument ORG Should be SMERSH."
- (interactive (list (header-ask-for-value "Organization")))
- (save-excursion
- (header-set-value "Organization" org)))
- (defun header-check-references ()
- "Place the cursor at the start of the References: if they are too long."
- (interactive)
- (cond ((> (header-references-length) 500) ; 500 to be on the safe side.
- (beep) ; Catch my attention.
- (goto-char (point-min))
- (search-forward-regexp "^References: " nil t))))
- (defun header-references-length (&optional show)
- "Get (and optionally display) the length of the references header.
- Optional argument SHOW Whether or not to display the length."
- (interactive)
- (let* ((header "References")
- (refs (header-get-value header))
- (len (+ (length header) (length refs) 2)))
- (if (or (interactive-p) show)
- (message "References header is %d characters in length." len))
- len))
- (defun header-delete-reference ()
- "Delete the first reference in the references header."
- (interactive)
- (save-excursion
- (let ((ref-location (header-goto-field "References")))
- (cond (ref-location
- (let ((ref-start (goto-char ref-location)))
- (cond ((search-forward ">" nil t)
- (forward-char 1)
- (delete-region ref-start (point))
- (header-references-length t)))))))))
- ;; Noninteractive functions.
- (defun header-ask-for-value (header &optional default)
- "Ask for a HEADER value, defaulting to the current value if one is present.
- Optional argument DEFAULT ."
- (let ((new-value (post-get-header-value header)))
- (and (= (length new-value) 0)
- default
- (setq new-value default))
- (read-string (concat header ": ") new-value)))
- (defun header-get-value (header)
- "Get the value of a specific mail HEADER."
- (save-excursion
- (let ((value "")
- (start-of-value nil))
- (goto-char (point-min))
- (cond ((post-find-header-line header)
- (setq start-of-value (point))
- (end-of-line)
- (setq value (buffer-substring-no-properties
- start-of-value (point)))))
- value)))
- (defun header-set-value (header value)
- "Set VALUE of a HEADER (replacing any existing value)."
- (let ((kill-ring kill-ring))
- (setf (point) (point-min))
- (cond ((post-find-header-line header)
- (beginning-of-line)
- (kill-line)
- (insert-string (concat header ": " value)))
- (t
- (header-append-value header value))))
- (message "%s set to %s" header value))
- (defun header-append-value (header value)
- "Add a HEADER and set it's VALUE (if header exists, will add multiple headers)."
- (goto-char (point-min))
- (search-forward-regexp "^$" nil t)
- (insert-string (concat header ": " value "\n")))
- ;;; Setup the mode map for the select-signature buffer.
- (if post-select-signature-mode-map nil
- (setq post-select-signature-mode-map (make-sparse-keymap))
- (define-key post-select-signature-mode-map "\C-m"
- 'post-select-signature-select-sig)
- (define-key post-select-signature-mode-map " "
- 'post-select-signature-select-sig)
- (define-key post-select-signature-mode-map "q" 'post-select-signature-quit)
- (define-key post-select-signature-mode-map "\C-g"
- 'post-select-signature-quit))
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;
- ;;; Key Bindings
- (define-key post-mode-map "\C-c\C-c" 'post-save-current-buffer-and-exit)
- (define-key post-mode-map "\C-c\C-d\C-s" 'post-delete-quoted-signatures)
- (define-key post-mode-map "\C-c\C-d\C-c" 'post-delete-old-citations)
- (define-key post-mode-map "\C-c\C-t" 'post-goto-body)
- (define-key post-mode-map "\C-c\C-e" 'post-goto-signature)
- (define-key post-mode-map "\C-c\C-r" 'post-random-signature)
- (define-key post-mode-map "\C-c\C-b" 'post-make-region-bold)
- (define-key post-mode-map "\C-c\C-u" 'post-make-region-underlined)
- (define-key post-mode-map "\C-c\C-q" 'post-quote-region)
- (define-key post-mode-map "\C-c\C-d\C-q" 'post-unquote-region)
- (define-key post-mode-map "\C-c\C-s" 'post-select-signature)
- (define-key header-mode-map "\C-c\C-f\C-t" 'header-goto-to)
- (define-key header-mode-map "\C-c\C-f\C-c" 'header-goto-cc)
- (define-key header-mode-map "\C-c\C-f\C-w" 'header-goto-fcc)
- (define-key header-mode-map "\C-c\C-f\C-u" 'header-goto-summary)
- (define-key header-mode-map "\C-c\C-f\C-k" 'header-goto-keywords)
- (define-key header-mode-map "\C-c\C-f\C-s" 'header-goto-subject)
- (define-key header-mode-map "\C-c\C-f\C-b" 'header-goto-bcc)
- (define-key header-mode-map "\C-c\C-f\C-r" 'header-goto-reply-to)
- (define-key header-mode-map "\C-c\C-f\C-f" 'header-goto-from)
- (define-key header-mode-map "\C-c\C-f\C-o" 'header-goto-organization)
- (define-key header-mode-map "\C-c\C-ff" 'header-set-followup-to)
- (define-key header-mode-map "\C-c\C-a" 'header-attach-file)
- (define-key header-mode-map "\C-c\C-fd" 'header-delete-reference)
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;
- ;;; Menus
- (easy-menu-define
- post-mode-menu post-mode-map "Post Message Composition Commands."
- '("Post"
- ["Delete quoted signatures" post-delete-quoted-signatures t]
- ["Delete doubly quoted text" post-delete-old-citations t]
- "----"
- ["Go to body of message" post-goto-body t]
- ["Go to signature of message" post-goto-signature t]
- ["Get new random signature" post-random-signature t]
- ["Select new signature" post-select-signature t]
- "----"
- ["Embolden region" post-make-region-bold t]
- ["Underline region" post-make-region-underlined t]
- "----"
- ["Quote region" post-quote-region t]
- ["Unquote region" post-unquote-region t]
- "----"
- ["Save message and return from Post" post-save-current-buffer-and-exit t]))
- (easy-menu-define
- header-mode-menu header-mode-map "Header Editing Commands."
- '("Header"
- ["Attach File..." header-attach-file t]
- "----"
- ["Edit From Header" header-goto-from t]
- ["Edit Subject Header" header-goto-subject t]
- ["Edit To Header" header-goto-to t]
- ["Edit Cc Header" header-goto-cc t]
- ["Edit Bcc Header" header-goto-bcc t]
- ["Edit Fcc Header" header-goto-fcc t]
- ["Edit Reply-To Header" header-goto-reply-to t]
- ["Edit Summary Header" header-goto-summary t]
- ["Edit Keywords Header" header-goto-keywords t]
- ["Edit Organization Header" header-goto-organization t]))
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;
- ;;; Finish Installing Post Mode
- (when post-insert-to-auto-mode-alist-on-load
- (unless (assq post-mail-message auto-mode-alist)
- (setq auto-mode-alist
- (cons (cons post-mail-message 'post-mode)
- auto-mode-alist)))
- (unless (assq post-news-posting auto-mode-alist)
- (setq auto-mode-alist
- (cons (cons post-news-posting 'post-mode)
- auto-mode-alist))))
- (provide 'post)
- ;;; post.el ends here
|