Commits

Anonymous committed 30d89b1

Patcher 3.8

  • Participants
  • Parent commits 7c738f9

Comments (0)

Files changed (4)

+2005-07-26  Didier Verna  <didier@xemacs.org>
+
+	* Patcher 3.8 is released.
+
+2005-07-26  Didier Verna  <didier@xemacs.org>
+
+	* patcher.el (patcher-warning): New.
+	* patcher.el (patcher-goto-signature): Use it.
+	* patcher.el (patcher-after-send): Ditto.
+	* patcher.el (patcher-install-send-hooks): New.
+	* patcher.el (patcher-mail-compose-mail): Use it.
+	* patcher.el (patcher-mail-adapt-1): Ditto.
+	* patcher.el (patcher-mail-sendmail): Don't use the ACTIONS
+	argument of the `mail' function, to stay coherent with the others
+	methods.
+
+2005-07-26  Didier Verna  <didier@xemacs.org>
+
+	* patcher.el (patcher-mail-or-reply-setup): Rename to
+	`patcher-mail-setup'.
+	* patcher.el (patcher-mail-1): Use it.
+	* patcher.el (patcher-reply-1): Rename to `patcher-mail-adapt-1'.
+	Use `patcher-mail-setup'.
+	* patcher.el (patcher-reply-subproject): Rename to
+	`patcher-mail-adapt-subproject'.
+	Use `patcher-mail-adapt-1'.
+	* patcher.el (patcher-reply): Rename to `patcher-mail-adapt'.
+	Use `patcher-mail-adapt-1'.
+	* patcher.el (patcher-gnus-summary-followup): New.
+	* patcher.el (patcher-gnus-summary-followup-with-original): New.
+	* patcher.el (patcher-gnus-summary-reply): New.
+	* patcher.el (patcher-gnus-summary-reply-with-original): New.
+	* patcher.el (patcher-gnus-summary-minor-mode-string): New.
+	* patcher.el (patcher-gnus-summary-minor-mode-hook): New.
+	* patcher.el (patcher-gnus-summary-minor-mode-map): New.
+	* patcher.el (patcher-gnus-summary-minor-mode): New.
+	* patcher.el (patcher-gnus-article-minor-mode-string): New.
+	* patcher.el (patcher-gnus-article-minor-mode-hook): New.
+	* patcher.el (patcher-gnus-article-minor-mode-map): New.
+	* patcher.el (patcher-gnus-article-minor-mode): New.
+	* patcher.el (patcher-insinuate-gnus): New.
+
+2005-07-25  Didier Verna  <didier@xemacs.org>
+
+	* patcher.el (patcher-goto-subject): New.
+	* patcher.el (patcher-goto-signature): New.
+	* patcher.el (patcher-logmsg-insert-subject): Use
+	`patcher-goto-subject'.
+	* patcher.el (patcher-logmsg-commit): Ditto.
+	* patcher.el (patcher-mail-or-reply-setup): New.
+	* patcher.el (patcher-mail-1): Use it. Remove &optional modifier.
+	* patcher.el (patcher-reply-1): New.
+	* patcher.el (patcher-reply-subproject): New.
+	* patcher.el (patcher-reply): New.
+
 2004-12-07  Norbert Koch  <viteno@xemacs.org>
 
 	* Makefile (VERSION): XEmacs package 1.70 released.
 
 	* Makefile (VERSION): XEmacs package 1.69 released.
 
-2004-11-27  Didier Verna  <didier@lrde.epita.fr>
+2004-11-27  Didier Verna  <didier@xemacs.org>
 
 	* Patcher 3.7 is released.
 
 
 ;; Patcher is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
 ;; Contents management by FCM version 0.1.
 
 ;; Patcher is an XEmacs package designed to automate and ease the
-;; maintenance of archive-based projects. It provides assistance in
+;; maintenance of archive-based projects.  It provides assistance in
 ;; building, reporting and committing patches, as well as in handling the
 ;; corresponding ChangeLog entries, for example by creating skeletons.
 
-;; Patcher is fully documented. Please refer to the documentation for
-;; information on how to use it. All user options can be found in the
+;; Patcher is fully documented.  Please refer to the documentation for
+;; information on how to use it.  All user options can be found in the
 ;; "Patcher" Custom group.
 
 
 ;; #### Provide a way to attach patches instead of inserting them as plain
 ;; text.
 
-;; #### Provide a way to filter out some files from the mailed patch. For
+;; #### Provide a way to filter out some files from the mailed patch.  For
 ;; instance, when you commit yourself, you want to have `configure' in your
 ;; files, but you don't want to display a patch against it.
 
 ;; #### Before sending the message, we could check that the contents is ok
 ;; (like, there's no more diff errors and stuff).
 
-;; #### Implement a real error mechanism.
+;; #### Implement a real error / warning mechanism.
 
 ;; #### When a project is found to be out of date, we could implement
 ;; something to update it and re-run patcher again.
 ;;
 ;; #### Have a control window to clarify the progress of everything.
 ;; Make it perhaps a small buffer, above the mail message/ChangeLog
-;; buffer. It shows what steps have been completed, what haven't, and
-;; what to do. It should have buttons in it for the various actions.
+;; buffer.  It shows what steps have been completed, what haven't, and
+;; what to do.  It should have buttons in it for the various actions.
 ;; One button is for include-changelogs, one for commit, one for send
-;; the mail, and one for execute the commit. These should be enabled
-;; or grayed out appropriately. It should also have buttons that show
+;; the mail, and one for execute the commit.  These should be enabled
+;; or grayed out appropriately.  It should also have buttons that show
 ;; the associated changelogs; clicking on a button puts that changelog
-;; buffer in the main window below the control window. By each
+;; buffer in the main window below the control window.  By each
 ;; changelog button should be an indication of whether the changelog
-;; has been modified so far. The control window should stay around as
+;; has been modified so far.  The control window should stay around as
 ;; much as it can during the whole process (e.g. use
 ;; set-buffer-dedicated-p or something), so that it's always there to
-;; drive the whole process. One corollary is that you don't actually
+;; drive the whole process.  One corollary is that you don't actually
 ;; have to switch to the mail buffer to (e.g.) execute
 ;; include-changelogs -- you just click on the control window, and it
-;; does it automatically. also, when you execute include-changelogs,
+;; does it automatically.  also, when you execute include-changelogs,
 ;; it can issue a warning if not all changelogs have been visited, and
-;; prompt you to make sure you want to continue. Similarly, you can
+;; prompt you to make sure you want to continue.  Similarly, you can
 ;; run include-changelogs more than once even if it succeeded the
 ;; first time (e.g. for some reason you didn't like the result and
-;; deleted it), but it will prompt "are you sure?". There could also
+;; deleted it), but it will prompt "are you sure?".  There could also
 ;; be an "undo include-changelogs", if you make a mistake after doing
 ;; include-changelogs and realize you want to go back and fix the
 ;; problem and do include-changelogs again.
 
 ;; Internal notes:
 
-;; - See why the ChangeLogs are represented in absolute path.
+;; - See why the ChangeLogs are represented in absolute path instead of
+;; relative to the project's directory. I can't remember, but this looks
+;; weird.
 
 
 
 
 ;; Require 'sendmail for getting `mail-header-separator'.
 ;; #### Now that a fake mail sending function exists, sendmail shouldn't be
-;; systematically required like this. However, since most users will really
-;; want do send real messages, it probably doesn't hurt to keep things like
-;; this.
+;; #### systematically required like this.  However, since most users will
+;; #### really want do send real messages, it probably doesn't hurt to keep
+;; #### things as-is.
 (require 'sendmail)
 
 
     (setq symbol (eval symbol))
     (if (not (consp symbol))
 	(setq symbol (list symbol)))
-    ;; Another hack. This works because the autoload environment is
+    ;; Another hack.  This works because the autoload environment is
     ;; currently used ONLY to suppress warnings, and the actual
-    ;; autoload definition is not used. (NOTE: With this definition,
+    ;; autoload definition is not used.  (NOTE: With this definition,
     ;; we will get spurious "multiple autoloads for %s" warnings if we
     ;; have an autoload later in the file for any functions in SYMBOL.
     ;; This is not something that code should ever do, though.)
 ;; ===========================================================================
 
 ;; $Format: "(defconst patcher-prcs-major-version \"$ProjectMajorVersion$\")"$
-(defconst patcher-prcs-major-version "version-3-7")
+(defconst patcher-prcs-major-version "version-3-8")
 ;; $Format: "(defconst patcher-prcs-minor-version \"$ProjectMinorVersion$\")"$
 (defconst patcher-prcs-minor-version "1")
 (defconst patcher-version
 ;; General utilities
 ;; ===========================================================================
 
+(defsubst patcher-message (msg &rest args)
+  ;; Print a message, letting XEmacs time to display it.  Also, handle command
+  ;; substitution.
+  (message (substitute-command-keys (apply 'format msg args)))
+  (sit-for 0))
+
+(defsubst patcher-warning (msg &rest args)
+  ;; Like `patcher-message, but triggers a Patcher warning instead.
+  (warn (substitute-command-keys (apply 'format msg args))))
+
 (defsubst patcher-error (msg &rest args)
   ;; Like `patcher-message, but triggers a Patcher error instead.
   (error (substitute-command-keys (apply 'format msg args))))
 
-(defsubst patcher-message (msg &rest args)
-  ;; Print a message, letting XEmacs time to display it. Also, handle command
-  ;; substitution.
-  (message (substitute-command-keys (apply 'format msg args)))
-  (sit-for 0))
-
 (defmacro patcher-with-progression (msg &rest body)
   ;; wrap BODY in "msg..." / "msg...done" messages.
   ;; Return the value of BODY execution.
 
 (defsubst patcher-file-relative-name (file &optional dir raw)
   ;; Construct a filename from FILE relative to DIR (default directory if not
-  ;; given). Unless RAW is given, force unix syntax
+  ;; given).  Unless RAW is given, force unix syntax
   ;; #### NOTE: FILE may be either a string (a file name), or a list such as
   ;; #### patcher-change-logs elements, whose car must then be the file name
   ;; #### in question.
     ))
 
 (defsubst patcher-files-string (files)
-  ;; Convert FILES to a string of relative file names. Unless RAW is given,
+  ;; Convert FILES to a string of relative file names.  Unless RAW is given,
   ;; force unix syntax.
   ;; #### NOTE: FILES may be either a list of strings (file names), or a list
   ;; #### such as the one in patcher-change-logs.
 
 (defun patcher-files-buffers (files &optional find)
   ;; Find a buffer visiting each file in FILES, and return a list of
-  ;; corresponding buffers. Skip files that are not visited, unless optional
-  ;; argument FIND is non nil. In that case, visit the file.
+  ;; corresponding buffers.  Skip files that are not visited, unless optional
+  ;; argument FIND is non nil.  In that case, visit the file.
   ;; #### NOTE: FILES may be either a list of strings (file names), or a list
   ;; #### such as the one in patcher-change-logs.
   (let (buffer buffers)
    buffers
    '("buffer" "buffers" "save")))
 
+(defun patcher-goto-subject ()
+  ;; Move point to the beginning of the Subject: header's contents, if any.
+  ;; Return that position, or nil.
+  ;; #### FIXME: maybe we should issue a warning if no subject line is found ?
+  (let (pos)
+    (save-excursion
+      (goto-char (point-min))
+      (setq pos (re-search-forward "^Subject: " nil t)))
+    (and pos (goto-char pos))))
+
+(defun patcher-goto-signature ()
+  ;; Move point to the beginning of the mail signature (actually, in front of
+  ;; the signature separator), if any.  Otherwise, move point to the end of
+  ;; the message. Return that position.
+  (goto-char (point-min))
+  (if (re-search-forward
+       (cond ((eq major-mode 'mail-mode)
+	      ;; this is hard-wired in sendmail.el
+	      "\n\n-- \n")
+	     ((eq major-mode 'message-mode)
+	      message-signature-separator)
+	     (t
+	      (patcher-warning "\
+Major mode: %s.
+Your mailing method is not fully supported by Patcher.
+This is not critical though: Patcher may not find the message signature
+correctly.
+
+Please report to <didier@xemacs.org>."
+			       major-mode)
+	      ;; Use the standard one by default.
+	      "\n\n-- \n"))
+       nil t)
+      (goto-char (match-beginning 0))
+    ;; else: no signature
+    (goto-char (point-max))))
+
 
 
 ;; ===========================================================================
 (defcustom patcher-default-subject-committed-prefix "[COMMIT]"
   "*Default prefix for the subject of Patcher mails.
 
-Same as `patcher-default-subject-prefix', but for committed patches. If nil,
+Same as `patcher-default-subject-prefix', but for committed patches.  If nil,
 keep the normal subject prefix."
   :group 'patcher-default
   :type '(choice (const :tag "Don't change" nil)
 `patcher-themes' user option."
   :group 'patcher-default
   ;; #### NOTE: ideally, this type should be computed automatically, depending
-  ;; on the defined themes. This arises the interesting question of custom
-  ;; dynamic types. Without them, it's a complex thing to do.
+  ;; #### on the defined themes.  This arises the interesting question of
+  ;; #### custom dynamic types.  Without them, it's a complex thing to do.
   :type '(repeat (symbol :tag "Theme name")))
 
 
 	  :format "%{%t%}: %v"
 	  (const :tag "" :value :themes)
 	  ;; #### NOTE: ideally, this type should be computed automatically,
-	  ;; depending on the defined themes. This arises the interesting
-	  ;; question of custom dynamic types. Without them, it's a complex
-	  ;; thing to do.
+	  ;; #### depending on the defined themes.  This arises the
+	  ;; #### interesting question of custom dynamic types.  Without them,
+	  ;; #### it's a complex thing to do.
 	  (repeat (symbol :tag "Theme name"))))
   ;; This is currently useless, and would cause problems in the custom type:
   ;; it will match the inheritance field in patcher-projects before the
   :type `(repeat
 	  (group (symbol :tag "Theme name")
 		 ;; #### NOTE: we could be tempted to add an `inheritance'
-		 ;; mechanism for themes, just like for projects. However,
-		 ;; don't forget that a theme can contain other themes because
-		 ;; themes belong to `patcher-project-options-custom-type'.
+		 ;; #### mechanism for themes, just like for projects.
+		 ;; #### However, don't forget that a theme can contain other
+		 ;; #### themes because themes belong to
+		 ;; #### `patcher-project-options-custom-type'.
 		 (repeat :inline t :tag "Options"
 			 (choice :inline t :value (:mail-method compose-mail)
 				 ,@patcher-project-options-custom-type))
 		 (repeat :inline t :tag "Options"
 			 (choice :inline t :value (:subdirectory "")
 				 ;; #### Look inside the widget library to see
-				 ;; how we can modify the completion behavior
+				 ;; #### how we can modify the completion
+				 ;; #### behavior
 				 (list :inline t :tag "Subdirectory"
 				       :format "%{%t%}: %v"
 				       (const :tag "" :value :subdirectory)
 ;; Project descriptors Accessors =============================================
 
 ;; #### NOTE: the accessors routines don't handle the case where the same
-;; option is given several times. Only the first one is used. This currently
-;; would have any sensible meaning anyway.
+;; #### option is given several times.  Only the first one is used.  This
+;; #### currently would have any sensible meaning anyway.
 
 (defsubst patcher-project-patcher-name (project)
   (nth 0 project))
   :type 'integer)
 
 (defun patcher-themes-option (themes option level)
-  ;; Look for an option in a list of themes. Note that themes can have the
-  ;; :themes option set. The themes tree (it shouldn't be a graph) is
+  ;; Look for an option in a list of themes.  Note that themes can have the
+  ;; :themes option set.  The themes tree (it shouldn't be a graph) is
   ;; traversed in depth first.
   (let (theme value)
     (while (and (not value) (setq theme (pop themes)))
 	(unless value
 	  (let ((subthemes (member :themes theme-options)))
 	    (when (> level patcher-max-theme-depth)
-	      (patcher-error
-	       "Theme `%s': maximum nesting level of themes exceeded.
+	      (patcher-error "\
+Theme `%s': maximum nesting level of themes exceeded.
 Either you have an infinite loop in your theme's :themes option, or you should
 increase the value of `patcher-max-theme-depth'"
 	       (car theme)))
   ;; project from the project's inheritance list.
   ;; The whole option form is returned: '(:stuff value)
   (when (> level patcher-max-inheritance-depth)
-    (patcher-error "Project `%s': maximum nesting level of projects exceeded.
+    (patcher-error "\
+Project `%s': maximum nesting level of projects exceeded.
 Either you have an infinite loop in your project's inheritance, or you should
 increase the value of `patcher-max-inheritance-depth'"
 		   (patcher-project-patcher-name project)))
 	(when themes
 	  (setq value (patcher-themes-option (cadr themes) option 0)))
 	))
-    ;; Try to find the option in inherited projects. Note that inherited
-    ;; projects can have their :inherit option set in turn. The inheritance
+    ;; Try to find the option in inherited projects.  Note that inherited
+    ;; projects can have their :inherit option set in turn.  The inheritance
     ;; tree (it shouldn't be a graph) is traverse in depth first.
     (unless value
       (let ((projs (if is-subproject
 	(when projs
 	  (while (and (not value) (setq proj (pop projs)))
 	    ;; #### FIXME: what happens if we inherit from something like a
-	    ;; subproject which is unrelated to the current project ?
+	    ;; #### subproject which is unrelated to the current project ?
 	    (setq value (patcher-project-option-1 (assoc proj patcher-projects)
 						  option (1+ level)))))
 	))
 	  ;; Return the files as a string, not as the original list.
 	  (setq value (list :files (mapconcat #'identity (cadr value) " ")))
 	;; #### NOTE: we don't normally check other user-level errors (like,
-	;; only projects can have an :inheritance option above). However, that
-	;; case is special: we have some blind calls to
-	;; `patcher-project-option' that could get an illegal :files options
-	;; from illegal projects. These calls are supposed to return `nil' as a
-	;; result, so we perform the checking.
+	;; #### only projects can have an :inheritance option above).
+	;; #### However, that case is special: we have some blind calls to
+	;; #### `patcher-project-option' that could get an illegal :files
+	;; #### options  from illegal projects.  These calls are supposed to
+	;; #### return `nil' as a  result, so we perform the checking.
 	(patcher-error "Project `%s': only subprojects can have a :file option"
 		       (patcher-project-patcher-name project))
 	(setq value nil)))
 ;; #### NOTE: this is currently useless.
 (defvar patcher-instances nil
   ;; A list of all alive instances of Patcher (an instance is dead after the
-  ;; mail has been sent. Each element is of the form '(BUFFER_NAME . BUFFER).
+  ;; mail has been sent.  Each element is of the form '(BUFFER_NAME . BUFFER).
   )
 
 (defconst patcher-change-log-entry-start-regexp
 
 (make-variable-buffer-local
  (defvar patcher-project nil
-   ;; Patcher project related to the current patch. This is also set in
+   ;; Patcher project related to the current patch.  This is also set in
    ;; auxiliary buffers.
    ))
 
 ;; Utility functions =========================================================
 
 ;;(defun patcher-keyword-value (keyword values)
-;;  ;; Return the value of KEYWORD from a (KEY VAL ...) list. VAL may be omitted
+;;  ;; Return the value of KEYWORD from a (KEY VAL ...) list.  VAL may be omitted
 ;;  ;; in the list, in which case t is returned.
 ;;  (let ((vals values)
 ;;	key val)
 
 (defun patcher-process-output-buffer (&optional mail-buffer)
   ;; Get a process output buffer for the current Patcher MAIL-BUFFER (current
-  ;; buffer by default), and prepare it. We can reuse an already existing one
+  ;; buffer by default), and prepare it.  We can reuse an already existing one
   ;; because auxiliary buffers are currently used only in one Lisp shot, so
   ;; there's no risk of Patcher instances overlapping.
   (let ((project patcher-project)
 
 (make-variable-buffer-local
  (defvar patcher-logmsg-commit-command
-   ;; Commit command used for the current Patcher LogMsg buffer. This variable
+   ;; Commit command used for the current Patcher LogMsg buffer.  This variable
    ;; is needed because the user has the ability to override the command with
    ;; a prefix argument.
    ))
 
 (defun patcher-logmsg-compress-change-logs ()
   ;; Compress ChangeLog entries appearing in the current buffer between FROM
-  ;; and TO. This function compresses the output into something that conveys
+  ;; and TO.  This function compresses the output into something that conveys
   ;; the essence of what has been changed, but much more compactly.
   (save-excursion
     (goto-char (point-min))
 		  (setq subject
 			(buffer-substring (point) (point-at-eol)))))
 	    (goto-char (point-min))
-	    (when (re-search-forward "^Subject: " nil t)
+	    (when (patcher-goto-subject)
 	      (skip-chars-forward " \t\f\r")
 	      (unless (eq (point) (point-at-eol))
 		(setq subject
 
 (defun patcher-logmsg-insert-change-logs (&optional separator)
   "Insert ChangeLog entries in the current Patcher LogMsg buffer at point.
-When used interactively, use a prefix argument to also insert the
+When called interactively, use a prefix argument to also insert the
 ChangeLogs separator string defined by the :change-logs-separator project
 option."
   (interactive "P")
     ))
 
 
-;; #### This should be defined in the Mail Buffer section, but defining it
-;; here avoids a compiler warning.
+;; #### NOTE: This should be defined in the Mail Buffer section, but defining
+;; #### it here avoids a compiler warning.
 (make-variable-buffer-local
  (defvar patcher-change-committed nil
    ;; Boolean indicating whether the change has been committed already.
 		      nil 'silent)
 	(patcher-with-progression "Committing changes"
 	  (patcher-call-process command output-buffer))
-	;; Don't kill the log message buffer. This will be done after sending
-	;; the message -- i.e. when we are done with this project. We don't
+	;; Don't kill the log message buffer.  This will be done after sending
+	;; the message -- i.e. when we are done with this project.  We don't
 	;; kill the log message buffer now in case the user needs it later --
 	;; e.g. if the commit failed and needs to be redone (we try to detect
 	;; this, but we might not succeed in all cases.).
 Error during commit.  Please fix the problem and type \
 \\[patcher-logmsg-commit] to try again."))))
 	;; Otherwise, record the successful commit in the mail message.
-	;; #### Note: it is normal to protect the re-search-forward calls
-	;; against errors, because when the `fake mail' method is used,
-	;; neither the Subject line nore the mail-header-separator one exist.
+	;; #### NOTE: it is normal to protect the re-search-forward calls
+	;; #### against errors, because when the `fake mail' method is used,
+	;; #### neither the Subject line nore the mail-header-separator one
+	;; #### exist.
 	(with-current-buffer patcher-mail-buffer
 	  (setq patcher-change-committed t)
 	  (save-excursion
 	    ;; Possibly change the subject:
 	    (goto-char (point-min))
-	    (when (re-search-forward "^Subject: " nil t)
+	    (when (patcher-goto-subject)
 	      (let ((subject-committed-prefix
 		     (patcher-project-option patcher-project
 		       :subject-committed-prefix))
 
 (make-variable-buffer-local
  (defvar patcher-diff-command nil
-   ;; String containing the diff command to use. This string is not supposed
-   ;; to include the files to which the command applies. Only the command
-   ;; itself. This variable is needed because the user has the ability to
+   ;; String containing the diff command to use.  This string is not supposed
+   ;; to include the files to which the command applies.  Only the command
+   ;; itself.  This variable is needed because the user has the ability to
    ;; override the project's command by giving a prefix to
    ;; `patcher-generate-diff'.
    ))
 (make-variable-buffer-local
  (defvar patcher-sources nil
    ;; List of files/directories command-line specification for the diff
-   ;; command. This variable is needed because the user has the ability to
+   ;; command.  This variable is needed because the user has the ability to
    ;; override the project's files by calling `patcher-mail-subproject'
    ;; instead of `patcher-mail'.
    ))
 
 (make-variable-buffer-local
  (defvar patcher-change-logs nil
-   ;; List of ChangeLog absolute file names. This is computed after the
-   ;; initial diff by `patcher-diff-base'. Each element is a list of the form
+   ;; List of ChangeLog absolute file names.  This is computed after the
+   ;; initial diff by `patcher-diff-base'.  Each element is a list of the form
    ;; (FILENAME . LOADED). LOADED is a boolean indicating whether we loaded
    ;; the file ourselves, and hence can kill it once we're done.
    ))
     ))
 
 (defun patcher-parse-region (&optional min max buffer)
-  ;; Parse a diff output between MIN and MAX in BUFFER. Defaults to point min,
+  ;; Parse a diff output between MIN and MAX in BUFFER.  Defaults to point min,
   ;; point max and current buffer respectively.
   ;; For each diffed file, create an extent with the following properties:
   ;; 'patcher-change-log = <absolute filename> for ChangeLog files.
 
 (defun patcher-generate-change-logs (&optional min max buffer)
   ;; Generate ChangeLog skeletons based on the diff between MIN and MAX in
-  ;; BUFFER. Defaults to point min, point max and current buffer respectively.
+  ;; BUFFER.  Defaults to point min, point max and current buffer respectively.
   ;; Check `patcher-mail-buffer' first because if that is non nil, we're
-  ;; in an auxiliary buffer. Otherwise, we're in a Patcher mail one.
+  ;; in an auxiliary buffer.  Otherwise, we're in a Patcher mail one.
   (let ((mailbuf (or patcher-mail-buffer (current-buffer))))
     (with-current-buffer (or buffer (current-buffer))
       (patcher-with-progression "Generating ChangeLog skeletons"
 	   :extent-property 'patcher
 	   :extent-property-value mailbuf)))
       ;; patch-to-change-log has the unfortunate side effect of burying all
-      ;; the ChangeLog buffers when it's done. This is exactly the opposite of
+      ;; the ChangeLog buffers when it's done.  This is exactly the opposite of
       ;; what we want, since once the ChangeLogs have been generated, the next
-      ;; step is to go visit them. so put them (in order!) directly below the
+      ;; step is to go visit them.  so put them (in order!) directly below the
       ;; current buffer.
       (let ((topbuf (car (buffer-list))))
 	(dolist (x (patcher-files-buffers
 
 (defun patcher-insert-diff (buffer)
   ;; Insert the diff created in auxiliary BUFFER, and create the patcher-diff
-  ;; extent. This function also filters out lines specified by the
+  ;; extent.  This function also filters out lines specified by the
   ;; diff-line-filter project option.
   (save-excursion
     (goto-char patcher-diff-marker)
   ;; If any, call the after-diff hooks on BUFFER (auxiliary or mail
   ;; buffer), possibly limiting to the region (BEG END).
   ;; #### NOTE: remember that patcher-projects is also set in auxiliary
-  ;;buffers.
+  ;; #### buffers.
   (with-current-buffer buffer
     (let ((after-diff-hook (patcher-project-option patcher-project
 			    :after-diff-hook)))
 Error during diff.  Please fix the problem and type \
 \\[patcher-insert-change-logs] to try again."))
     ;; #### FIXME: maybe check that all changelogs are diff'ed (meaning the
-    ;; user has not forgotten to update one of them).
+    ;; #### user has not forgotten to update one of them).
     (save-excursion
       (goto-char patcher-change-logs-marker)
       (patcher-insert-change-logs-diff-prologue command)
 	  (errors 0)
 	  change-log beg end)
       ;; #### Don't forget to start-close the diff extent !! A ChangeLog could
-      ;; appear at the beginning of the diff.
+      ;; #### appear at the beginning of the diff.
       (set-extent-property diff-extent 'start-open nil)
       (patcher-with-progression "Regenerating ChangeLog diffs"
 	(patcher-map-change-log-extents nil
 	  ;; #### WARNING: it seems that if I modify the extent contents here,
-	  ;; instead of deleting and recreating it, map(car)-extents goes into
-	  ;; an infinite loop, on all extents over and over again.
+	  ;; #### instead of deleting and recreating it, map(car)-extents goes
+	  ;; #### into an infinite loop, on all extents over and over again.
 	  (setq change-log (extent-property extent 'patcher-change-log))
 	  (goto-char (extent-start-position extent))
 	  (setq beg (point-marker))
 	    (source-diff
 	     (patcher-command patcher-project patcher-diff-command))
 	    ;; #### NOTE: maybe passing a list instead of a string would be
-	    ;; better. I won't break backward compatibility though, at least
-	    ;; not before a major release.
+	    ;; #### better.  I won't break backward compatibility though, at
+	    ;; #### least not before a major release.
 	    (source-files (patcher-files-string (patcher-sources)))
 	    (change-log-files (patcher-files-string patcher-change-logs))
 	    (change-log-diff
       ;; We do ChangeLogs, so deal with the formatting.
       (cond ((eq updating 'automatic)
 	     ;; In the "automatic" case, ChangeLog contents insertion is
-	     ;; postponed until the user has edited the skeletons. If no files
+	     ;; postponed until the user has edited the skeletons.  If no files
 	     ;; were specified, we have a chance to check that the project is
 	     ;; up to date: if a ChangeLog appears in the diff, the project
-	     ;; needs to be updated first. Note that this does not catch all
+	     ;; needs to be updated first.  Note that this does not catch all
 	     ;; cases though.
 	     (cond ((or (eq appearance 'verbatim)
 			(eq appearance 'packed))
 				       (patcher-change-logs buffer))
 			      (patcher-change-logs-diff-error))
 			    ;; ChangeLogs must appear in the patch, so there's
-			    ;; no point in inserting the diff right now. It
+			    ;; no point in inserting the diff right now.  It
 			    ;; needs to be redone afterwards.
 			    (patcher-generate-change-logs nil nil buffer)
 			    (patcher-message "\
 	     )
 	    ((eq updating 'manual)
 	     ;; In the "manual" case, ChangeLogs are supposed to be already
-	     ;; written, so their insertion does not have to be postponed. If
+	     ;; written, so their insertion does not have to be postponed.  If
 	     ;; no files were specified, we have a chance to check that
 	     ;; ChangeLogs /really/ are up to date: the diff output should
 	     ;; contain all ChangeLog entries.
 Please update them before running Patcher."))
 	     (cond ((eq appearance 'verbatim)
 		    ;; #### NOTE: when ChangeLog entries are part of the diff,
-		    ;; we could try to convert the diff to a verbatim version
-		    ;; instead of calling
+		    ;; #### we could try to convert the diff to a verbatim
+		    ;; #### version  instead of calling
 		    ;; `patcher-insert-change-logs-verbatim'.
 		    (patcher-remove-change-logs buffer)
 		    (patcher-insert-diff buffer)
 		      (cond ((eq command 'diff)
 			     ;; We use the same diff command:
 			     (if (not patcher-sources)
-				 ;; All ChangeLogs appear in the diff. We can
+				 ;; All ChangeLogs appear in the diff.  We can
 				 ;; just move them to a pack.
 				 (progn
 				   (and regenerate
 				    patcher-diff-command)))
 			     )
 			    ((stringp command)
-			     ;; The diff command is different. We have to
+			     ;; The diff command is different.  We have to
 			     ;; (re)diff them anyway.
 			     (patcher-remove-change-logs buffer)
 			     (patcher-insert-diff buffer)
 
 
 (defcustom patcher-minor-mode-string " Patch"
-  "*String to use in the modeline when Patcher minor mode is active."
+  "*Patcher minor mode modeline string."
   :group 'patcher
   :type 'string)
 
 ;; Mail preparation routines
 ;; ===========================================================================
 
+(patcher-globally-declare-boundp '(message-exit-actions))
+
+
+(defvar patcher-projects-history nil
+  ;; History used for prompting patcher projects.
+  )
+
+(defvar patcher-subjects-history nil
+  ;; History used for prompting patcher mail subjects.
+  )
+
 (defgroup patcher-mail nil
   "Mailing options for Patcher projects."
   :group 'patcher)
   ;; Function hooked in the different mailing methods to perform some
   ;; checkings prior to sending the message.
   ;; #### NOTE: it is currently impossible (and probably not worth it) to
-  ;; offer an automatic ChangeLog insertion or commit operation at that point:
-  ;; we're already in an interactive call (the message sending pocess) and a
-  ;; complex trickery would be necessary in case of operation failure. So it's
-  ;; simpler to just abort the sending, let the user manually fix things, and
-  ;; re-send the message.
+  ;; #### offer an automatic ChangeLog insertion or commit operation at that
+  ;; #### point: we're already in an interactive call (the message sending
+  ;; #### pocess) and a complex trickery would be necessary in case of
+  ;; #### operation failure.  So it's simpler to just abort the sending, let
+  ;; #### the user manually fix things, and re-send the message.
 
   ;; Check ChangeLogs insertion:
   (let ((updating
       (patcher-save-buffers buffers)
       (dolist (b buffers)
 	(let ((ac (assoc (buffer-file-name b) patcher-change-logs)))
-	  (when (or (not ac) ;; ??????
+	  (when (or (not ac) ;; #### ??????
 		    (cdr ac))
 	    (kill-buffer b))))))
   (when patcher-logmsg-buffer
   (when patcher-pre-commit-window-config
     (set-window-configuration patcher-pre-commit-window-config)))
 
+(defun patcher-install-send-hooks ()
+  ;; Install before- and after-send hooks into the MUA.
+  (cond ((eq major-mode 'mail-mode)
+	 (add-local-hook 'mail-send-hook 'patcher-before-send)
+	 (push '(patcher-after-send) mail-send-actions))
+	((eq major-mode 'message-mode)
+	 (add-local-hook 'message-send-hook 'patcher-before-send)
+	 ;; `message-exit-actions' is probably more appropriate than
+	 ;; `message-send-actions' to perform the cleanup.
+	 (push '(patcher-after-send) message-exit-actions))
+	(t
+	 (patcher-warning "\
+Major mode: %s.
+This mailing method is not fully supported by Patcher.
+This is not critical though: Patcher won't be able to perform checks or
+cleanups during mail sending.
+
+Please report to <didier@xemacs.org>."
+			  major-mode))))
+
 
 ;; Patcher FakeMail mode ====================================================
 
 Only perform the usual cleanup after real Patcher mails are sent."
   (interactive)
   (patcher-before-send)
-  (patcher-after-send nil)
+  (patcher-after-send)
   (kill-buffer (current-buffer)))
 
 (defvar patcher-fakemail-mode-map
 
 (patcher-globally-declare-fboundp
  '(gnus-alive-p gnus gnus-other-frame gnus-post-news
-		message-mail message-goto-subject message-goto-body))
+		message-mail message-goto-body))
 
 (defmacro patcher-with-mail-parameters (project &rest body)
   ;; Wrap BODY in a let construct possibly defining user-full-name and
-  ;;user-mail-address by Patcher options.
+  ;; user-mail-address by Patcher options.
   ;; Return the value of BODY execution.
   ;; #### NOTE: why is it called like this ? Because I'm sure one day or
-  ;;another, some sucker will ask for more parameters, like the mail
-  ;;signature for instance ;-)
+  ;; #### another, some sucker will ask for more parameters, like the mail
+  ;; #### signature for instance ;-)
   `(let ((user-full-name (or (patcher-project-option ,project :user-name)
 			     user-full-name))
 	 (user-mail-address (or (patcher-project-option ,project :user-mail)
   (patcher-with-mail-parameters project
     (compose-mail (or (patcher-project-option project :to-address)
 		      (read-string "To address: "))
-		  subject nil nil nil nil '((patcher-after-send))))
-  (cond ((eq mail-user-agent 'sendmail-user-agent)
-	 (add-local-hook 'mail-send-hook 'patcher-before-send))
-	((or (eq mail-user-agent 'message-user-agent)
-	     (eq mail-user-agent 'gnus-user-agent))
-	 (add-local-hook 'message-send-hook 'patcher-before-send))
-	(t
-	 (warn "\
-Your mail user agent (%s) is not fully supported by Patcher.
-This is not critical: it onlly means that Patcher will not be
-able to perform some checks before sending the message.
-
-Please report this message to <didier@xemacs.org>."
-	       mail-user-agent
-	       ))
-	))
+		  subject))
+  (patcher-install-send-hooks))
+
 
 (defun patcher-mail-sendmail (project subject)
   "Prepare a patch-related mail with the `mail' function.
   (patcher-with-mail-parameters project
     (mail nil (or (patcher-project-option project :to-address)
 		  (read-string "To address: "))
-	  subject nil nil nil '((patcher-after-send))))
-  (add-local-hook 'mail-send-hook 'patcher-before-send))
-
-(defvar message-exit-actions)
+	  subject))
+  (add-local-hook 'mail-send-hook 'patcher-before-send)
+  (push '(patcher-after-send) mail-send-actions))
+
 (defun patcher-mail-message (project subject)
   "Prepare a patch-related mail with the `message-mail' function.
 This method requires the `message' library.
     (message-mail (or (patcher-project-option project :to-address)
 		      (read-string "To address: "))
 		  subject))
+  (add-local-hook 'message-send-hook 'patcher-before-send)
   ;; `message-exit-actions' is probably more appropriate than
   ;; `message-send-actions' to perform the cleanup.
-  (push '(patcher-after-send) message-exit-actions)
-  (add-local-hook 'message-send-hook 'patcher-before-send))
+  (push '(patcher-after-send) message-exit-actions))
 
 
 (defcustom patcher-mail-run-gnus 'prompt
   (let ((gnus-newsgroup-name (or (patcher-project-option project :gnus-group)
 				 (read-string "Gnus group name: "))))
     (patcher-with-mail-parameters project
-      (gnus-post-news 'post gnus-newsgroup-name))
-    (message-goto-subject)
-    (insert subject)
-    (message-goto-body)
-    ;; `message-exit-actions' is probably more appropriate than
-    ;; `message-send-actions' to perform the cleanup.
-    (push '(patcher-after-send) message-exit-actions))
-  (add-local-hook 'message-send-hook 'patcher-before-send))
+      (gnus-post-news 'post gnus-newsgroup-name)))
+  (when (patcher-goto-subject)
+    (insert subject))
+  (message-goto-body)
+  (add-local-hook 'message-send-hook 'patcher-before-send)
+  ;; `message-exit-actions' is probably more appropriate than
+  ;; `message-send-actions' to perform the cleanup.
+  (push '(patcher-after-send) message-exit-actions))
 
 (defun patcher-mail-fake (project subject)
   "Prepare a patch-related fake mail.
   (let ((buffer (generate-new-buffer "*Patcher Fake Mail*")))
     (switch-to-buffer buffer)
     ;; #### NOTE: Patcher asks for a subject even with the fakemail method,
-    ;; which is arguable. However, even with a fake mail, one could require
-    ;; log message initialization from a fake subject. We could do something
-    ;; more clever here.
+    ;; #### which is arguable.  However, even with a fake mail, one could
+    ;; #### require log message initialization from a fake subject.  We could
+    ;; #### do something more clever here.
     (insert "Subject: " subject "\n")
     (patcher-fakemail-mode)
     ))
 
-(defun patcher-mail-1 (project subject files &optional override)
-  ;; Perform the real job of preparing the mail buffer.
-  (let ((subject-prefix (patcher-project-option project :subject-prefix))
-	extent)
-    ;; Construct the subject, maybe with an extent marking the prefix:
-    (when (> (length subject-prefix) 0)
-      (setq subject-prefix (patcher-substitute-name project subject-prefix))
-      (setq extent (make-extent 0 (length subject-prefix) subject-prefix))
-      (set-extent-properties extent
-	'(duplicable t patcher-subject-prefix t)))
-    (setq subject (concat subject-prefix
-			  (and subject-prefix (> (length subject-prefix) 0)
-			       subject (> (length subject) 0)
-			       " ")
-			  subject))
-    (funcall
-     (intern (concat "patcher-mail-"
-		     (symbol-name
-		      (patcher-project-option project :mail-method))))
-     project subject))
+(defun patcher-mail-setup (project files)
+  ;; Setup patcher-minor-mode and initialize Patcher local variables in mails
+  ;; (both generated or adapted).
   (push (cons (buffer-name) (current-buffer)) patcher-instances)
   (patcher-minor-mode t)
   (setq patcher-project project)
       (cd (patcher-project-directory project))
       (setq patcher-sources files)
       ))
-  (setq patcher-diff-command (patcher-project-option project :diff-command))
+  (setq patcher-diff-command (patcher-project-option project :diff-command)))
+
+
+;; Mail generation entry points =============================================
+
+(defun patcher-mail-1 (project subject files override)
+  ;; Perform the real job of preparing the mail buffer.
+  (let ((subject-prefix (patcher-project-option project :subject-prefix))
+	extent)
+    ;; Construct the subject, maybe with an extent marking the prefix:
+    (when (> (length subject-prefix) 0)
+      (setq subject-prefix (patcher-substitute-name project subject-prefix))
+      (setq extent (make-extent 0 (length subject-prefix) subject-prefix))
+      (set-extent-properties extent
+	'(duplicable t patcher-subject-prefix t)))
+    (setq subject (concat subject-prefix
+			  (and subject-prefix (> (length subject-prefix) 0)
+			       subject (> (length subject) 0)
+			       " ")
+			  subject))
+    (funcall
+     (intern (concat "patcher-mail-"
+		     (symbol-name
+		      (patcher-project-option project :mail-method))))
+     project subject))
+  (patcher-mail-setup project files)
   (let ((mail-prologue (patcher-project-option project :mail-prologue)))
     (when (> (length mail-prologue) 0)
       (insert "\n" mail-prologue)))
     (patcher-generate-diff override)))
 
 
-;; Entry points for Patcher mails ============================================
-
-(defvar patcher-projects-history nil
-  ;; History used for prompting patcher projects.
-  )
-
-(defvar patcher-subjects-history nil
-  ;; History used for prompting patcher mail subjects.
-  )
-
 ;;;###autoload
 (defun patcher-mail-subproject (project subject files &optional arg)
   "Prepare a mail about a patch to apply on part of a project.
 directories the subproject is composed of.
 
 When you use this command instead of `patcher-mail', any commits issued
-from the mail buffer (using
-\\<patcher-minor-mode-map>\\[patcher-commit-change]) will automatically
-include
+from the mail buffer (using \\<patcher-minor-mode-map>\\[patcher-commit-change]) will automatically include
 the associated ChangeLogs, as well as the file(s) specified as part of
 this command.
 
 		  (and (interactive-p) arg))
   )
 
+
+;; Mail adaptation entry points =============================================
+
+;; #### NOTE: the prefix argument usage in patcher-mail[-subproject]
+;; #### to override the diff command is broken by design (it comes from an
+;; #### early version of Patcher): why the diff command and not any other
+;; #### option ? I'm not going to propagate this misconception here, so the
+;; #### adaptation functions don't have a prefix argument at all.
+
+(defun patcher-mail-adapt-1 (project files)
+  ;; Like `patcher-mail-1', but for already existing mails.
+  (let ((subject-prefix (patcher-project-option project :subject-prefix))
+	extent)
+    ;; Construct the subject, maybe with an extent marking the prefix:
+    (when (> (length subject-prefix) 0)
+      (setq subject-prefix (patcher-substitute-name project subject-prefix))
+      (setq extent (make-extent 0 (length subject-prefix) subject-prefix))
+      (set-extent-properties extent '(duplicable t patcher-subject-prefix t))
+      (when (patcher-goto-subject)
+	(insert subject-prefix " "))))
+  (patcher-install-send-hooks)
+  (patcher-mail-setup project files)
+  ;; #### FIXME: currently, I have simply discarded the mail-prologue
+  ;; #### insertion for adapted mails. This is because mail adaptation is
+  ;; #### mostly for replies in which you probably don't want the standard
+  ;; #### prologue. However, this could be turned into a standard option.
+  ;;  (let ((mail-prologue (patcher-project-option project :mail-prologue)))
+  ;;    (when (> (length mail-prologue) 0)
+  ;;      (insert "\n" mail-prologue)))
+  (patcher-goto-signature)
+  (when (patcher-project-option project :change-logs-updating)
+    (let ((appearance
+	   (patcher-project-option project :change-logs-appearance)))
+      (when (and appearance (not (eq appearance 'patch)))
+	(setq patcher-change-logs-marker (point-marker))
+	(insert "\n"))))
+  (setq patcher-diff-marker (point-marker))
+  (patcher-generate-diff))
+
+;;;###autoload
+(defun patcher-mail-adapt (project)
+  "Same as `patcher-mail', but for already started mails.
+This function is mostly designed to adapt replies or followups probably
+started with your usual MUA to Patcher.
+
+Note two differences with `patcher-mail' however:
+1. there is no SUBJECT argument to this function,
+2. no prefix argument is available to override the diff command."
+  (interactive
+   (list (assoc (completing-read "Project: " (append patcher-subprojects
+						     patcher-projects)
+				 nil t nil 'patcher-projects-history)
+		(append patcher-subprojects patcher-projects))))
+  (patcher-mail-adapt-1 project (patcher-project-option project :files)))
+
+;;;###autoload
+(defun patcher-mail-adapt-subproject (project files)
+  "Same as `patcher-mail-subproject', but for already started mails.
+This function is mostly designed to adapt replies or followups probably
+started with your usual MUA to Patcher.
+
+Note two differences with `patcher-mail-subproject' however:
+1. there is no SUBJECT argument to this function,
+2. no prefix argument is available to override the diff command."
+  (interactive
+   (let* ((prj (assoc (completing-read "Project: " (append patcher-subprojects
+							   patcher-projects)
+				       nil t nil 'patcher-projects-history)
+		      (append patcher-subprojects patcher-projects)))
+	  (dir (patcher-project-directory prj))
+	  (fls (let ((default-directory (file-name-as-directory dir)))
+		 (or (let ((f (patcher-project-option prj :files)))
+		       (and f (read-shell-command "Files: " (concat f " ")
+						  nil f)))
+		     (let* ((default-file (and (buffer-file-name)
+					       (patcher-file-relative-name
+						(buffer-file-name)
+						dir 'raw)))
+			    (default-file
+			      ;; If the file is not actually underneath the
+			      ;; project, then don't suggest it as a
+			      ;; possibility.
+			      (and default-file
+				   (if (string-match "^\\.\\.$\\|^\\.\\.[/\\]"
+						     default-file)
+				       nil default-file))))
+		       (read-shell-command
+			"Files: "
+			default-file nil default-file))))))
+     (list prj fls)))
+  (patcher-mail-adapt-1 project files))
+
+
+;; Patcher Gnus Summary minor mode ==========================================
+
+(patcher-globally-declare-fboundp
+ '(gnus-summary-followup gnus-summary-followup-with-original
+   gnus-summary-reply gnus-summary-reply-with-original))
+
+(defun patcher-gnus-summary-followup (&optional arg)
+  "Prepare a Patcher followup from the Gnus Summary buffer.
+With a prefix argument, behave like `patcher-mail-subproject' instead of
+`patcher-mail'."
+  (interactive "P")
+  (gnus-summary-followup nil)
+  (call-interactively
+   (if arg
+       'patcher-mail-adapt-subproject
+     'patcher-mail-adapt)))
+
+(defun patcher-gnus-summary-followup-with-original (&optional arg)
+  "Prepare a Patcher followup from the Gnus Summary buffer.
+The original message is yanked.
+With a prefix argument, behave like `patcher-mail-subproject' instead of
+`patcher-mail'."
+  (interactive "P")
+  (gnus-summary-followup-with-original nil)
+  (call-interactively
+   (if arg
+       'patcher-mail-adapt-subproject
+     'patcher-mail-adapt)))
+
+(defun patcher-gnus-summary-reply (&optional arg)
+  "Prepare a Patcher reply from the Gnus Summary buffer.
+With a prefix argument, behave like `patcher-mail-subproject' instead of
+`patcher-mail'."
+  (interactive "P")
+  ;; #### NOTE: it is strange that this function's first argument is not
+  ;; #### mandatory, as in the 3 other ones.
+  (gnus-summary-reply)
+  (call-interactively
+   (if arg
+       'patcher-mail-adapt-subproject
+     'patcher-mail-adapt)))
+
+(defun patcher-gnus-summary-reply-with-original (&optional arg)
+  "Prepare a Patcher reply from the Gnus Summary buffer.
+The original message is yanked.
+With a prefix argument, behave like `patcher-mail-subproject' instead of
+`patcher-mail'."
+  (interactive "P")
+  (gnus-summary-reply-with-original nil)
+  (call-interactively
+   (if arg
+       'patcher-mail-adapt-subproject
+     'patcher-mail-adapt)))
+
+(defcustom patcher-gnus-summary-minor-mode-string " Patch"
+  "*Patcher Gnus Summary minor mode modeline string."
+  :group 'patcher
+  :type 'string)
+
+(defcustom patcher-gnus-summary-minor-mode-hook nil
+  "*Hooks to run after setting up Patcher Gnus Summary minor mode."
+  :group 'patcher
+  :type 'hook)
+
+(defvar patcher-gnus-summary-minor-mode-map
+  (let ((map (make-sparse-keymap 'patcher-minor-mode-map)))
+    (define-key map [(control c) (control p) f]
+      'patcher-gnus-summary-followup)
+    (define-key map [(control c) (control p) F]
+      'patcher-gnus-summary-followup-with-original)
+    (define-key map [(control c) (control p) r]
+      'patcher-gnus-summary-reply)
+    (define-key map [(control c) (control p) R]
+      'patcher-gnus-summary-reply-with-original)
+    map)
+  ;; Patcher Gnus Summary minor mode keymap.
+  )
+
+(make-variable-buffer-local
+ (defvar patcher-gnus-summary-minor-mode nil))
+
+(defun patcher-gnus-summary-minor-mode (arg)
+  "Toggles Patcher Gnus Summary minor mode.
+Used for Patcher messages composed as Gnus replies and followups.
+You're not supposed to use this, unless you know what you're doing.
+
+\\{patcher-gnus-summary-minor-mode-map}"
+  (interactive "*P")
+  (setq patcher-gnus-summary-minor-mode
+	(if (null arg) (not patcher-gnus-summary-minor-mode)
+	  (> (prefix-numeric-value arg) 0)))
+  (run-hooks 'patcher-gnus-summary-minor-mode-hook))
+
+(add-minor-mode
+ 'patcher-gnus-summary-minor-mode
+ patcher-gnus-summary-minor-mode-string
+ patcher-gnus-summary-minor-mode-map)
+
+
+;; Patcher Gnus Article minor mode ==========================================
+
+(defcustom patcher-gnus-article-minor-mode-string " Patch"
+  "*Patcher Gnus Article minor mode modeline string."
+  :group 'patcher
+  :type 'string)
+
+(defcustom patcher-gnus-article-minor-mode-hook nil
+  "*Hooks to run after setting up Patcher Gnus Article minor mode."
+  :group 'patcher
+  :type 'hook)
+
+(defvar patcher-gnus-article-minor-mode-map
+  (let ((map (make-sparse-keymap 'patcher-minor-mode-map)))
+    (define-key map [(control c) (control p) f]
+      'patcher-gnus-summary-followup)
+    (define-key map [(control c) (control p) F]
+      'patcher-gnus-summary-followup-with-original)
+    (define-key map [(control c) (control p) r]
+      'patcher-gnus-summary-reply)
+    (define-key map [(control c) (control p) R]
+      'patcher-gnus-summary-reply-with-original)
+    map)
+  ;; Patcher Gnus Article minor mode keymap.
+  )
+
+(make-variable-buffer-local
+ (defvar patcher-gnus-article-minor-mode nil))
+
+(defun patcher-gnus-article-minor-mode (arg)
+  "Toggles Patcher Gnus Article minor mode.
+Used for Patcher messages composed as Gnus replies and followups.
+You're not supposed to use this, unless you know what you're doing.
+
+\\{patcher-gnus-article-minor-mode-map}"
+  (interactive "*P")
+  (setq patcher-gnus-article-minor-mode
+	(if (null arg) (not patcher-gnus-article-minor-mode)
+	  (> (prefix-numeric-value arg) 0)))
+  (run-hooks 'patcher-gnus-article-minor-mode-hook))
+
+(add-minor-mode
+ 'patcher-gnus-article-minor-mode
+ patcher-gnus-article-minor-mode-string
+ patcher-gnus-article-minor-mode-map)
+
+
+;; ==========================================================================
+;; Routines to plug Patcher into external libraries
+;; ==========================================================================
+
+(patcher-globally-declare-boundp
+ '(gnus-summary-mode-hook gnus-article-mode-hook))
+
+;;;###autoload
+(defun patcher-insinuate-gnus ()
+  "This function plugs Patcher into Gnus.
+It should be called from your gnusrc file."
+  (add-hook 'gnus-summary-mode-hook
+	    '(lambda () (patcher-gnus-summary-minor-mode 1)))
+  (add-hook 'gnus-article-mode-hook
+	    '(lambda () (patcher-gnus-article-minor-mode 1))))
+
+
 (provide 'patcher)
 
 ;;; patcher.el ends here
+2005-07-26  Didier Verna  <didier@xemacs.org>
+
+	* Patcher 3.8 is released.
+
+	* patcher.texi: Remove the GFDL.
+
+	* patcher.texi (Installation): New. Add the three subnodes below.
+	* patcher.texi (Distribution): Moved under Installation.
+	* patcher.texi (Requirements): Ditto.
+	* patcher.texi (Insinuation): New.
+	* patcher.texi (Mail Preparation): Document the mail adaptation
+	and reply feature.
+	* patcher.texi (Patch Restriction): Ditto.
+
 2004-11-08  Didier Verna  <didier@xemacs.org>
 
 	* Patcher 3.6.2 is released.

texi/patcher.texi

 
 @c #### TODO:
 @c - Add a section on how to setup Patcher for PRCS.
+@c   Or better yet: provide default themes from which people would get
+@c   inspiration.
 
 
 @c %** start of header
 @c ====================================================================
 @c Definitions
 @c ====================================================================
-@set VERSION 3.7
-@set COPYRIGHT_DATE 1999, 2000, 2001, 2002, 2003, 2004
+@set VERSION 3.8
+@set COPYRIGHT_DATE 1999, 2000, 2001, 2002, 2003, 2004, 2005
 
 
 @c ====================================================================
 
 Copyright @copyright{} @value{COPYRIGHT_DATE} Didier Verna.
 
-Permission is granted to copy, distribute and/or modify this document
-under the terms of the GNU Free Documentation License Version 1.2, as
-published by the Free Software Foundation; with the Invariant Sections
-being just this one, no Front-Cover Texts, and no Back-Cover Texts. A
-copy of the license is included in the file @file{COPYING.DOC}.
+Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
 
 @ignore
 Permission is granted to process this file through TeX and print the
-result, provided that the printed document carries a copying permission
+results, provided the printed document carries a copying permission
 notice identical to this one except for the removal of this paragraph
 (this paragraph not being relevant to the printed manual).
 
 @end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+sections entitled ``Copying'' and ``GNU General Public License'' are
+included exactly as in the original, and provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation
+approved by the Free Software Foundation.
 @end ifinfo
 
 
 @vskip 0pt plus 1filll
 Copyright @copyright{} @value{COPYRIGHT_DATE} Didier Verna.
 
-Permission is granted to copy, distribute and/or modify this document
-under the terms of the GNU Free Documentation License Version 1.2, as
-published by the Free Software Foundation; with the Invariant Sections
-being just this one, no Front-Cover Texts, and no Back-Cover Texts. A
-copy of the license is included in the file @file{COPYING.DOC}.
+
+Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+sections entitled ``Copying'' and ``GNU General Public License'' are
+included exactly as in the original, and provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation
+approved by the Free Software Foundation.
 @end titlepage
 
 
 @menu
 * Copying::          The GNU General Public License
 * Introduction::     What Patcher is all about
-* Distribution::     How to obtain and install Patcher
-* Requirements::     What you need to get Patcher running
+* Installation::     How to get and install Patcher
 * Quick Start::      For the brave and the impatient
 * User Manual::      A step-by-step guide to using Patcher
 * Variables Index::
 @c ====================================================================
 @c Introduction
 @c ====================================================================
-@node Introduction, Distribution, Copying, Top
+@node Introduction, Installation, Copying, Top
 @comment  node-name,  next,  previous,  up
 @chapter Introduction
 
 When a project becomes important in size, or when the development is
 performed cooperatively by several people across the Internet, it is a
 common practice to help maintaining it by using a development control
-system. Such tools (CVS, PRCS, to name a few) usually work by maintaining
-a centralized project archive (also called a repository) that keeps
-track of the history of the changes, lets you develop different
-"branches" at the same time and perform operations like merges between
-these different project branches.
+system. Such tools (CVS, PRCS, to name a few) usually work by
+maintaining a centralized project archive (also called a repository)
+that keeps track of the history of the changes, lets you develop
+different ``branches'' at the same time and perform operations like
+merges between these different project branches.
 
-In such "archive-based" maintenance models, making the project evolve
+In such ``archive-based'' maintenance models, making the project evolve
 usually involves repeatedly the same few steps, some of which can be
 tedious: you work on your local copy of the project; once you're
 satisfied with your changes, you create a patch by diffing your local
 
 
 @c ====================================================================
-@c Distribution
+@c Installation
 @c ====================================================================
-@node Distribution, Requirements, Introduction, Top
+@node Installation, Quick Start, Introduction, Top
 @comment  node-name,  next,  previous,  up
-@chapter Distribution
+@chapter Installation
+
+@menu
+* Distribution::                How to get Patcher
+* Requirements::                What you need to get Patcher running
+* Insinuation::                 How to plug Patcher into other libraries
+@end menu
+
+
+@c Distribution =======================================================
+@node Distribution, Requirements, , Installation
+@comment  node-name,  next,  previous,  up
+@section Distribution
 
 Patcher is available either as a standalone package, or as part of the
 standard @file{xemacs-devel} XEmacs package.
 @file{xemacs-devel}. The standalone version of Patcher can be found at
 @uref{http://www.lrde.epita.fr/~didier/comp/development/software.php}.
 You will also find different inlined versions of this documentation at
-that place.
+that place. For installation instructions, please read the
+@file{INSTALL} file.
 
 
-
-@c ====================================================================
-@c Requirements
-@c ====================================================================
-
-@node Requirements, Quick Start, Distribution, Top
+@c Requirements =======================================================
+@node Requirements, Insinuation, Distribution, Installation
 @comment  node-name,  next,  previous,  up
-@chapter Requirements
+@section Requirements
 
 Patcher currently works only with XEmacs 21.4 or later. I'm not sure it
 works with earlier versions of XEmacs, but I'm sure it does @strong{not}
 
 @item
 If you want to send mails from Patcher (@pxref{Mail Methods}), you will
-need a mail user agent. Patcher currently supports @file{compose-mail},
-@file{sendmail}, @file{message} and @file{Gnus} natively.
+need a mail user agent. Patcher currently supports @file{sendmail},
+@file{message} and @file{Gnus} natively and through the
+@file{compose-mail} interface. Other MUA might be partly supported when
+used with @code{compose-mail}. Patcher will probably suffer from non
+critical deficiencies in that case however (it will issue warnings).
 @end itemize
 
 
+@c Insinuation ========================================================
+@node Insinuation, , Requirements, Installation
+@comment  node-name,  next,  previous,  up
+@section Insinuation
+
+With a proper installation of Patcher (either way), you don't need any
+special trickery in your @file{.emacs} file because all entry points to
+the library should be autoloaded.
+
+However, Patcher has the ability to hook into external libraries, but
+won't do so unless requested. Currently, Patcher has hooks for Gnus
+only. If you're using Gnus as your MUA, you might want to add the
+following line to your @file{gnusrc} file:
+
+@example
+(patcher-insinuate-gnus)
+@end example
+
+This will add some facilities described along the text.
+
+
 
 @c ====================================================================
 @c Quick Start
 @c ====================================================================
-@node Quick Start, User Manual, Requirements, Top
+@node Quick Start, User Manual, Installation, Top
 @comment  node-name,  next,  previous,  up
 @chapter Quick Start
 
 @comment  node-name,  next,  previous,  up
 @section Setting up Patcher
 
-The first thing to do is to make patcher aware of your "XEmacs" project.
-Put this in your @file{.emacs} file:
+The first thing to do is to make patcher aware of your ``XEmacs''
+project. Put this in your @file{.emacs} file:
 
 @lisp
 (setq patcher-projects
 @vindex patcher-projects
 As you can imagine, @code{patcher-projects} is a user option in which
 you store information about the projects you want to manage with
-Patcher. It is actually a list of what's called @dfn{project descriptors}.
-Here's the meaning of the only project descriptor we have in the example
-above: we have a project named "XEmacs", located in
+Patcher. It is actually a list of what's called @dfn{project
+descriptors}. Here's the meaning of the only project descriptor we have
+in the example above: we have a project named ``XEmacs'', located in
 @file{/usr/local/src/XEmacs-21.5} and for which emails should be sent to
 @email{xemacs-patches@@xemacs.org}.
 
 @findex patcher-mail
 First, you're prompted (with completion) for a project name (the first
 element of each project descriptor, remember ?). We currently only have
-an "XEmacs" project, so hitting @kbd{TAB} will directly fill the
+an ``XEmacs'' project, so hitting @kbd{TAB} will directly fill the
 minibuffer in with this only choice. Then, you're prompted for a subject
 line that will be used in the mail. Say something sensible.
 
 @vindex :to-address
 Patcher prepares a mail buffer. The message will be sent to the address
 you specified with the @code{:to-address} project option, and the
-subject line now reads "[PATCH] something sensible".
+subject line now reads ``[PATCH] something sensible''.
 
 @item
 Patcher now builds the patch. The command used to do this is @samp{cvs
 on the method you use for sending mails, but will usually be done via a
 @samp{C-c C-c} command of some sort. On thing to note however: if you've
 committed your changes via Patcher, the message has been slightly
-modified: the subject line now reads "[COMMIT] something sensible"
-instead of "[PATCH] @dots{}", and a short commit notice has been inserted
-just at the beginning of the message's body.
+modified: the subject line now reads ``[COMMIT] something sensible''
+instead of ``[PATCH] @dots{}'', and a short commit notice has been
+inserted just at the beginning of the message's body.
 
 That's it. That was easy. Congratulations on your first shot at Patcher,
 anyway ! Of course, Patcher is much more powerful and customizable than
 tasks. Good question. Here is a good answer.
 
 Projects might share options for different reasons. For example, my
-"XEmacs" (source) and "XEmacs Packages" projects share many options
+``XEmacs'' (source) and ``XEmacs Packages'' projects share many options
 (@code{To:} address, @code{From:} address, diff and commit commands and
 so on) because they both relate to XEmacs. On the other hand I have
 personal but totally unrelated projects that share the same commands
 @comment  node-name,  next,  previous,  up
 @section Mail Preparation
 
-Patcher currently uses the mail buffers as "master" buffers for
+Patcher currently uses the mail buffers as ``master'' buffers for
 controlling all operations: building a patch, creating the ChangeLog
-entries, committing@dots{} all is done from the mail buffer.
+entries, committing@dots{} all is done from the mail buffer. Note
+however that you don't need to actually send mails to use Patcher
+(@pxref{Fake Mail Method}).
 
-@findex patcher-mail
-To start using Patcher on a certain project, you call the function
-@samp{patcher-mail}. This function will interactively prompt you for the
-name of the project and for a (mail) subject line. Patcher starts
-working on the project (by first creating the patch) after the message
-is prepared. Because of this, we'll start by reviewing the mail-related
-customizations you might want to setup.
+To use Patcher on a certain project, you start by preparing a (possibly
+fake) mail. There are several ways to do so: you could start a brand new
+message, ``adapt'' a message already in preparation to Patcher, or even
+compose some sort of a Patcher reply to another message.
+
+@defun patcher-mail
+Start composing a brand new Patcher message. This function interactively
+prompts you for the name of the project and for a (mail) subject line.
+@end defun
+
+@defun patcher-mail-adapt
+Assuming that you are already editing a message (with your usual MUA),
+this function ``adapts'' it to Patcher by prompting you for the name of
+a project. Note that this function does @emph{not} prompt you for a
+subject.
+@end defun
+
+If you're using Gnus to read mail and have properly insinuated it
+(@pxref{Insinuation}), Patcher offers different Gnus-like ways to answer
+mails and adapt them to Patcher. All the functions below are available
+from both the Gnus Summary and the Article buffer.
+
+@defun patcher-gnus-summary-followup
+@kindex C-c C-p f
+Compose a followup to the article, and adapt it to Patcher. This
+function is bound to @kbd{C-c C-p f}.
+@end defun
+
+@defun patcher-gnus-summary-followup-with-original
+@kindex C-c C-p F
+Idem, but also cite the original article. This function is bound to
+@kbd{C-c C-p F}.
+@end defun
+
+@defun patcher-gnus-summary-reply
+@kindex C-c C-p r
+Like @code{patcher-gnus-summary-followup}, but compose a reply. This
+function is bound to @kbd{C-c C-p r}.
+@end defun
+
+@defun patcher-gnus-summary-reply-with-original
+@kindex C-c C-p R
+Idem, but also cite the original article. This function is bound to
+@kbd{C-c C-p R}.
+@end defun
+
+
+In any case, Patcher starts working on the project (by first creating
+the patch) after the message is prepared. Because of this, we'll start
+by reviewing the mail-related customizations you might want to setup.
 
 @menu
 * Mail Methods::          Using a particular mailer
 @comment  node-name,  next,  previous,  up
 @subsubsection Standard Mail Methods
 
+Patcher currently supports @file{sendmail}, @file{message} and
+@file{Gnus} natively and through the @file{compose-mail} interface.
+Other MUA might be partly supported when used with @code{compose-mail}.
+Patcher will probably suffer from non critical deficiencies in that case
+however (it will issue warnings).
+
 @table @code
 @item compose-mail
 @findex compose-mail
 
 @vindex patcher-default-mail-method
 @vindex :mail-method
-If you're not satisfied with the provided mail methods (but really, you
-should; or, give me a @code{vm} one), you can provide your own. Here's
-what to do: set your @code{:mail-method} project option to, say,
-@code{foo}, and write your own function which must be named
-@code{patcher-mail-foo}.
+If you're not satisfied with the provided mail methods (want a @code{vm}
+one ?), you can provide your own, more or less. Here's what to do: set
+your @code{:mail-method} project option to, say, @code{foo}, and write
+your own function which must be named @code{patcher-mail-foo}.
 
 This function must take two arguments (a project descriptor and a string
 containing the subject of the message), and prepare a mail buffer. If
 you want to do this, you should see how it's done for the built-in
 methods.
 
+Note that the mail adaptation facility won't be available for your
+custom method. For that, I would have to hack the internals of Patcher.
+
+
 @node Message Customization, , Mail Methods, Mail Preparation
 @comment  node-name,  next,  previous,  up
 @subsection Message Customization
 @vindex patcher-default-subject-prefix
 @vindex :subject-prefix
 A prefix for the subject line of messages. It can be @code{nil} or a
-string. By default, "[PATCH]" is used. This part of subjects is never
+string. By default, ``[PATCH]'' is used. This part of subjects is never
 prompted for. A @samp{%n} occurring in this string will be replaced with
 the project name. Also, a space is inserted between the prefix and the
 remainder of the subject, when appropriate.
 on a subset of the project's files. Patcher understands this concept as
 working on a @dfn{subproject}.
 
-@findex patcher-mail-subproject
-Instead of calling @code{patcher-mail}, you rather call
-@code{patcher-mail-subproject}. This function behaves exactly like the
-former, except that it will also prompt you for the files affected by
-the patch. You can specify files as well as directories, use wildcards,
-just as you would construct a command line diff.
+As for working on whole projects, there are several alternatives to
+start working on a subproject:
+
+@defun patcher-mail-subproject
+@findex patcher-mail
+This function behaves exactly like @code{patcher-mail}, except that it
+also prompts you for the files affected by the patch. You can specify
+files as well as directories, use wildcards, just as you would construct
+a command line diff.
+@end defun
+
+@defun patcher-mail-adapt-subproject
+@findex patcher-mail-adapt
+Idem, with respect to @code{patcher-mail-adapt}.
+@end defun
+
+@findex patcher-gnus-summary-followup
+@findex patcher-gnus-summary-followup-with-original
+@findex patcher-gnus-summary-reply
+@findex patcher-gnus-summary-reply-with-original
+Finally, all the Gnus-specific reply functions (@pxref{Mail
+Preparation}) take an optional prefix argument that make them work on
+subprojects.
+
 
 Two important things are to be kept in mind when working on subprojects:
 @itemize @bullet
 removed.
 
 @item compressed-change-logs
-The "compressed" ChangeLog entries. Only the most important part of the
-ChangeLogs is preserved, so the entries appear in a more compact
+The ``compressed'' ChangeLog entries. Only the most important part of
+the ChangeLogs is preserved, so the entries appear in a more compact
 fashion.
 
 @item change-logs
 item, they appear in the order specified above. If anything appears
 before the raw ChangeLog entries, a separator string is used. This
 string is specified by the @code{:change-logs-separator} project option.
-By default the string looks like "--- ChangeLog entries follow: ---".
+By default the string looks like ``--- ChangeLog entries follow: ---''.
 
 
 @node Log Message Editing, , Log Message Elements, Log Message Handling
 @vindex :subject-committed-prefix
 The subject prefix is changed to that specified by the
 @code{:subject-committed-prefix} project option (a string), unless it is
-@code{nil}. By default, "[COMMIT]" is used.
+@code{nil}. By default, ``[COMMIT]'' is used.
 
 @item
 @vindex patcher-default-committed-notice
 @vindex :committed-notice
 A commit notice is added right at the beginning of the message's body.
 This notice is specified by the @code{:committed-notice} project option.
-It can be @code{nil} or a string. By default, it reads "NOTE: this patch
-has been committed.".
+It can be @code{nil} or a string. By default, it reads ``NOTE: this
+patch has been committed.''.
 @end itemize
 
 
 subset of a project's files (@pxref{Patch Restriction}). If you happen
 to work more than once on the same project subset, it will quickly
 become annoying to have to specify explicitly the same files over and
-over again. Patcher offers you a way to @emph{permanently} define
-subprojects.
+over again. Patcher offers you a way to permanently define subprojects.
 
 @menu
 * Defining Subprojects::  Storing subprojects definitions
 @item
 @findex patcher-mail
 @findex patcher-mail-subproject
-Permanent subprojects are designed to work with the function
-@code{patcher-mail}. You don't need to use
-@code{patcher-mail-subproject} any more.
+@findex patcher-mail-adapt
+@findex patcher-mail-adapt-subproject
+Since permanent subprojects are defined statically, they should be used
+with the normal Patcher functions like @code{patcher-mail}. You don't
+need to use the @code{*-subproject} versions any more.
 
 @item
 Because of that, projects and subprojects can't have names in common. If
 rather than a project of that name
 
 @item
-What happens if you use @code{patcher-mail-subproject} on a permanent
-subproject ? You punctually work on a subsubproject@dots{}
+So what happens if you persist in using a @code{*-subproject} function
+on a permanent subproject ? Well, you punctually work on a
+subsubproject@dots{}
 @end itemize