Annotation of 43BSD/contrib/emacs/lisp/mh-e.el, revision 1.1

1.1     ! root        1: ;;;  mh-e.el   (Version: 3.3c for GNU Emacs Version 17 and MH.5 and MH.6)
        !             2: 
        !             3: ;;;  Copyright (C) James Larus ([email protected], ucbvax!larus), 1985
        !             4: ;;;    Please send suggestions and corrections to the above address.
        !             5: ;;;
        !             6: ;;;  This file contains mh-e, a GNU Emacs front end to the MH mail system.
        !             7: 
        !             8: 
        !             9: ;; GNU Emacs is distributed in the hope that it will be useful,
        !            10: ;; but without any warranty.  No author or distributor
        !            11: ;; accepts responsibility to anyone for the consequences of using it
        !            12: ;; or for whether it serves any particular purpose or works at all,
        !            13: ;; unless he says so in writing.
        !            14: 
        !            15: ;; Everyone is granted permission to copy, modify and redistribute
        !            16: ;; GNU Emacs, but only under the conditions described in the
        !            17: ;; document "GNU Emacs copying permission notice".   An exact copy
        !            18: ;; of the document is supposed to have been given to you along with
        !            19: ;; GNU Emacs so that you can know how you may redistribute it all.
        !            20: ;; It should be in a file named COPYING.  Among other things, the
        !            21: ;; copyright notice and this notice must be preserved on all copies.
        !            22: 
        !            23: 
        !            24: ;;;  Original version for Gosling emacs by Brian Reid, Stanford, 1982.
        !            25: ;;;  Modified by James Larus, BBN, July 1984 and UCB, 1984 & 1985.
        !            26: ;;;  Rewritten for GNU Emacs, James Larus 1985.
        !            27: 
        !            28: 
        !            29: ;;;  NB MH must have been compiled with the MHE compiler flag or several
        !            30: ;;;  features necessary to this program will be missing.
        !            31: 
        !            32: 
        !            33: 
        !            34: ;;; Constants:
        !            35: 
        !            36: ;;; Set for local environment:
        !            37: ;;;* These are now in paths.el.
        !            38: ;;;(defvar mh-progs "/usr/new/mh/"     "Directory containing MH commands")
        !            39: ;;;(defvar mh-lib   "/usr/new/lib/mh/" "Directory of MH library")
        !            40: 
        !            41: 
        !            42: ;;; Mode hooks:
        !            43: 
        !            44: (defvar mh-folder-mode-hook nil
        !            45:   "*Invoked in mh-folder-mode on a new folder.")
        !            46: (defvar mh-letter-mode-hook nil
        !            47:   "*Invoked in mh-letter-mode on a new letter.")
        !            48: (defvar mh-compose-letter-hook nil
        !            49:   "*Invoked in mh-compose-and-send-mail on an outgoing letter.  It is passed
        !            50: three arguments: TO recipients, SUBJECT, and CC recipients.")
        !            51: 
        !            52: 
        !            53: ;;; Personal preferences:
        !            54: 
        !            55: (defvar mh-auto-fill-letters t
        !            56:   "*Non-nil means invoke auto-fill-mode in draft messages.")
        !            57: (defvar mh-clean-message-header nil
        !            58:   "*Non-nil means remove invisible header lines in messages.")
        !            59: (defvar mh-use-mhl nil
        !            60:   "*Non-nil means use mhl to format messages.")
        !            61: (defvar mh-lpr-command-format "lpr -p -J '%s'"
        !            62:   "*Format for Unix command line to print a message. The format should be
        !            63: a unix command line, with the string \"%s\" where the folder and message
        !            64: number should appear.")
        !            65: (defvar mh-summary-height 4
        !            66:   "*Number of lines in summary window.")
        !            67: (defvar mh-ins-buf-prefix ">> "
        !            68:   "*String to put before each non-blank line of the the current message
        !            69: as it is inserted in an outgoing letter.")
        !            70: 
        !            71: 
        !            72: ;;; Real constants:
        !            73: 
        !            74: (defvar mh-cmd-note 4                 "Offset to insert notation")
        !            75: (defvar mh-invisible-headers
        !            76:   "^Received: \\|^Message-Id: \\|^Remailed-\\|^Via: \\|^Mail-from: \\|\^Return-Path: \\|^In-Reply-To: \\|^Resent-"
        !            77:   "Regexp specifying headers that are not to be shown.")
        !            78: (defvar mh-rejected-letter-start "^   ----- Unsent message follows -----$"
        !            79:   "Regexp specifying the beginning of the wrapper around a letter returned
        !            80: by the mail system.")
        !            81: (defvar mh-good-msg-regexp  "^....[^D^]"
        !            82:   "Regexp specifiying the scan lines that are 'good' messages")
        !            83: 
        !            84: ;;; Global variables:
        !            85: 
        !            86: (defvar mh-user-path  ""            "User's mail folder.")
        !            87: (defvar mh-last-destination nil             "Destination of last "move" command.")
        !            88: (defvar mh-folder-mode-map (make-sparse-keymap) "Keymap for MH folders.")
        !            89: (defvar mh-letter-mode-map (make-sparse-keymap) "Keymap for composing mail.")
        !            90: (defvar mh-pick-mode-map (make-sparse-keymap) "Keymap for searching folder.")
        !            91: (defvar mh-folder-list nil          "List of folder names for completion.")
        !            92: 
        !            93: ;;; Macros and generic functions:
        !            94: 
        !            95: (defmacro push (v l)
        !            96:   (list 'setq l (list 'cons v l)))
        !            97: 
        !            98: (defmacro caar (l)
        !            99:   (list 'car (list 'car l)))
        !           100: 
        !           101: (defmacro cadr (l)
        !           102:   (list 'car (list 'cdr l)))
        !           103: 
        !           104: (defmacro cdar (l)
        !           105:   (list 'cdr (list 'car l)))
        !           106: 
        !           107: (defmacro cddr (l)
        !           108:   (list 'cdr (list 'cdr l)))
        !           109: 
        !           110: (defmacro when (pred &rest body)
        !           111:   (list 'cond (cons pred body)))
        !           112: 
        !           113: (defun mapc (func list)
        !           114:   (while list
        !           115:     (funcall func (car list))
        !           116:     (setq list (cdr list))))
        !           117: 
        !           118: 
        !           119: 
        !           120: ;;; Entry points:
        !           121: 
        !           122: (defun mh-rmail (&optional arg)
        !           123:   "Inc(orporate) new mail if optional ARG omitted, or scan a MH mail box
        !           124: if arg is present.  This front end uses the MH mail system, which uses
        !           125: different conventions from the usual mail system."
        !           126:   (interactive "P")
        !           127:   (mh-find-path)
        !           128:   (if (null mh-folder-list)
        !           129:       (setq mh-folder-list (mh-make-folder-list)))
        !           130:   (cond (arg
        !           131:         (let ((folder (mh-prompt-for-folder "mh" "+inbox" t))
        !           132:               (range (read-string "Range [all]? ")))
        !           133:           (mh-scan-folder folder (if (equal range "") "all" range))
        !           134:           (delete-other-windows)))
        !           135:        (t
        !           136:         (mh-inc-folder))))
        !           137: 
        !           138: 
        !           139: (defun mh-smail ()
        !           140:   "Send mail using the MH mail system."
        !           141:   (interactive)
        !           142:   (mh-find-path)
        !           143:   (call-interactively 'mh-send))
        !           144: 
        !           145: 
        !           146: 
        !           147: ;;; User executable mh-e commands:
        !           148: 
        !           149: 
        !           150: (defun mh-answer (&optional arg)
        !           151:   "Answer a letter.  If given a non-nil ARGUMENT, then include the current
        !           152: message in the reply."
        !           153:   (interactive "P")
        !           154:   (let ((msg-filename (mh-msg-filename))
        !           155:        (msg (mh-get-msg-num t))
        !           156:        (minibuffer-help-form
        !           157: "from => Sender\n  to => Sender and primary recipients\n  cc => Sender and all recipients")
        !           158:        (folder mh-current-folder)
        !           159:        (show-buffer mh-show-buffer))
        !           160:     (let ((reply-to (completing-read
        !           161:                     "Reply to whom: " '(("from") ("to") ("cc")) nil t)))
        !           162:     (message "Composing a reply...")
        !           163:     (cond ((or (equal reply-to "from") (equal reply-to ""))
        !           164:           (apply 'mh-exec-cmd
        !           165:                  (nconc
        !           166:                   (list "repl" "-build" mh-current-folder msg "-nocc" "all")
        !           167:                   (if arg (list "-filter" "mhl.reply")))))
        !           168:          ((equal reply-to "to")
        !           169:           (apply 'mh-exec-cmd
        !           170:                  (nconc
        !           171:                   (list "repl" "-build" mh-current-folder msg "-cc" "to")
        !           172:                   (if arg (list "-filter" "mhl.reply")))))
        !           173:          ((equal reply-to "cc")
        !           174:           (apply 'mh-exec-cmd
        !           175:                  (nconc
        !           176:                   (list "repl" "-build" mh-current-folder msg "-cc" "all")
        !           177:                   (if arg (list "-filter" "mhl.reply"))))))
        !           178: 
        !           179:     (mh-read-draft)
        !           180:     (delete-other-windows)
        !           181:     (when (or (zerop (buffer-size))
        !           182:              (not (y-or-n-p "The file 'draft' exists.  Use for reply? ")))
        !           183:       (erase-buffer)
        !           184:       (insert-file-contents (format "%sreply" mh-user-path))
        !           185:       (delete-file (format "%sreply" mh-user-path)))
        !           186:     (set-buffer-modified-p nil)
        !           187: 
        !           188:     (let ((to (mh-get-field "To:"))
        !           189:          (subject (mh-get-field "Subject:"))
        !           190:          (cc (mh-get-field "Cc:")))
        !           191:       (goto-char (point-min))
        !           192:       (re-search-forward "^$" (point-max) nil)
        !           193:       (if (not arg)
        !           194:        (mh-display-msg msg msg-filename show-buffer))
        !           195:       (mh-add-msg-to-seq msg "answered" t)
        !           196:       (message "Composing a reply...done")
        !           197:       (mh-compose-and-send-mail "" folder to subject cc "-" "Replied:")))))
        !           198: 
        !           199: 
        !           200: (defun my-apply-command-to-seq (command)
        !           201:   "Applies the next command to all messages in a sequence to be prompted for."
        !           202:   (interactive "k")
        !           203:   (funcall (key-binding command) (mh-read-seq "Apply to" mh-narrowed-to-seq)))
        !           204: 
        !           205: 
        !           206: (defun mh-copy-msg (&optional seq)
        !           207:   "Copy specified message(s) to another folder without deleting them.
        !           208: Optional argument is a SEQUENCE name to copy."
        !           209:   (interactive "P")
        !           210:   (let ((msgs (if seq seq (mh-get-msg-num t))))
        !           211:     (mh-exec-cmd "refile" msgs "-link" "-src" mh-current-folder
        !           212:                 (mh-prompt-for-folder "Copy to" "" t))
        !           213:     (if seq
        !           214:        (mh-notate-seq msgs ?C mh-cmd-note)
        !           215:        (mh-notate ?C mh-cmd-note))))
        !           216: 
        !           217: 
        !           218: (defun mh-delete-msg (&optional seq)
        !           219:   "Marks the specified message(s) for later deletion.  Optional argument is a
        !           220: SEQUENCE name to  delete."
        !           221:   (interactive "P")
        !           222:   (if seq
        !           223:       (mh-map-to-seq-msgs 'mh-delete-a-msg seq)
        !           224:       (mh-delete-a-msg))
        !           225:   (mh-next-msg))
        !           226: 
        !           227: 
        !           228: (defun mh-delete-msg-from-seq (&optional arg)
        !           229:   "Deletes a message from a sequence or, if optional ARG is non-nil, deletes
        !           230: the sequence."
        !           231:   (interactive "P")
        !           232:   (if arg
        !           233:       (mh-remove-seq (mh-read-seq "Delete"))
        !           234:       (mh-remove-msg-from-seq (mh-get-msg-num t) (mh-read-seq "Delete from")))
        !           235:   (mh-next-msg))
        !           236: 
        !           237: 
        !           238: (defun mh-execute-commands ()
        !           239:   "Process outstanding delete and move commands."
        !           240:   (interactive)
        !           241:   (if mh-narrowed-to-seq (mh-widen))
        !           242:   (save-excursion
        !           243:     (mh-process-commands mh-current-folder))
        !           244:   (delete-other-windows)
        !           245:   (setq mh-summarize t)
        !           246:   (setq mode-name "Mh-Summary")
        !           247:   (setq mode-line-format (mh-make-mode-line)))
        !           248: 
        !           249: 
        !           250: (defun mh-extract-rejected-mail ()
        !           251:   "Extract a letter returned by the mail system and make it resendable."
        !           252:   (interactive "")
        !           253:   (let ((msg-filename (format "%s%d" mh-folder-filename (mh-get-msg-num t))))
        !           254:     (mh-read-draft)
        !           255:     (when (or (zerop (buffer-size))
        !           256:              (not (y-or-n-p "The file 'draft' exists.  Use it? ")))
        !           257:       (erase-buffer)
        !           258:       (insert-file-contents msg-filename))
        !           259:     (goto-char (point-min))
        !           260:     (re-search-forward mh-rejected-letter-start)
        !           261:     (forward-char 1)
        !           262:     (kill-region (point-min) (point))
        !           263:     (let ((mh-invisible-headers "^Date:\\|^Received:\\|^Message-Id:\\|^From:"))
        !           264:       (mh-clean-msg-header (point-min)))
        !           265:     (goto-char (point-min))
        !           266:     (switch-to-buffer mh-current-folder)
        !           267:     (mh-compose-and-send-mail "" mh-current-folder (mh-get-field "To")
        !           268:                              (mh-get-field "From") (mh-get-field "cc"))))
        !           269: 
        !           270: 
        !           271: (defun mh-forward (&optional seq)
        !           272:   "Forward a letter.  Optional argument is a SEQUENCE of messages to forward."
        !           273:   (interactive "P")
        !           274:   (let ((to (read-string "To: "))
        !           275:        (cc (read-string "Cc: "))
        !           276:        (msg-filename (mh-msg-filename))
        !           277:        (msg (if seq seq (mh-get-msg-num t)))
        !           278:        (folder mh-current-folder))
        !           279:     (cond ((or (not (file-exists-p (format "%sdraft" mh-user-path)))
        !           280:               (y-or-n-p "The file 'draft' exists.  Discard it? "))
        !           281:           (mh-exec-cmd "forw" "-build" mh-current-folder msg)
        !           282:           (mh-read-draft)
        !           283:           (mh-insert-fields "To:" to "Cc:" cc)
        !           284:           (set-buffer-modified-p nil))
        !           285:          (t
        !           286:           (mh-read-draft)))
        !           287:     (goto-char (point-min))
        !           288:     (re-search-forward "^------- Forwarded Message")
        !           289:     (previous-line 1)
        !           290:     (narrow-to-region (point) (point-max))
        !           291:     (let* ((subject (save-excursion (mh-get-field "From:")))
        !           292:           (trim (string-match "<" subject))
        !           293:           (forw-subject (save-excursion (mh-get-field "Subject:"))))
        !           294:       (if trim
        !           295:          (setq subject (substring subject 0 (1- trim))))
        !           296:       (widen)
        !           297:       (save-excursion
        !           298:        (mh-insert-fields "Subject:" (format "[%s: %s]" subject forw-subject)))
        !           299:       (delete-other-windows)
        !           300:       (if seq
        !           301:          (mh-add-msg-list-to-seq (mh-seq-to-msgs seq) "forwarded" t)
        !           302:          (mh-add-msg-to-seq msg "forwarded" t))
        !           303:       (mh-compose-and-send-mail "" folder to subject cc "F" "Forwarded:"))))
        !           304: 
        !           305: 
        !           306: (defun mh-goto-msg (number &optional no-error-if-no-message)
        !           307:   "Position the cursor at message NUMBER.  Do not signal an error if optional
        !           308: ARG is t.  Return non-nil if cursor is at message."
        !           309:   (interactive "nMessage number? ")
        !           310:   (let ((starting-place (point)))
        !           311:     (goto-char (point-min))
        !           312:     (cond ((not (re-search-forward (mh-msg-search-pat number) nil t))
        !           313:           (goto-char starting-place)
        !           314:           (if (not no-error-if-no-message) (error "No message %d " number))
        !           315:           nil)
        !           316:          (t
        !           317:           (beginning-of-line)
        !           318:           (mh-maybe-show)
        !           319:           t))))
        !           320: 
        !           321: 
        !           322: (defun mh-inc-folder ()
        !           323:   "inc(orporate) new mail into inbox."
        !           324:   (interactive)
        !           325:   (pop-to-buffer "+inbox")
        !           326:   (if (or (not (boundp 'mh-current-folder)) (null mh-current-folder))
        !           327:       (mh-make-folder "+inbox"))
        !           328:   (if (mh-get-new-mail)
        !           329:       (mh-show)))
        !           330: 
        !           331: 
        !           332: (defun mh-kill-folder ()
        !           333:   "Removes the current folder."
        !           334:   (interactive)
        !           335:   (if (yes-or-no-p (format "Remove folder %s? " mh-current-folder))
        !           336:       (let ((folder mh-current-folder))
        !           337:        (switch-to-buffer-other-window " *mh-temp*")
        !           338:        (mh-exec-cmd "rmf" "-nointeractive" folder)
        !           339:        (mh-remove-folder-from-folder-list folder)
        !           340:        (message "Folder removed")
        !           341:        (kill-buffer folder))
        !           342:       (message "Folder not removed")))
        !           343: 
        !           344: 
        !           345: (defun mh-list-folders ()
        !           346:   "List mail folders."
        !           347:   (interactive)
        !           348:   (message "listing folders...")
        !           349:   (switch-to-buffer-other-window " *mh-temp*")
        !           350:   (erase-buffer)
        !           351:   (mh-exec-cmd-output "folders")
        !           352:   (goto-char (point-min))
        !           353:   (message "listing folders...done"))
        !           354: 
        !           355: 
        !           356: (defun mh-msg-is-in-seq ()
        !           357:   "Displays the sequences that the current messages is in."
        !           358:   (interactive)
        !           359:   (let ((msg (mh-get-msg-num t))
        !           360:        (l mh-seq-list)
        !           361:        (seqs ""))
        !           362:       (while l
        !           363:        (if (memq msg (cdar l))
        !           364:            (setq seqs (format "%s %s" (symbol-name (caar l)) seqs)))
        !           365:        (setq l (cdr l)))
        !           366:       (message "Message %d is in sequences: %s" msg seqs)))
        !           367: 
        !           368: 
        !           369: (defun mh-move-msg (&optional seq)
        !           370:   "Move specified message(s) to another folder.  Optional argument is a
        !           371: SEQUENCE of messages to refile."
        !           372:   (interactive "P")
        !           373:   (setq mh-last-destination
        !           374:        (cons 'move (intern (mh-prompt-for-folder "Destination" "" t))))
        !           375:   (if seq
        !           376:       (mh-map-to-seq-msgs 'mh-move-a-msg seq (cdr mh-last-destination))
        !           377:       (mh-move-a-msg (cdr mh-last-destination)))
        !           378:   (mh-next-msg))
        !           379: 
        !           380: 
        !           381: (defun mh-move-or-write-again ()
        !           382:   "Move or write the current message to same folder or file as the last move
        !           383: or write."
        !           384:   (interactive)
        !           385:   (if (null mh-last-destination)
        !           386:       (error "No previous move"))
        !           387:   (cond ((eq (car mh-last-destination) 'move)
        !           388:         (mh-move-a-msg (cdr mh-last-destination))
        !           389:         (message "Destination folder: %s" (cdr mh-last-destination)))
        !           390:        (t
        !           391:         (mh-write-msg-to-file (cdr mh-last-destination))
        !           392:         (message "Destination: %s" (cdr mh-last-destination))))
        !           393:   (sit-for 3)
        !           394:   (mh-next-msg))
        !           395: 
        !           396: 
        !           397: (defun mh-narrow-to-seq ()
        !           398:   "Restrict the display of the current folder to the messages in the sequence
        !           399: to be prompted for.  Use \\[mh-widen] to undo this command."
        !           400:   (interactive "")
        !           401:   (let ((seq (mh-read-seq "Narrow to"))
        !           402:        (eob (point-max))
        !           403:        (buffer-read-only nil))
        !           404:     (cond ((mh-seq-to-msgs seq)
        !           405:           (mh-copy-seq-to-point seq eob)
        !           406:           (narrow-to-region eob (point-max))
        !           407:           (setq mode-line-format (mh-make-mode-line (symbol-name seq)))
        !           408:           (recenter)
        !           409:           (setq mh-narrowed-to-seq seq))
        !           410:          (t
        !           411:           (error "No messages in sequence `%s'" (symbol-name seq))))))
        !           412: 
        !           413: 
        !           414: (defun mh-next-line (&optional arg)
        !           415:   "Move to next undeleted message in window and display body if summary
        !           416: flag set."
        !           417:   (interactive "p")
        !           418:   (forward-line (if arg arg 1))
        !           419:   (setq mh-next-direction 'forward)
        !           420:   (cond ((re-search-forward mh-good-msg-regexp nil 0 arg)
        !           421:         (beginning-of-line)
        !           422:         (mh-maybe-show))
        !           423:        (t
        !           424:         (forward-line -1)
        !           425:         (sit-for 2)
        !           426:         (message "No more messages"))))
        !           427: 
        !           428: 
        !           429: (defun mh-renumber-folder ()
        !           430:   "Renumber messages in folder to be 1..N."
        !           431:   (interactive)
        !           432:   (message "packing buffer...")
        !           433:   (mh-pack-folder)
        !           434:   (mh-unmark-all-headers nil)
        !           435:   (mh-goto-cur-msg)
        !           436:   (message "packing buffer...done"))
        !           437: 
        !           438: 
        !           439: (defun mh-page-digest ()
        !           440:   "Advance displayed message to next digested message."
        !           441:   (interactive)
        !           442:   (save-excursion
        !           443:     (switch-to-buffer-other-window mh-show-buffer)
        !           444:     (move-to-window-line nil)
        !           445:     (let ((case-fold-search nil))
        !           446:       (when (not (search-forward "\nFrom:" nil t))
        !           447:        (other-window -1)
        !           448:        (error "No more messages")))
        !           449:     (recenter 0)
        !           450:     (other-window -1)))
        !           451: 
        !           452: 
        !           453: (defun mh-page-msg (&optional arg)
        !           454:   (interactive "P")
        !           455:   (scroll-other-window arg))
        !           456: 
        !           457: 
        !           458: (defun mh-previous-line (&optional arg)
        !           459:   "Move to previous message in window and display body if summary flag set."
        !           460:   (interactive "p")
        !           461:   (setq mh-next-direction 'backward)
        !           462:   (if (not (re-search-backward mh-good-msg-regexp nil 0 arg))
        !           463:       (message "Beginning of messages")
        !           464:       (mh-maybe-show)))
        !           465: 
        !           466: 
        !           467: (defun mh-previous-page ()
        !           468:   "Page the displayed message backwards."
        !           469:   (interactive)
        !           470:   (save-excursion
        !           471:     (switch-to-buffer-other-window mh-show-buffer)
        !           472:     (unwind-protect
        !           473:        (scroll-down nil)
        !           474:       (other-window -1))))
        !           475: 
        !           476: 
        !           477: (defun mh-print-msg (&optional seq)
        !           478:   "Print specified message(s) on a line printer.  Optional argument is a
        !           479: SEQUENCE of messages to print."
        !           480:   (interactive "P")
        !           481:   (let ((msgs (if seq
        !           482:                  (reverse (mh-seq-to-msgs seq))
        !           483:                  (list (mh-get-msg-num t)))))
        !           484:     (message "printing message...")
        !           485:     (call-process shell-file-name nil 0 nil "-c"
        !           486:                  (if seq
        !           487:                      (format "(scan -clear %s ; %smhl -nobell -clear %s) | %s"
        !           488:                              (mapconcat (function (lambda (msg) msg)) msgs " ")
        !           489:                              mh-lib
        !           490:                              (mh-msg-filenames msgs mh-folder-filename)
        !           491:                              (format mh-lpr-command-format
        !           492:                                      (if seq
        !           493:                                          "Mail"
        !           494:                                          (format "%s/%d" mh-current-folder
        !           495:                                                  (mh-get-msg-num t)))))
        !           496:                      (format "%smhl -nobell -clear %s | %s"
        !           497:                              mh-lib
        !           498:                              (mh-msg-filenames msgs mh-folder-filename)
        !           499:                              (format mh-lpr-command-format
        !           500:                                      (if seq
        !           501:                                          "Mail"
        !           502:                                          (format "%s/%d" mh-current-folder
        !           503:                                                  (mh-get-msg-num t)))))))
        !           504:     (if seq
        !           505:        (mh-notate-seq msgs ?P mh-cmd-note)
        !           506:        (mh-notate ?P mh-cmd-note))
        !           507:     (mh-add-msg-list-to-seq msgs 'printed t)
        !           508:     (message "printing message...done")))
        !           509: 
        !           510: 
        !           511: (defun mh-put-msg-in-seq (&optional arg)
        !           512:   "Add a message to a sequence or, if optional ARG is non-nil, add the
        !           513: messages from a sequence to another sequence."
        !           514:   (interactive "P")
        !           515:   (if arg
        !           516:       (mh-add-msg-list-to-seq (mh-seq-to-msgs
        !           517:                               (mh-read-seq "Add messages from"))
        !           518:                              (mh-read-seq "to"))
        !           519:       (mh-add-msg-to-seq (mh-get-msg-num t) (mh-read-seq "Add to")))
        !           520:   (mh-next-msg))
        !           521: 
        !           522: 
        !           523: (defun mh-rescan-folder (&optional arg)
        !           524:   "Rescan a folder after optionally processing the outstanding commands.  If
        !           525: the optional argument is non-nil, then prompt for the range of messages to
        !           526: display, otherwise assume the whole buffer."
        !           527:   (interactive "P")
        !           528:   (if (and (or mh-delete-list mh-move-list)
        !           529:           (y-or-n-p "Process commands? "))
        !           530:       (mh-process-commands mh-current-folder))
        !           531:   (setq mh-next-direction 'forward)
        !           532:   (mh-scan-folder mh-current-folder
        !           533:                  (if arg (read-string "Range [all]? ") "all")))
        !           534: 
        !           535: 
        !           536: (defun mh-redistribute (to cc)
        !           537:   "Redistribute a letter."
        !           538:   (interactive "sRedist-To: \nsRedist-Cc: ")
        !           539:   (let ((msg-filename (mh-msg-filename))
        !           540:        (msg (mh-get-msg-num t))
        !           541:        (folder mh-current-folder))
        !           542:     (save-window-excursion
        !           543:       (mh-read-draft)
        !           544:       (when (or (zerop (buffer-size))
        !           545:                (not (y-or-n-p
        !           546:                      "The file 'draft' exists.  Redistribute old version? ")))
        !           547:        (erase-buffer)
        !           548:        (insert-file-contents msg-filename))
        !           549:       (re-search-forward "^$\\|^---")
        !           550:       (insert "Resent-To: " to "\n")
        !           551:       (if (not (equal cc ""))
        !           552:          (insert "Resent-cc: " cc "\n"))
        !           553:       (let ((mh-invisible-headers "^Message-Id:\\|^Received:\\|Return-Path:"))
        !           554:        (mh-clean-msg-header (point-min)))
        !           555:       (save-buffer)
        !           556:       (message "Redistributing...")
        !           557:       (call-process "/bin/sh" nil 0 nil "-c"
        !           558:        (format "mhdist=1 mhaltmsg=%s %s/send -push %s/draft"
        !           559:               msg-filename mh-progs mh-user-path))
        !           560:       (mh-annotate-msg msg folder "R"
        !           561:                       "-component" "Resent:"
        !           562:                       "-text" (format "\"%s %s\"" to cc))
        !           563:       (message "Redistributing...done"))))
        !           564: 
        !           565: 
        !           566: (defun mh-write-msg-to-file (file)
        !           567:   "Append the current message to the end of a file."
        !           568:   (interactive "FSave message in file: ")
        !           569:   (setq mh-last-destination (cons 'write file))
        !           570:   (call-process shell-file-name nil 0 nil "-c"
        !           571:                (format "cat %s >> %s " (mh-msg-filename) file)))
        !           572: 
        !           573: 
        !           574: (defun mh-search-folder ()
        !           575:   "Search the current folder for messages matching a pattern."
        !           576:   (interactive)
        !           577:   (let ((folder mh-current-folder))
        !           578:     (switch-to-buffer-other-window "pick-pattern")
        !           579:     (if (or (zerop (buffer-size))
        !           580:            (not (y-or-n-p "Reuse pattern? ")))
        !           581:        (mh-make-pick-template)
        !           582:        (message ""))
        !           583:     (setq mh-searching-folder folder)))
        !           584: 
        !           585: 
        !           586: (defun mh-send (to cc subject)
        !           587:   "Compose and send a letter."
        !           588:   (interactive "sTo: \nsCc: \nsSubject: ")
        !           589:   (let ((folder (if (boundp 'mh-current-folder) mh-current-folder)))
        !           590:     (message "Composing a message...")
        !           591:     (mh-read-draft)
        !           592:     (delete-other-windows)
        !           593:     (when (or (zerop (buffer-size))
        !           594:              (not (y-or-n-p "The file 'draft' exists.  Use it? ")))
        !           595:       (erase-buffer)
        !           596:       (if (file-exists-p (format "%scomponents" mh-user-path))
        !           597:          (insert-file-contents (format "%scomponents" mh-user-path))
        !           598:          (if (file-exists-p (format "%scomponents" mh-lib))
        !           599:              (insert-file-contents (format "%scomponents" mh-lib))
        !           600:              (error "Can't find components")))
        !           601:       (mh-insert-fields "To:" to "Subject:" subject "Cc:" cc)
        !           602:       (set-buffer-modified-p nil)
        !           603:       (goto-char (point-max))
        !           604:       (message "Composing a message...done"))
        !           605:     (mh-compose-and-send-mail "" folder to subject cc)))
        !           606: 
        !           607: 
        !           608: (defun mh-show ()
        !           609:   "Show message indicated by cursor in scan buffer."
        !           610:   (interactive)
        !           611:   (setq mh-summarize nil)
        !           612:   (setq mode-name "Mh-Show")
        !           613:   (let ((msg-num (mh-get-msg-num t))
        !           614:        (folder mh-current-folder))
        !           615:     (mh-display-msg msg-num (mh-msg-filename) mh-show-buffer)
        !           616: 
        !           617:     ;; These contortions are to force the summary line to be the top window.
        !           618:     (switch-to-buffer-other-window folder)
        !           619:     (delete-other-windows)
        !           620:     (switch-to-buffer-other-window mh-show-buffer)
        !           621:     (switch-to-buffer-other-window folder)
        !           622:     (shrink-window (- (window-height) mh-summary-height))
        !           623:     (recenter 1)
        !           624:     (push msg-num mh-seen-list)))
        !           625: 
        !           626: 
        !           627: (defun mh-sort-folder ()
        !           628:   "Sort the messages in the current folder by date."
        !           629:   (interactive "")
        !           630:   (mh-process-commands mh-current-folder)
        !           631:   (setq mh-next-direction 'forward)
        !           632:   (message "sorting folder...")
        !           633:   (mh-exec-cmd "sortm" mh-current-folder)
        !           634:   (message "sorting folder...done")
        !           635:   (mh-scan-folder mh-current-folder "all"))
        !           636: 
        !           637: 
        !           638: (defun mh-toggle-summarize ()
        !           639:   "Turn the summary mode of displaying messages on or off."
        !           640:   (interactive)
        !           641:   (setq mh-summarize (not mh-summarize))
        !           642:   (cond (mh-summarize
        !           643:         (delete-other-windows)
        !           644:         (setq mode-name "Mh-Summarize")
        !           645:         (recenter (/ (window-height) 2)))
        !           646:        (t
        !           647:         (setq mode-name "Mh-Show")
        !           648:         (mh-show))))
        !           649: 
        !           650: 
        !           651: (defun mh-undo (&optional seq)
        !           652:   "Undo the deletion or move of the specified message(s).  Optional argument
        !           653: is a name of a sequence of messages to apply undo to."
        !           654:   (interactive "P")
        !           655:   (cond ((looking-at "^....D")
        !           656:         (cond (seq
        !           657:                (mapc (function (lambda (msg)
        !           658:                                  (setq mh-delete-list
        !           659:                                        (delq msg mh-delete-list))
        !           660:                                  (mh-remove-msg-from-seq msg 'deleted)))
        !           661:                      (mh-seq-to-msgs seq))
        !           662:                (mh-notate-seq seq ?  mh-cmd-note))
        !           663:               (t
        !           664:                (let ((msg (mh-get-msg-num t)))
        !           665:                  (setq mh-delete-list (delq msg mh-delete-list))
        !           666:                  (mh-remove-msg-from-seq msg 'deleted)
        !           667:                  (mh-notate ?  mh-cmd-note)))))
        !           668: 
        !           669:        ((looking-at "^....\\^")
        !           670:         (cond (seq
        !           671:                (mapc (function (lambda (msg)
        !           672:                                  (mapc (function
        !           673:                                         (lambda (dest)
        !           674:                                           (mh-remove-msg-from-seq msg dest)))
        !           675:                                        mh-move-list)))
        !           676:                      (mh-seq-to-msgs seq))
        !           677:                (mh-notate-seq seq ?  mh-cmd-note))
        !           678:               (t
        !           679:                (let ((msg (mh-get-msg-num t)))
        !           680:                  (mapc (function (lambda (dest)
        !           681:                                    (mh-remove-msg-from-seq msg dest)))
        !           682:                        mh-move-list)
        !           683:                  (mh-notate ?  mh-cmd-note)))))
        !           684: 
        !           685:        (t nil)))
        !           686: 
        !           687: 
        !           688: (defun mh-undo-folder ()
        !           689:   "Undo all commands in current folder."
        !           690:   (interactive "")
        !           691:   (cond ((yes-or-no-p "Undo all commands in folder? ")
        !           692:         (setq mh-delete-list nil
        !           693:               mh-move-list nil
        !           694:               mh-seq-list nil
        !           695:               mh-next-direction 'forward)
        !           696:         (mh-unmark-all-headers t))
        !           697:        (t
        !           698:         (message "Commands not undone."))))
        !           699: 
        !           700: 
        !           701: (defun mh-visit-folder (&optional arg)
        !           702:   "Visit a new folder.  If optional argument is non-nil, then prompt for the
        !           703: range of messages, otherwise scan the whole buffer."
        !           704:   (interactive "p")
        !           705:   (let ((folder (mh-prompt-for-folder "Visit" "" t))
        !           706:        (range (if arg (read-string "Range [all]? ") "all")))
        !           707:     (mh-scan-folder folder (if (equal range "") "all" range))
        !           708:     (delete-other-windows)))
        !           709: 
        !           710: 
        !           711: (defun mh-widen ()
        !           712:   "Remove restrictions from the current folder, thereby showing all messages."
        !           713:   (interactive "")
        !           714:   (let ((buffer-read-only nil))
        !           715:     (delete-region (point-min) (point-max))
        !           716:     (widen)
        !           717:     (setq mode-line-format (mh-make-mode-line)))
        !           718:   (setq mh-narrowed-to-seq nil))
        !           719: 
        !           720: 
        !           721: 
        !           722: ;;; Support routines.
        !           723: 
        !           724: (defun mh-delete-a-msg ()
        !           725:   "Delete the message pointed to by the cursor."
        !           726:   (let ((msg (mh-get-msg-num t)))
        !           727:     (if (looking-at "....\\^")
        !           728:        (error "Message %d already moved.  Undo move before deleting." msg))
        !           729:     (push msg mh-delete-list)
        !           730:     (mh-add-msg-to-seq msg 'deleted t)
        !           731:     (mh-notate ?D mh-cmd-note)))
        !           732: 
        !           733: 
        !           734: (defun mh-move-a-msg (destination)
        !           735:   "Move the message pointed to by the cursor."
        !           736:   (if (looking-at "....D")
        !           737:       (error "Message %d is already deleted.  Undo delete before moving."
        !           738:             (mh-get-msg-num nil))
        !           739:       (let ((msg (mh-get-msg-num t)))
        !           740:        (if (not (memq destination mh-move-list))
        !           741:            (push destination mh-move-list))
        !           742:        (mh-add-msg-to-seq msg destination t)
        !           743:        (mh-notate ?^ mh-cmd-note))))
        !           744: 
        !           745: 
        !           746: (defun mh-display-msg (msg-num msg-filename show-buffer)
        !           747:   "Displays the message NUMBER and PATHNAME in BUFFER."
        !           748:   (if (not (file-exists-p msg-filename))
        !           749:       (error "Message %d does not exist." msg-num))
        !           750:   (switch-to-buffer show-buffer)
        !           751:   (buffer-flush-undo (current-buffer))
        !           752:   (when (not (equal msg-filename buffer-file-name))
        !           753:     ;; Buffer does not yet contain message.
        !           754:     (setq buffer-file-name msg-filename)
        !           755:     (erase-buffer)
        !           756:     (unlock-buffer)
        !           757:     (if mh-use-mhl
        !           758:        (mh-exec-lib-cmd-output "mhl" "-nobell" "-noclear" msg-filename)
        !           759:        (insert-file-contents msg-filename))
        !           760:     (goto-char (point-min))
        !           761:     (cond (mh-clean-message-header
        !           762:           (mh-clean-msg-header (point-min))
        !           763:           (goto-char (point-min)))
        !           764:          (t
        !           765:           (let ((case-fold-search t))
        !           766:             (re-search-forward "^To:\\|^From:\\|^Subject:\\|^Date:" nil t)
        !           767:             (beginning-of-line)
        !           768:             (recenter 0))))
        !           769:     (set-buffer-modified-p nil)
        !           770:     (setq mode-line-format
        !           771:          (concat "{%b} %[%p of " folder "/" msg-num "%]        %M"))))
        !           772: 
        !           773: 
        !           774: (defun mh-clean-msg-header (start)
        !           775:   "Flush extraneous lines in a message header.  The variable
        !           776: mh-invisible-headers contains a regular expression specifying these lines."
        !           777:   (save-restriction
        !           778:     (goto-char start)
        !           779:     (search-forward "\n\n" nil t)
        !           780:     (narrow-to-region start (point))
        !           781:     (goto-char (point-min))
        !           782:     (while (re-search-forward mh-invisible-headers nil t)
        !           783:       (beginning-of-line)
        !           784:       (kill-line 1)
        !           785:       (while (looking-at "^[ \t]+")
        !           786:        (beginning-of-line)
        !           787:        (kill-line 1)))
        !           788:     (unlock-buffer)))
        !           789: 
        !           790: 
        !           791: (defun mh-read-draft ()
        !           792:   "Read draft file into draft buffer.  Avoids errors even if disk file has been
        !           793: modified underneath the buffer.  Causes an error if the folder is modified and
        !           794: the user does not want to change it."
        !           795:   (switch-to-buffer "draft")
        !           796:   (if (buffer-modified-p)
        !           797:       (if (y-or-n-p "Draft is modified; kill anyways? ")
        !           798:          (set-buffer-modified-p nil)
        !           799:          (error "Draft is not killed.")))
        !           800:   (kill-buffer "draft")
        !           801:   (switch-to-buffer-other-window
        !           802:    (find-file-noselect (format "%sdraft" mh-user-path))))
        !           803: 
        !           804: 
        !           805: (defun mh-next-msg ()
        !           806:   "Move backward or forward to the next message in the buffer."
        !           807:   (if (eq mh-next-direction 'forward)
        !           808:       (mh-next-line 1)
        !           809:       (mh-previous-line 1)))
        !           810: 
        !           811: 
        !           812: (defun mh-maybe-show ()
        !           813:   "If the scan listing is not summarized, show the message pointed to
        !           814: by the cursor."
        !           815:   (if (not mh-summarize) (mh-show)))
        !           816: 
        !           817: 
        !           818: 
        !           819: ;;; The folder data abstraction.
        !           820: 
        !           821: (defun mh-make-folder (name)
        !           822:   "Create and initialize a new mail folder called NAME and make it the
        !           823: current folder."
        !           824:   (switch-to-buffer name)
        !           825:   (buffer-flush-undo (current-buffer))
        !           826:   (kill-all-local-variables)
        !           827:   (setq buffer-read-only nil)
        !           828:   (erase-buffer)
        !           829:   (make-local-vars
        !           830:    'mh-current-folder name             ;Name of folder
        !           831:    'mh-show-buffer (format "show-%s" name) ; Buffer that displays messages
        !           832:    'mh-folder-filename                 ; e.g. /usr/foobar/Mail/inbox/
        !           833:      (format "%s%s/" mh-user-path (substring name 1))
        !           834:    'mh-summarize t                     ; Show scan list only?
        !           835:    'mh-next-seq-num 0                  ; Index of free sequence id
        !           836:    'mh-delete-list nil                 ; List of msgs nums to delete
        !           837:    'mh-move-list nil                   ; List of folder names in mh-seq-list
        !           838:    'mh-seq-list nil                    ; Alist of seq . msgs nums
        !           839:    'mh-seen-list nil                   ; List of displayed messages
        !           840:    'mh-next-direction 'forward         ; Direction to move to next message
        !           841:    'mh-narrowed-to-seq nil)            ; Sequence display is narrowed to
        !           842:   (mh-folder-mode)
        !           843:   (setq buffer-read-only t)
        !           844:   (setq mode-name "Mh-Summarize"))
        !           845: 
        !           846: 
        !           847: (defun make-local-vars (&rest pairs)
        !           848:   "Takes VARIABLE-VALUE pairs and makes local variables initialized to the
        !           849: value."
        !           850:   (while pairs
        !           851:     (make-local-variable (car pairs))
        !           852:     (set (car pairs) (cadr pairs))
        !           853:     (setq pairs (cddr pairs))))
        !           854: 
        !           855: 
        !           856: (defun mh-folder-mode ()
        !           857:   "Major mode for \"editing\" an MH folder scan listing.
        !           858: Messages can be marked for refiling and deletion.  However, both actions
        !           859: are defered until you request execution with \\[mh-execute-commands].
        !           860: \\{mh-folder-mode-map}
        !           861:   A prefix argument (\\[universal-argument]) to delete, move, list, or undo applies the action to a message sequence.
        !           862: 
        !           863: Variables controlling mh-e operation are (defaults in parentheses):
        !           864: 
        !           865:  mh-auto-fill-letters (t)
        !           866:     Non-nil means invoke auto-fill-mode in draft messages.
        !           867: 
        !           868:  mh-clean-message-header (nil)
        !           869:     Non-nil means remove header lines matching the regular expression
        !           870:     specified in mh-invisible-headers from messages.
        !           871: 
        !           872:  mh-use-mhl (nil)
        !           873:     Non-nil means use mhl to format displayed messages.
        !           874: 
        !           875:  mh-lpr-command-format (\"lpr -p -J '%s'\")
        !           876:     Format for command used to print a message on a system printer.
        !           877: 
        !           878:  mh-summary-height (4)
        !           879:     Number of lines in the summary window.
        !           880: 
        !           881:  mh-ins-buf-prefix (\">> \")
        !           882:     String to insert before each non-blank line of a message as it is
        !           883:     inserted in a letter being composed."
        !           884: 
        !           885:   (use-local-map mh-folder-mode-map)
        !           886:   (setq major-mode 'mh-folder-mode)
        !           887:   (setq mode-name "mh-folder")
        !           888:   (if (and (boundp 'mh-folder-mode-hook) mh-folder-mode-hook)
        !           889:       (funcall mh-folder-mode-hook)))
        !           890: 
        !           891: 
        !           892: (defun mh-scan-folder (folder range)
        !           893:   "Scan the folder FOLDER over the range RANGE.  Return in the folder."
        !           894:   (cond ((null (get-buffer folder))
        !           895:         (mh-make-folder folder))
        !           896:        (t
        !           897:         (if (or mh-delete-list mh-move-list mh-seq-list)
        !           898:             (if (y-or-n-p "Process commands?")
        !           899:                 (mh-process-commands folder)
        !           900:                 (mh-undo-folder)))
        !           901:         (switch-to-buffer-other-window folder)))
        !           902:   (mh-regenerate-headers range)
        !           903:   (when (= (count-lines (point-min) (point-max)) 0)
        !           904:     (if (equal range "all")
        !           905:        (message  "Folder %s is empty" folder)
        !           906:        (message  "No messages in %s, range %s" folder range))
        !           907:     (sit-for 5))
        !           908:   (setq mode-line-format (mh-make-mode-line))
        !           909:   (mh-unmark-all-headers nil)
        !           910:   (mh-goto-cur-msg))
        !           911: 
        !           912: 
        !           913: (defun mh-regenerate-headers (range)
        !           914:   "Replace buffer with scan of its contents over range RANGE."
        !           915:   (let ((buffer-read-only nil))
        !           916:     (message (format "scanning %s..." (buffer-name)))
        !           917:     (delete-other-windows)
        !           918:     (erase-buffer)
        !           919:     (mh-exec-cmd-output "scan" "-noclear" "-noheader" (buffer-name) range)
        !           920:     (goto-char (point-min))
        !           921:     (cond ((looking-at "scan: no messages in")
        !           922:           (keep-lines "^[ ]*[0-9]"))   ; Flush random scan lines
        !           923:          ((looking-at "scan: "))       ; Keep error messages
        !           924:          (t
        !           925:           (keep-lines "^[ ]*[0-9]")))  ; Flush random scan lines
        !           926:     (message (format "scanning %s...done" (buffer-name)))))
        !           927: 
        !           928: 
        !           929: (defun mh-get-new-mail ()
        !           930:   "Read new mail into the current buffer.  Return t if there was new mail,
        !           931: nil otherwise.  Leave cursor in current buffer."
        !           932:   (let ((buffer-read-only nil)
        !           933:        (point-before-inc (point)))
        !           934:     (message (format "inc %s..." (buffer-name)))
        !           935:     (mh-unmark-all-headers nil)
        !           936:     (setq mh-next-direction 'forward)
        !           937:     (flush-lines "^inc:\\|^scan:")     ; Kill old error messages
        !           938:     (goto-char (point-max))
        !           939:     (let ((start-of-inc (point)))
        !           940:       (mh-exec-cmd-output "inc")
        !           941:       (goto-char start-of-inc)
        !           942:       (message (format "inc %s...done" (buffer-name)))
        !           943:       (cond ((looking-at "inc: no mail")
        !           944:             (keep-lines "^[ ]*[0-9]")  ; Flush random scan lines
        !           945:             (setq mode-line-format (mh-make-mode-line))
        !           946:             (goto-char point-before-inc)
        !           947:             (message "No new mail.")
        !           948:             nil)
        !           949:            ((looking-at "inc:")        ; Error messages
        !           950:             (setq mode-line-format (mh-make-mode-line))
        !           951:             (goto-char point-before-inc)
        !           952:             (message "inc error")
        !           953:             nil)
        !           954:            (t
        !           955:             (keep-lines "^[ ]*[0-9]")
        !           956:             (setq mode-line-format (mh-make-mode-line))
        !           957:             (mh-goto-cur-msg)
        !           958:             t)))))
        !           959: 
        !           960: 
        !           961: (defun mh-make-mode-line (&optional annotation)
        !           962:   "Returns a string for mode-line-format.  The optional ANNOTATION string is
        !           963: displayed after the folder's name."
        !           964:   (save-excursion
        !           965:     (goto-char (point-min))
        !           966:     (let ((lines (count-lines (point-min) (point-max))))
        !           967:       (let* ((first (mh-get-msg-num nil))
        !           968:             (case-fold-search nil)
        !           969:             (current (and (re-search-forward "....\\+" nil t)
        !           970:                           (mh-get-msg-num nil))))
        !           971:        (goto-char (point-max))
        !           972:        (previous-line 1)
        !           973:        (let ((last (mh-get-msg-num nil)))
        !           974:          (format "{%%b%s}  [%d messages%s%s]  (%%p%%%% - %%m)  %%M"
        !           975:                  (if annotation (format "/%s" annotation) "")
        !           976:                  lines
        !           977:                  (if (> lines 0)
        !           978:                      (format "  (%d - %d)" first last)
        !           979:                      "")
        !           980:                  (if current
        !           981:                      (format "  cur = %d" current)
        !           982:                      "")))))))
        !           983: 
        !           984: 
        !           985: (defun mh-unmark-all-headers (remove-all-flags)
        !           986:   "This function removes all + flags from the headers, and if called
        !           987:   with a non-nil argument, removes all D and ^ flags too."
        !           988:   (let ((buffer-read-only nil)
        !           989:        (case-fold-search nil))
        !           990:     (goto-char (point-min))
        !           991:     (while (if remove-all-flags
        !           992:               (re-search-forward "^....\\D\\|^....\\^\\|^....\\+\\|.....%"
        !           993:                                  nil t)
        !           994:               (re-search-forward "^....\\+" nil t))
        !           995:       (delete-backward-char 1)
        !           996:       (insert " "))))
        !           997: 
        !           998: 
        !           999: (defun mh-goto-cur-msg ()
        !          1000:   "Position the cursor at the current message."
        !          1001:   (let ((curmsg (mh-get-cur-msg mh-current-folder)))
        !          1002:     (cond ((or (zerop curmsg) (not (mh-goto-msg curmsg t)))
        !          1003:           (goto-char (point-max))
        !          1004:           (forward-line -1)
        !          1005:           (mh-maybe-show)
        !          1006:           (message "No current message"))
        !          1007:          (t
        !          1008:           (mh-notate ?+ 4)
        !          1009:           (recenter 0)))))
        !          1010: 
        !          1011: 
        !          1012: (defun mh-pack-folder ()
        !          1013:   "Closes and packs the current folder."
        !          1014:   (let ((buffer-read-only nil))
        !          1015:     (message "closing folder...")
        !          1016:     (mh-process-commands mh-current-folder)
        !          1017:     (message "packing folder...")
        !          1018:     (mh-exec-cmd-quiet 0 "folder" mh-current-folder "-pack")
        !          1019:     (mh-regenerate-headers "all")
        !          1020:     (message "packing done"))
        !          1021:   (setq mode-line-format (mh-make-mode-line)))
        !          1022: 
        !          1023: 
        !          1024: (defun mh-process-commands (buffer)
        !          1025:   "Process outstanding commands for the buffer BUFFER."
        !          1026:   (message "Processing deletes and moves...")
        !          1027:   (switch-to-buffer buffer)
        !          1028:   (let ((buffer-read-only nil))
        !          1029:     ;; Sequences must be first
        !          1030:     (mh-process-seq-commands mh-seq-list)
        !          1031:     ;; Update the unseen sequence
        !          1032:     (if mh-seen-list
        !          1033:        (let ((unseen-seq (mh-get-profile-field "Unseen-Sequence:")))
        !          1034:          (if (null unseen-seq)         ; For MH.5
        !          1035:              (setq unseen-seq "unseen"))
        !          1036:          (apply 'mh-exec-cmd-quiet
        !          1037:                 (nconc (list 0 "mark" mh-current-folder)
        !          1038:                        mh-seen-list
        !          1039:                        (list "-sequence" unseen-seq "-delete")))))
        !          1040: 
        !          1041:     ;; Then refile messages
        !          1042:     (mapc (function
        !          1043:           (lambda (dest)
        !          1044:             (let ((msgs (mh-seq-to-msgs dest)))
        !          1045:               (when msgs
        !          1046:                 (mh-delete-scan-msgs msgs)
        !          1047:                 (apply 'mh-exec-cmd
        !          1048:                        (nconc (cons "refile" msgs)
        !          1049:                               (list "-src" buffer (symbol-name dest))))))))
        !          1050:          mh-move-list)
        !          1051: 
        !          1052:     ;; Now delete messages
        !          1053:     (when mh-delete-list
        !          1054:       (apply 'mh-exec-cmd
        !          1055:             (nconc (list "rmm" (format "%s" buffer)) mh-delete-list))
        !          1056:       (mh-delete-scan-msgs mh-delete-list))
        !          1057: 
        !          1058:     ;; Mark as cur message.
        !          1059:     (cond ((mh-get-msg-num nil)
        !          1060:           (mh-exec-cmd "mark" mh-current-folder (mh-get-msg-num nil)
        !          1061:                        "-seq" "cur" "-add" "-zero"))
        !          1062:          ((> (buffer-size) 0)          ; Some messages left in folder.
        !          1063:           (mh-exec-cmd "mark" mh-current-folder
        !          1064:                        "-seq" "cur" "-delete" "all")))
        !          1065: 
        !          1066:     (save-excursion
        !          1067:       (switch-to-buffer mh-show-buffer)
        !          1068:       (setq buffer-file-name nil))     ; Invalidate buffer file cache
        !          1069: 
        !          1070:     (setq mh-delete-list nil
        !          1071:          mh-move-list nil
        !          1072:          mh-seq-list nil
        !          1073:          mh-seen-list nil))
        !          1074:   (message "Processing deletes and moves...done"))
        !          1075: 
        !          1076: 
        !          1077: (defun mh-delete-scan-msgs (msgs)
        !          1078:   "Delete the scan listing lines for each of the msgs in the LIST."
        !          1079:   (save-excursion
        !          1080:     (goto-char (point-min))
        !          1081:     (while msgs
        !          1082:       (flush-lines (mh-msg-search-pat (car msgs)))
        !          1083:       (setq msgs (cdr msgs)))))
        !          1084: 
        !          1085: 
        !          1086: 
        !          1087: ;;; A mode for composing and sending a message.
        !          1088: 
        !          1089: (defun mh-letter-mode ()
        !          1090:     "Mode for composing letters in mh-e.
        !          1091: \\{mh-letter-mode-map}"
        !          1092:   (text-mode)
        !          1093:   (if mh-auto-fill-letters
        !          1094:       (auto-fill-mode 1))
        !          1095:   (make-local-variable 'paragraph-start)
        !          1096:   (setq paragraph-start (concat "^[ \t]*[-_][-_][-_]+$\\|" paragraph-start))
        !          1097:   (make-local-variable 'paragraph-separate)
        !          1098:   (setq paragraph-separate
        !          1099:        (concat "^[ \t]*[-_][-_][-_]+$\\|" paragraph-separate))
        !          1100:   (use-local-map mh-letter-mode-map)
        !          1101:   (setq major-mode 'mh-letter-mode)
        !          1102:   (setq mode-name "mh-letter")
        !          1103:   (if (and (boundp 'mh-letter-mode-hook) mh-letter-mode-hook)
        !          1104:       (funcall mh-letter-mode-hook)))
        !          1105: 
        !          1106: 
        !          1107: (defun mh-to-to ()
        !          1108:   "Move point to end of To: field."
        !          1109:   (interactive)
        !          1110:   (expand-abbrev)
        !          1111:   (mh-position-on-field "To:" t))
        !          1112: 
        !          1113: 
        !          1114: (defun mh-to-subject ()
        !          1115:   "Move point to end of Subject: field.  Creates the field if necessary"
        !          1116:   (interactive)
        !          1117:   (expand-abbrev)
        !          1118:   (when (not (mh-position-on-field "Subject:" t))
        !          1119:     (mh-position-on-field "To:" nil)
        !          1120:     (insert-string "\nSubject: ")))
        !          1121: 
        !          1122: 
        !          1123: (defun mh-to-cc ()
        !          1124:   "Move point to end of Cc: field.  Creates the field if necessary"
        !          1125:   (interactive)
        !          1126:   (expand-abbrev)
        !          1127:   (when (not (mh-position-on-field "Cc:" t))
        !          1128:     (mh-position-on-field "To:" nil)
        !          1129:     (insert-string "\nCc: ")))
        !          1130: 
        !          1131: 
        !          1132: (defun mh-to-bcc ()
        !          1133:   "Move point to end of Bcc: field.  Creates the field if necessary"
        !          1134:   (interactive)
        !          1135:   (expand-abbrev)
        !          1136:   (when (not (mh-position-on-field "Bcc:" t))
        !          1137:     (mh-position-on-field "To:" nil)
        !          1138:     (insert-string "\nBcc: ")))
        !          1139: 
        !          1140: 
        !          1141: (defun mh-to-fcc ()
        !          1142:   "Move point to end of Fcc: field.  Creates the field if necessary"
        !          1143:   (interactive)
        !          1144:   (expand-abbrev)
        !          1145:   (when (not (mh-position-on-field "Fcc:" t))
        !          1146:     (mh-position-on-field "To:" nil)
        !          1147:     (insert-string "\nFcc: ")))
        !          1148: 
        !          1149: 
        !          1150: (defun mh-check-whom ()
        !          1151:   "List recipients of the current message."
        !          1152:   (interactive)
        !          1153:   (let ((file-name (buffer-file-name)))
        !          1154:     (set-buffer-modified-p t)          ; Force writing of contents
        !          1155:     (save-buffer)
        !          1156:     (message "Checking recipients...")
        !          1157:     (switch-to-buffer-other-window "*Mail Recipients*")
        !          1158:     (bury-buffer (current-buffer))
        !          1159:     (erase-buffer)
        !          1160:     (mh-exec-cmd-output "whom" file-name)
        !          1161:     (other-window -1)
        !          1162:     (message "Checking recipients...done")))
        !          1163: 
        !          1164: 
        !          1165: 
        !          1166: ;;; Routines to make a search pattern and search for a message.
        !          1167: 
        !          1168: (defun mh-make-pick-template ()
        !          1169:   "Initialize a buffer with a template for a pick pattern."
        !          1170:   (erase-buffer)
        !          1171:   (kill-all-local-variables)
        !          1172:   (make-local-variable 'mh-searching-folder)
        !          1173:   (insert "From: \n"
        !          1174:          "To: \n"
        !          1175:          "Cc: \n"
        !          1176:          "Date: \n"
        !          1177:          "Subject: \n"
        !          1178:          "---------\n")
        !          1179:   (mh-letter-mode)
        !          1180:   (use-local-map mh-pick-mode-map)
        !          1181:   (setq mode-line-format "{%b}\tPick Pattern\t(^C^C to do search)")
        !          1182:   (goto-char (point-min))
        !          1183:   (end-of-line))
        !          1184: 
        !          1185: 
        !          1186: (defun mh-do-pick-search ()
        !          1187:   "Search the current folder for the messages matching the qualification
        !          1188: in the current buffer and make them into a sequence called `search'."
        !          1189:   (interactive)
        !          1190:   (let* ((pattern-buffer (buffer-name))
        !          1191:         (searching-buffer mh-searching-folder)
        !          1192:         (range "all")
        !          1193:         (pattern nil))
        !          1194:     (message "Searching...")
        !          1195:     (goto-char (point-min))
        !          1196:     (while (setq pattern (mh-next-pick-field pattern-buffer))
        !          1197:       (setq msgs
        !          1198:            (mh-seq-from-command searching-buffer
        !          1199:                                 'search
        !          1200:                                 (nconc (cons "pick" pattern)
        !          1201:                                        (list searching-buffer
        !          1202:                                              range
        !          1203:                                              "-sequence" "search"
        !          1204:                                              "-list"))))
        !          1205:       (setq range "search"))
        !          1206:     (message "Searching...done")
        !          1207:     (switch-to-buffer searching-buffer)
        !          1208:     (mh-notate-seq 'search ?% (+ mh-cmd-note 1))))
        !          1209: 
        !          1210: 
        !          1211: (defun mh-next-pick-field (buffer)
        !          1212:   "Return the next piece of a pick argument that can be extracted from the
        !          1213: BUFFER.  Returns nil if no pieces remain."
        !          1214:   (switch-to-buffer buffer)
        !          1215:   (let ((case-fold-search t))
        !          1216:     (cond ((eobp)
        !          1217:           nil)
        !          1218:          ((re-search-forward "^\\([a-z].*\\):[ \t]*\\([a-z0-9].*\\)$" nil t)
        !          1219:           (let* ((component
        !          1220:                   (format "-%s"
        !          1221:                           (downcase (buffer-substring (match-beginning 1)
        !          1222:                                                       (match-end 1)))))
        !          1223:                  (pat (buffer-substring (match-beginning 2) (match-end 2))))
        !          1224:               (forward-line 1)
        !          1225:               (list component pat)))
        !          1226:          ((re-search-forward "^-*$" nil t)
        !          1227:           (forward-char 1)
        !          1228:           (let ((body (buffer-substring (point) (point-max))))
        !          1229:             (if (and (> (length body) 0) (not (equal body "\n")))
        !          1230:                 (list "-search" body)
        !          1231:                 nil)))
        !          1232:          (t
        !          1233:           nil))))
        !          1234: 
        !          1235: 
        !          1236: 
        !          1237: ;;; Routines compose and send a letter.
        !          1238: 
        !          1239: (defun mh-compose-and-send-mail (send-args sent-from-folder to subject cc
        !          1240:                                           &optional annotate-char
        !          1241:                                           annotate-field search-prefix)
        !          1242:   "Edit and compose a draft message and send or save it.
        !          1243: SENT-FROM-FOLDER is buffer containing summary of current folder, if any.
        !          1244: SEND-ARGS is an optional argument passed to the send command.
        !          1245: The TO, SUBJECT, and CC fields are passed to the mh-compose-letter-hook.
        !          1246: If ANNOTATE-CHAR is non-null, it is used to notate the scan listing of the
        !          1247: current message.  In that case, the ANNOTATE-FIELD is used to build a string
        !          1248: for mh-annotate-msg."
        !          1249:   (let ((sent-from-msg))
        !          1250:     (save-window-excursion
        !          1251:       (when sent-from-folder
        !          1252:        (switch-to-buffer sent-from-folder)
        !          1253:        (setq sent-from-msg (mh-get-msg-num nil))))
        !          1254:     (pop-to-buffer "draft")
        !          1255:     (mh-letter-mode)
        !          1256:     (make-local-vars
        !          1257:      'mh-send-args send-args
        !          1258:      'mh-sent-from-folder sent-from-folder
        !          1259:      'mh-sent-from-msg sent-from-msg
        !          1260:      'mh-annotate-field annotate-field
        !          1261:      'mh-annotate-char annotate-char
        !          1262:      'mh-annotate-search-prefix (if search-prefix search-prefix ""))
        !          1263:     (setq mode-line-format "{%b}  %[Mail/draft%] (%p - %m) (^C^C to send) %M")
        !          1264:     (if (and (boundp 'mh-compose-letter-hook) mh-compose-letter-hook)
        !          1265:        (funcall mh-compose-letter-hook to subject cc))))
        !          1266: 
        !          1267: 
        !          1268: (defun mh-send-letter (&optional arg)
        !          1269:   "Send the letter in the current buffer.  If given an ARGUMENT, the delivery
        !          1270: process is monitored and displayed."
        !          1271:   (interactive "P")
        !          1272:   (save-buffer)
        !          1273:   (message "Sending...")
        !          1274:   (if arg
        !          1275:       (let ((from-buffer (buffer-name))
        !          1276:            (file-name (buffer-file-name)))
        !          1277:        (pop-to-buffer " *mh-temp*")
        !          1278:        (erase-buffer)
        !          1279:        (if mh-send-args
        !          1280:            (mh-exec-cmd-output "send" "-watch" "-unique" mh-send-args
        !          1281:                                file-name)
        !          1282:            (mh-exec-cmd-output "send" "-watch" "-unique" file-name))
        !          1283:        (pop-to-buffer from-buffer))
        !          1284:       (if mh-send-args
        !          1285:          (mh-exec-cmd-quiet 0 "send" "-push" "-unique" mh-send-args
        !          1286:                             (buffer-file-name))
        !          1287:          (mh-exec-cmd-quiet 0 "send" "-push" "-unique" (buffer-file-name))))
        !          1288:   (if mh-annotate-char
        !          1289:       (mh-annotate-msg mh-sent-from-msg
        !          1290:                       mh-sent-from-folder
        !          1291:                       mh-annotate-char
        !          1292:                       "-component" mh-annotate-field
        !          1293:                       "-text" (format "\"%s %s\""
        !          1294:                                       (mh-get-field
        !          1295:                                        (format "%s%s"
        !          1296:                                                mh-annotate-search-prefix
        !          1297:                                                "To:"))
        !          1298:                                       (mh-get-field
        !          1299:                                        (format "%s%s"
        !          1300:                                                mh-annotate-search-prefix
        !          1301:                                                "Cc:")))))
        !          1302:   (message "Sending...done")
        !          1303:   (kill-buffer (buffer-name)))
        !          1304: 
        !          1305: 
        !          1306: (defun mh-insert-letter (&optional arg)
        !          1307:   "Insert a message in the current letter, asking for folder and number.
        !          1308: Removes headers using mh-invisible-headers.
        !          1309: Prefixes each non-blank line with mh-ins-buf-prefix (default \">> \").
        !          1310: Just \\[universal-argument] means do not indent and do not delete any
        !          1311: header fields.  Leaves point before the text and mark after it."
        !          1312:   (interactive "p")
        !          1313:   (let ((folder (mh-prompt-for-folder "Message from" mh-sent-from-folder nil))
        !          1314:        (message (read-input (format "Message number%s: "
        !          1315:                                     (if mh-sent-from-msg
        !          1316:                                         (format " [%d]" mh-sent-from-msg)
        !          1317:                                         ""))))
        !          1318:        (start (point)))
        !          1319:     (if (equal message "") (setq message (format "%d" mh-sent-from-msg)))
        !          1320:     (mh-exec-lib-cmd-output "mhl" "-nobell" "-noclear"
        !          1321:                            (format "%s%s/%s" mh-user-path
        !          1322:                                    (substring folder 1) message))
        !          1323:     (when (not (equal arg 4))
        !          1324:       (mh-clean-msg-header start)
        !          1325:       (narrow-to-region start (mark))
        !          1326:       (mh-insert-prefix-string mh-ins-buf-prefix)
        !          1327:       (widen))
        !          1328:     (exchange-point-and-mark)))
        !          1329: 
        !          1330: 
        !          1331: (defun mh-insert-cur-msg ()
        !          1332:   "Inserts the currently displayed message into the current draft buffer.
        !          1333: Prefixes each non-blank line with the string mh-ins-buf-prefix.
        !          1334: If there is a region set in the  message's buffer,only the region will
        !          1335: be inserted.  Otherwise, the region from (point) to the end will be grabbed."
        !          1336:   (interactive)
        !          1337:   (let ((to-point (point))
        !          1338:        (to-buffer (current-buffer)))
        !          1339:     (set-buffer mh-sent-from-folder)
        !          1340:     (set-buffer mh-show-buffer)                ; Find displayed message
        !          1341:     (let  ((mh-ins-str (if (mark)
        !          1342:                           (buffer-substring (point) (mark))
        !          1343:                           (buffer-substring (point) (point-max)))))
        !          1344:       (set-buffer to-buffer)
        !          1345:       (narrow-to-region to-point to-point)
        !          1346:       (insert-string mh-ins-str)
        !          1347:       (mh-insert-prefix-string mh-ins-buf-prefix)
        !          1348:       (widen))))
        !          1349: 
        !          1350: 
        !          1351: (defun mh-insert-prefix-string (ins-string)
        !          1352: "Preface each line in the current buffer with STRING."
        !          1353:   (goto-char (point-min))
        !          1354:   (replace-regexp "^." (concat ins-string "\\&") nil)
        !          1355:   (goto-char (point-min)))
        !          1356: 
        !          1357: 
        !          1358: (defun mh-fully-kill-draft ()
        !          1359:   "Kill the draft message file and the draft message buffer.  Use kill-buffer
        !          1360: if you don't want to delete the draft message file."
        !          1361:   (interactive "")
        !          1362:   (if (file-exists-p (buffer-file-name))
        !          1363:       (delete-file (buffer-file-name)))
        !          1364:   (kill-buffer (buffer-name)))
        !          1365: 
        !          1366: 
        !          1367: 
        !          1368: ;;; Commands to manipulate sequences.  Sequences are stored in an alist
        !          1369: ;;; of the form:
        !          1370: ;;;    ((seq-name msgs ...) (seq-name msgs ...) ...)
        !          1371: 
        !          1372: 
        !          1373: (defmacro mh-seq-name (pair)
        !          1374:   (list 'car pair))
        !          1375: 
        !          1376: (defmacro mh-seq-msgs (pair)
        !          1377:   (list 'cdr pair))
        !          1378: 
        !          1379: 
        !          1380: (defun mh-seq-to-msgs (seq)
        !          1381:   "Returns the messages in sequence SEQ."
        !          1382:   (mh-seq-msgs (assoc seq mh-seq-list)))
        !          1383: 
        !          1384: 
        !          1385: (defun mh-msg-to-seq (msg)
        !          1386:   "Given a MESSAGE number, return the first sequence in which it occurs."
        !          1387:   (let ((l mh-seq-list))
        !          1388:     (while (and l (not (memq msg (cdar l))))
        !          1389:       (setq l (cdr l)))
        !          1390:     (caar l)))
        !          1391: 
        !          1392: 
        !          1393: (defun mh-read-seq (prompt &optional seq)
        !          1394:   "Read and return a sequence name from the minibuffer, prompting with 
        !          1395: the string PROMPT and supplying the optional DEFAULT.
        !          1396: % defaults to the sequences that the current message is in.
        !          1397: Makes sure that the sequence is known to MH commands."
        !          1398:   (let ((input (completing-read
        !          1399:                (format "%s %s %s" prompt "sequence:"
        !          1400:                        (if seq (format "[%s] " (symbol-name seq)) ""))
        !          1401:                (mh-seq-names mh-seq-list))))
        !          1402:     (let ((seq (cond ((equal input "%") (mh-msg-to-seq (mh-get-msg-num t)))
        !          1403:                     ((equal input "") seq)
        !          1404:                     (t (intern input)))))
        !          1405:       (mh-process-seq seq (mh-seq-to-msgs seq))
        !          1406:       seq)))
        !          1407: 
        !          1408: 
        !          1409: (defun mh-seq-names (seq-list)
        !          1410:   "Returns an alist of the names of the SEQUENCES."
        !          1411:   (mapcar (function (lambda (entry) (cons (symbol-name (car entry)) nil)))
        !          1412:          seq-list))
        !          1413: 
        !          1414: 
        !          1415: (defun mh-seq-from-command (folder seq command)
        !          1416:   "In FOLDER, make a sequence named SEQ by executing COMMAND."
        !          1417:   (let ((msgs ())
        !          1418:        (case-fold-search t))
        !          1419:     (save-excursion
        !          1420:       (save-window-excursion
        !          1421:        (apply 'mh-exec-cmd-quiet (cons " *mh-temp*" command))
        !          1422:        (goto-char (point-min))
        !          1423:        (while (re-search-forward "\\([0-9]+\\)" nil t)
        !          1424:          (let ((num (string-to-int (buffer-substring (match-beginning 1)
        !          1425:                                                      (match-end 1)))))
        !          1426:            (if (not (zerop num))
        !          1427:                (push num msgs)))))
        !          1428:       (switch-to-buffer folder)
        !          1429:       (push (cons seq msgs) mh-seq-list)
        !          1430:       msgs)))
        !          1431: 
        !          1432: 
        !          1433: (defun mh-remove-seq (seq)
        !          1434:   "Delete the sequence SEQ."
        !          1435:   (let ((entry (assoc seq mh-seq-list)))
        !          1436:     (setq mh-seq-list (delq (car entry) mh-seq-list))
        !          1437:     (mh-notate-seq (mh-seq-msgs (car entry)) ?  (+ mh-cmd-note 1))))
        !          1438: 
        !          1439: 
        !          1440: (defun mh-remove-msg-from-seq (msg-num seq &optional do-not-mark)
        !          1441:   "Remove a message MSG-NUM from the sequence SEQ.  If optional FLAG is
        !          1442: non-nil, do not mark the message as being part of a sequence."
        !          1443:   (let ((seq (assoc seq mh-seq-list)))
        !          1444:     (if seq
        !          1445:        (setcdr seq (delq msg-num (mh-seq-msgs seq)))))
        !          1446:   (if (not do-not-mark) (mh-notate ? (+ mh-cmd-note 1))))
        !          1447: 
        !          1448: 
        !          1449: (defun mh-add-msg-to-seq (msg-num seq &optional do-not-mark)
        !          1450:   "Add the message MSG-NUM to the SEQUENCE.  If optional FLAG is non-nil,
        !          1451: do not mark the message as being part of a sequence."
        !          1452:   (let ((seq-list (assoc seq mh-seq-list)))
        !          1453:     (if (not do-not-mark) (mh-notate ?% (+ mh-cmd-note 1)))
        !          1454:     (if (null seq-list)
        !          1455:        (push (cons seq (list msg-num)) mh-seq-list)
        !          1456:        (setcdr seq-list (cons msg-num (cdr seq-list))))))
        !          1457: 
        !          1458: 
        !          1459: (defun mh-add-msg-list-to-seq (msgs seq &optional do-not-mark)
        !          1460:   "Add the messages in LIST to the SEQUENCE.  If optional FLAG is non-nil,
        !          1461: do not mark the messages as being part of a sequence."
        !          1462:   (mapc (function (lambda (msg) (mh-add-msg-to-seq msg seq do-not-mark)))
        !          1463:        msgs))
        !          1464: 
        !          1465: 
        !          1466: (defun mh-rename-seq (seq new-name)
        !          1467:   "Rename a SEQUENCE to have a new NAME."
        !          1468:   (interactive "SOld sequence name: \nSNew name: ")
        !          1469:   (let ((old-seq (assoc seq mh-seq-list)))
        !          1470:     (if old-seq
        !          1471:        (rplaca old-seq new-name)
        !          1472:        (error "Sequence %s does not exists" (symbol-name seq)))))
        !          1473: 
        !          1474: 
        !          1475: (defun mh-notate-seq (seq notation offset)
        !          1476:   "Mark all messages in the sequence SEQ with the NOTATION at character
        !          1477: OFFSET."
        !          1478:   (mh-map-to-seq-msgs 'mh-notate seq notation offset))
        !          1479: 
        !          1480: 
        !          1481: (defun mh-map-to-seq-msgs (func seq &rest args)
        !          1482:   "Invoke the function FUNC at each message in the sequence SEQ, passing
        !          1483: the remaining ARGS as arguments."
        !          1484:   (let ((msgs (mh-seq-to-msgs seq)))
        !          1485:     (while msgs
        !          1486:       (mh-goto-msg (car msgs))
        !          1487:       (apply func args)
        !          1488:       (setq msgs (cdr msgs)))))
        !          1489: 
        !          1490: 
        !          1491: (defun mh-map-over-seqs (func seq-list)
        !          1492:   "Apply the function FUNC to each element in the sequence LIST,
        !          1493: passing the sequence name and a list of messages as arguments."
        !          1494:   (while seq-list
        !          1495:     (funcall func (caar seq-list) (cdar seq-list))
        !          1496:     (setq seq-list (cdr seq-list))))
        !          1497: 
        !          1498: 
        !          1499: (defun mh-process-seq-commands (seq-list)
        !          1500:   "Process outstanding sequence commands for the sequences in SEQ-LIST."
        !          1501:   (mh-map-over-seqs 'mh-process-seq seq-list))
        !          1502: 
        !          1503: 
        !          1504: (defun mh-process-seq (seq msgs)
        !          1505:   "Mark sequence SEQ to contain MSGS."
        !          1506:   ;; Do not mark pseudo-sequences.
        !          1507:   (if (not (equal (substring (symbol-name seq) 0 1) "+"))
        !          1508:       (apply 'mh-exec-cmd
        !          1509:             (nconc (list "mark" "-zero" "-seq" (format "%s" seq) "-add")
        !          1510:                    msgs))))
        !          1511: 
        !          1512: 
        !          1513: (defun mh-copy-seq-to-point (seq location)
        !          1514:   "Copy the messages in SEQUENCE to after the LOCATION in the current buffer."
        !          1515:   (mh-map-to-seq-msgs 'mh-copy-line-to-point seq location))
        !          1516: 
        !          1517: 
        !          1518: (defun mh-copy-line-to-point (location)
        !          1519:   "Copy the current line to the LOCATION in the current buffer."
        !          1520:   (beginning-of-line)
        !          1521:   (let ((beginning-of-line (point)))
        !          1522:     (forward-line 1)
        !          1523:     (copy-region-as-kill beginning-of-line (point))
        !          1524:     (goto-char location)
        !          1525:     (yank)
        !          1526:     (goto-char beginning-of-line)))
        !          1527: 
        !          1528: 
        !          1529: 
        !          1530: ;;; Issue commands to mh.
        !          1531: 
        !          1532: (defun mh-exec-cmd (command &rest args)
        !          1533:   "Execute MH command COMMAND with ARGS.  Any output is shown to the user."
        !          1534:   (save-excursion
        !          1535:     (switch-to-buffer-other-window " *mh-temp*")
        !          1536:     (erase-buffer)
        !          1537:     (apply 'call-process
        !          1538:           (nconc (list (format "%s%s" mh-progs command) nil t nil)
        !          1539:                  (mh-list-to-string args)))
        !          1540:     (if (> (buffer-size) 0)
        !          1541:        (sit-for 5))))
        !          1542: 
        !          1543: 
        !          1544: (defun mh-exec-cmd-quiet (buffer command &rest args)
        !          1545:   "In BUFFER, execute MH command COMMAND with ARGS.  Return in buffer, if
        !          1546: one exists."
        !          1547:   (when (stringp buffer)
        !          1548:     (switch-to-buffer buffer)
        !          1549:     (erase-buffer))
        !          1550:   (apply 'call-process
        !          1551:         (nconc (list (format "%s%s" mh-progs command) nil buffer nil)
        !          1552:                (mh-list-to-string args))))
        !          1553: 
        !          1554: 
        !          1555: (defun mh-exec-cmd-output (command &rest args)
        !          1556:   "Execute MH command COMMAND with ARGS putting the output into buffer after
        !          1557: point.  Set mark after inserted text."
        !          1558:   (set-mark (point))
        !          1559:   (apply 'call-process
        !          1560:         (nconc (list (format "%s%s" mh-progs command) nil t nil)
        !          1561:                (mh-list-to-string args)))
        !          1562:   (exchange-point-and-mark))
        !          1563: 
        !          1564: 
        !          1565: 
        !          1566: (defun mh-exec-lib-cmd-output (command &rest args)
        !          1567:   "Execute MH library command COMMAND with ARGS.  Put the output into
        !          1568: buffer after point.  Set mark after inserted text."
        !          1569:   (set-mark (point))
        !          1570:   (apply 'call-process
        !          1571:         (nconc (list (format "%s%s" mh-lib command) nil t nil)
        !          1572:                (mh-list-to-string args)))
        !          1573:   (exchange-point-and-mark))
        !          1574: 
        !          1575: 
        !          1576: (defun mh-list-to-string (l)
        !          1577:   "Flattens the list L and makes every element a string."
        !          1578:   (let ((new-list nil))
        !          1579:     (while l
        !          1580:       (cond ((symbolp (car l)) (push (format "%s" (car l)) new-list))
        !          1581:            ((numberp (car l)) (push (format "%d" (car l)) new-list))
        !          1582:            ((equal (car l) ""))
        !          1583:            ((stringp (car l)) (push (car l) new-list))
        !          1584:            ((null (car l)))
        !          1585:            ((listp (car l)) (setq new-list
        !          1586:                                   (nconc (mh-list-to-string (car l))
        !          1587:                                          new-list)))
        !          1588:            (t (error "Bad argument %s" (car l))))
        !          1589:       (setq l (cdr l)))
        !          1590:     (nreverse new-list)))
        !          1591: 
        !          1592: 
        !          1593: 
        !          1594: ;;; Commands to annotate a message.
        !          1595: 
        !          1596: (defun mh-annotate-msg (msg buffer note &rest args)
        !          1597:   "Mark the MESSAGE in BUFFER listing with the character NOTE and annotate
        !          1598: the saved message with ARGS."
        !          1599:   ;; Wait for annotation to finish, to avoid race condition with reading msg.
        !          1600:   (apply 'mh-exec-cmd (cons "anno" (cons buffer (cons msg args))))
        !          1601:   (save-excursion
        !          1602:     (switch-to-buffer buffer)
        !          1603:     (if (mh-goto-msg msg t)
        !          1604:        (mh-notate note (+ mh-cmd-note 1)))))
        !          1605: 
        !          1606: 
        !          1607: (defun mh-notate (notation offset)
        !          1608:   "Marks the current message with the character NOTATION at position OFFSET."
        !          1609:   (let ((buffer-read-only nil))
        !          1610:     (beginning-of-line)
        !          1611:     (goto-char (+ (point) offset))
        !          1612:     (delete-char 1)
        !          1613:     (insert notation)
        !          1614:     (beginning-of-line)))
        !          1615: 
        !          1616: 
        !          1617: 
        !          1618: ;;; User prompting commands.
        !          1619: 
        !          1620: (defun mh-prompt-for-folder (prompt default can-create)
        !          1621:   "Prompt for a folder name with PROMPT.  Returns the folder's name.
        !          1622: DEFAULT is used if the folder exists and the user types CR.
        !          1623: If the CAN-CREATE flag is t,then a non-existant folder is made."
        !          1624:   (let* ((prompt (format "%s folder%s" prompt
        !          1625:                         (if (equal "" default)
        !          1626:                             "? "
        !          1627:                             (format " [%s]? " default))))
        !          1628:         name)
        !          1629:     (while (and (setq name (completing-read prompt mh-folder-list
        !          1630:                                            nil (not can-create) "+"))
        !          1631:                (equal name "")
        !          1632:                (equal default "")))
        !          1633:     (cond ((or (equal name "") (equal name "+"))
        !          1634:           (setq name default))
        !          1635:          ((not (equal (substring name 0 1) "+"))
        !          1636:           (setq name (format "+%s" name))))
        !          1637:     (let ((new-file-p
        !          1638:           (not
        !          1639:            (file-exists-p (format "%s%s" mh-user-path (substring name 1))))))
        !          1640:       (cond ((and new-file-p
        !          1641:                  (y-or-n-p
        !          1642:                   (format "Folder %s does not exist. Create it? " name)))
        !          1643:             (message "Creating %s" name)
        !          1644:             (call-process "mkdir" nil nil nil
        !          1645:                           (format "%s%s" mh-user-path (substring name 1)))
        !          1646:             (message "Creating %s...done" name)
        !          1647:             (push (list name) mh-folder-list)
        !          1648:             (push (list (substring name 1 nil)) mh-folder-list))
        !          1649:            (new-file-p
        !          1650:             (error ""))
        !          1651:            (t
        !          1652:             (when (null (assoc name mh-folder-list))
        !          1653:               (push (list name) mh-folder-list)
        !          1654:               (push (list (substring name 1 nil)) mh-folder-list)))))
        !          1655:     name))
        !          1656: 
        !          1657: 
        !          1658: (defun mh-make-folder-list ()
        !          1659:   "Returns a list of the user's folders in a form suitable for completing
        !          1660: read."
        !          1661:   (interactive)
        !          1662:   (save-window-excursion
        !          1663:     (mh-exec-cmd-quiet " *mh-temp*" "folders" "-fast" "-norecurse")
        !          1664:     (goto-char (point-min))
        !          1665:     (let ((list nil))
        !          1666:       (while (not (eobp))
        !          1667:        (let ((start (point)))
        !          1668:          (search-forward "\n" nil t)
        !          1669:          (let ((folder (buffer-substring start (- (point) 1))))
        !          1670:            (push (list (format "+%s" folder)) list))))
        !          1671:       list)))
        !          1672: 
        !          1673: 
        !          1674: (defun mh-remove-folder-from-folder-list (folder)
        !          1675:   "Remove FOLDER from the list of folders."
        !          1676:   (setq mh-folder-list
        !          1677:        (delq (assoc (substring folder 1 nil) mh-folder-list)
        !          1678:              mh-folder-list)))
        !          1679: 
        !          1680: 
        !          1681: 
        !          1682: ;;; Misc. functions.
        !          1683: 
        !          1684: (defun mh-get-msg-num (error-if-no-message)
        !          1685:   "Returns the message number of the current message.  If the argument
        !          1686: ERROR-IF-NO-MESSAGE is non-nil, then complain if the cursor is not 
        !          1687: pointing to a message."
        !          1688:   (save-excursion
        !          1689:     (beginning-of-line)
        !          1690:     (cond ((looking-at "^[ ]*\\([0-9]+\\)")
        !          1691:           (string-to-int (buffer-substring (match-beginning 1)
        !          1692:                                            (match-end 1))))
        !          1693:          (error-if-no-message
        !          1694:           (error "Cursor not pointing to message"))
        !          1695:          (t nil))))
        !          1696: 
        !          1697: 
        !          1698: (defun mh-msg-search-pat (n)
        !          1699:   "Returns a search pattern for message N in the scan listing."
        !          1700:   (cond ((< n 10) (format "^[^0-9][^0-9][^0-9]%d" n))
        !          1701:        ((< n 100) (format "^[^0-9][^0-9]%d" n))
        !          1702:        ((< n 1000) (format "^[^0-9]%d" n))
        !          1703:        (t (format "^%d" n))))
        !          1704: 
        !          1705: 
        !          1706: (defun mh-msg-filename ()
        !          1707:   "Returns a string containing the pathname for the file containing the
        !          1708: current message."
        !          1709:   (format "%s%d" mh-folder-filename (mh-get-msg-num t)))
        !          1710: 
        !          1711: 
        !          1712: (defun mh-msg-filenames (msgs folder)
        !          1713:   "Returns a string of filenames for MSGS in FOLDER."
        !          1714:   (mapconcat (function (lambda (msg) (concat folder msg))) msgs " "))
        !          1715: 
        !          1716: 
        !          1717: (defun mh-find-path ()
        !          1718:    "Set mh-user-path to the user's Mail directory from  ~/.mh_profile."
        !          1719:    (if (equal (setq mh-user-path (mh-get-profile-field "Path:")) "")
        !          1720:        (setq mh-user-path "Mail/")
        !          1721:        (setq mh-user-path (format "%s/" mh-user-path)))
        !          1722:    (if (not (equal (substring mh-user-path 0 1) "/"))
        !          1723:        (setq mh-user-path (format "%s/%s" (getenv "HOME") mh-user-path))))
        !          1724: 
        !          1725: 
        !          1726: (defun mh-get-profile-field (field)
        !          1727:   "Return FIELD from the user's .mh_profile file."
        !          1728:   (save-window-excursion
        !          1729:     (if (not (file-exists-p "~/.mh_profile"))
        !          1730:        (error "Cannot find .mh_profile file."))
        !          1731:     (switch-to-buffer " *mh_temp*")
        !          1732:     (erase-buffer)
        !          1733:     (insert-file-contents "~/.mh_profile")
        !          1734:     (mh-get-field field)))
        !          1735: 
        !          1736: 
        !          1737: (defun mh-get-cur-msg (folder)
        !          1738:   "Returns the number of the 'cur' message in FOLDER."
        !          1739:   (save-excursion
        !          1740:     (switch-to-buffer " *mh_temp*")
        !          1741:     (erase-buffer)
        !          1742:     (mh-exec-cmd-output "pick" folder "cur")
        !          1743:     (string-to-int (buffer-substring (point-min) (point-max)))))
        !          1744: 
        !          1745: 
        !          1746: (defun mh-get-field (field)
        !          1747:   "Find and return the value of field FIELD in the current buffer.
        !          1748: Returns the empty string if the field is not in the message."
        !          1749:   (let ((case-fold-search t))
        !          1750:     (goto-char (point-min))
        !          1751:     (cond ((not (search-forward field nil t)) "")
        !          1752:          ((looking-at "[\t ]*$") "")
        !          1753:          (t
        !          1754:           (re-search-forward "[\t ]*\\([a-zA-z0-9/\.].*\\)$" nil t)
        !          1755:           (let ((field (buffer-substring (match-beginning 1)
        !          1756:                                          (match-end 1)))
        !          1757:                 (end-of-match (point)))
        !          1758:             (forward-line)
        !          1759:             (while (looking-at "[ \t]") (forward-line 1))
        !          1760:             (backward-char 1)
        !          1761:             (format "%s%s" field (buffer-substring end-of-match (point))))))))
        !          1762: 
        !          1763: 
        !          1764: (defun mh-insert-fields (&rest name-values)
        !          1765:   "Insert the NAME-VALUE pairs in the current buffer."
        !          1766:   (let ((case-fold-search t))
        !          1767:     (while name-values
        !          1768:       (let ((field-name (car name-values))
        !          1769:            (value (cadr name-values)))
        !          1770:        (goto-char (point-min))
        !          1771:        (cond ((not (re-search-forward (format "^%s" field-name) nil t))
        !          1772:               (re-search-forward "^---\\|^$")
        !          1773:               (beginning-of-line)
        !          1774:               (insert field-name " " value "\n"))
        !          1775:              (t
        !          1776:               (end-of-line)
        !          1777:               (insert " " value)))
        !          1778:        (setq name-values (cddr name-values))))))
        !          1779: 
        !          1780: 
        !          1781: (defun mh-position-on-field (field set-mark)
        !          1782:   "Set point to the end of the line beginning with FIELD.  Sets the mark
        !          1783: to the point, if SET-MARK is non-nil."
        !          1784:   (if set-mark (set-mark (point)))
        !          1785:   (goto-char (point-min))
        !          1786:   (if (re-search-forward (format "^%s" field) nil t)
        !          1787:       (progn (end-of-line) t)
        !          1788:       nil))
        !          1789: 
        !          1790: 
        !          1791: 
        !          1792: ;;; Build the folder-mode keymap:
        !          1793: 
        !          1794: (define-key mh-folder-mode-map "?" 'mh-msg-is-in-seq)
        !          1795: (define-key mh-folder-mode-map "%" 'mh-put-msg-in-seq)
        !          1796: (define-key mh-folder-mode-map "\e%" 'mh-delete-msg-from-seq)
        !          1797: (define-key mh-folder-mode-map "\^xn" 'mh-narrow-to-seq)
        !          1798: (define-key mh-folder-mode-map "\^xw" 'mh-widen)
        !          1799: 
        !          1800: (define-key mh-folder-mode-map "\^c" 'my-apply-command-to-seq)
        !          1801: (define-key mh-folder-mode-map "\eu" 'mh-undo-folder)
        !          1802: (define-key mh-folder-mode-map "\e " 'mh-page-digest)
        !          1803: (define-key mh-folder-mode-map "\ee" 'mh-extract-rejected-mail)
        !          1804: (define-key mh-folder-mode-map "\ef" 'mh-visit-folder)
        !          1805: (define-key mh-folder-mode-map "\ek" 'mh-kill-folder)
        !          1806: (define-key mh-folder-mode-map "\el" 'mh-list-folders)
        !          1807: (define-key mh-folder-mode-map "\ep" 'mh-renumber-folder)
        !          1808: (define-key mh-folder-mode-map "\es" 'mh-search-folder)
        !          1809: (define-key mh-folder-mode-map "\er" 'mh-rescan-folder)
        !          1810: (define-key mh-folder-mode-map "l" 'mh-print-msg)
        !          1811: (define-key mh-folder-mode-map "t" 'mh-toggle-summarize)
        !          1812: (define-key mh-folder-mode-map "c" 'mh-copy-msg)
        !          1813: (define-key mh-folder-mode-map ">" 'mh-write-msg-to-file)
        !          1814: (define-key mh-folder-mode-map "i" 'mh-inc-folder)
        !          1815: (define-key mh-folder-mode-map "x" 'mh-execute-commands)
        !          1816: (define-key mh-folder-mode-map "e" 'mh-execute-commands)
        !          1817: (define-key mh-folder-mode-map "r" 'mh-redistribute)
        !          1818: (define-key mh-folder-mode-map "f" 'mh-forward)
        !          1819: (define-key mh-folder-mode-map "s" 'mh-send)
        !          1820: (define-key mh-folder-mode-map "a" 'mh-answer)
        !          1821: (define-key mh-folder-mode-map "g" 'mh-goto-msg)
        !          1822: (define-key mh-folder-mode-map "\177" 'mh-previous-page)
        !          1823: (define-key mh-folder-mode-map " " 'mh-page-msg)
        !          1824: (define-key mh-folder-mode-map "." 'mh-show)
        !          1825: (define-key mh-folder-mode-map "u" 'mh-undo)
        !          1826: (define-key mh-folder-mode-map "!" 'mh-move-or-write-again)
        !          1827: (define-key mh-folder-mode-map "^" 'mh-move-msg)
        !          1828: (define-key mh-folder-mode-map "d" 'mh-delete-msg)
        !          1829: (define-key mh-folder-mode-map "p" 'mh-previous-line)
        !          1830: (define-key mh-folder-mode-map "n" 'mh-next-line)
        !          1831: 
        !          1832: 
        !          1833: ;;; Build the letter-mode keymap:
        !          1834: 
        !          1835: (define-key mh-letter-mode-map "\^Cb" 'mh-to-bcc)
        !          1836: (define-key mh-letter-mode-map "\^Cw" 'mh-check-whom)
        !          1837: (define-key mh-letter-mode-map "\^Cc" 'mh-to-cc)
        !          1838: (define-key mh-letter-mode-map "\^Cf" 'mh-to-fcc)
        !          1839: (define-key mh-letter-mode-map "\^Cs" 'mh-to-subject)
        !          1840: (define-key mh-letter-mode-map "\^Ct" 'mh-to-to)
        !          1841: (define-key mh-letter-mode-map "\^Cq" 'mh-fully-kill-draft)
        !          1842: (define-key mh-letter-mode-map "\^Cy" 'mh-insert-cur-msg)
        !          1843: (define-key mh-letter-mode-map "\^C\^Y" 'mh-insert-letter)
        !          1844: (define-key mh-letter-mode-map "\^C\^C" 'mh-send-letter)
        !          1845: 
        !          1846: ;;; Build the pick-mode keymap:
        !          1847: 
        !          1848: (define-key mh-pick-mode-map "\^C\^C" 'mh-do-pick-search)
        !          1849: (define-key mh-pick-mode-map "\^Cb" 'mh-to-bcc)
        !          1850: (define-key mh-pick-mode-map "\^Cc" 'mh-to-cc)
        !          1851: (define-key mh-pick-mode-map "\^Cf" 'mh-to-fcc)
        !          1852: (define-key mh-pick-mode-map "\^Cs" 'mh-to-subject)
        !          1853: (define-key mh-pick-mode-map "\^Ct" 'mh-to-to)
        !          1854: (define-key mh-pick-mode-map "\^Cw" 'mh-check-whom)

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.