(require 'sendmail)
(require 'rnews)
(defvar news-reply-mode-map () "Mode map used by news-reply.")
(or news-reply-mode-map
(progn
(setq news-reply-mode-map (make-keymap))
(define-key news-reply-mode-map "\C-c\C-f\C-d" 'news-reply-distribution)
(define-key news-reply-mode-map "\C-c\C-f\C-k" 'news-reply-keywords)
(define-key news-reply-mode-map "\C-c\C-f\C-n" 'news-reply-newsgroups)
(define-key news-reply-mode-map "\C-c\C-f\C-f" 'news-reply-followup-to)
(define-key news-reply-mode-map "\C-c\C-f\C-s" 'mail-subject)
(define-key news-reply-mode-map "\C-c\C-f\C-a" 'news-reply-summary)
(define-key news-reply-mode-map "\C-c\C-t" 'mail-text)
(define-key news-reply-mode-map "\C-c\C-r" 'news-caesar-buffer-body)
(define-key news-reply-mode-map "\C-c\C-w" 'news-reply-signature)
(define-key news-reply-mode-map "\C-c\C-y" 'news-reply-yank-original)
(define-key news-reply-mode-map "\C-c\C-q" 'mail-fill-yanked-message)
(define-key news-reply-mode-map "\C-c\C-c" 'news-inews)
(define-key news-reply-mode-map "\C-c\C-s" 'news-inews)
(define-key news-reply-mode-map [menu-bar] (make-sparse-keymap))
(define-key news-reply-mode-map [menu-bar fields]
(cons "Fields" (make-sparse-keymap "Fields")))
(define-key news-reply-mode-map [menu-bar fields news-reply-distribution]
'("Distribution" . news-reply-distribution))
(define-key news-reply-mode-map [menu-bar fields news-reply-keywords]
'("Keywords" . news-reply-keywords))
(define-key news-reply-mode-map [menu-bar fields news-reply-newsgroups]
'("Newsgroups" . news-reply-newsgroups))
(define-key news-reply-mode-map [menu-bar fields news-reply-followup-to]
'("Followup-to" . news-reply-followup-to))
(define-key news-reply-mode-map [menu-bar fields mail-subject]
'("Subject" . mail-subject))
(define-key news-reply-mode-map [menu-bar fields news-reply-summary]
'("Summary" . news-reply-summary))
(define-key news-reply-mode-map [menu-bar fields mail-text]
'("Text" . mail-text))
(define-key news-reply-mode-map [menu-bar news]
(cons "News" (make-sparse-keymap "News")))
(define-key news-reply-mode-map [menu-bar news news-caesar-buffer-body]
'("Rot13" . news-caesar-buffer-body))
(define-key news-reply-mode-map [menu-bar news news-reply-yank-original]
'("Yank Original" . news-reply-yank-original))
(define-key news-reply-mode-map [menu-bar news mail-fill-yanked-message]
'("Fill Yanked Messages" . mail-fill-yanked-message))
(define-key news-reply-mode-map [menu-bar news news-inews]
'("Send" . news-inews))))
(defun news-reply-mode ()
"Major mode for editing news to be posted on USENET.
First-time posters are asked to please read the articles in newsgroup:
news.announce.newusers .
Like Text Mode but with these additional commands:
C-c C-s news-inews (post the message) C-c C-c news-inews
C-c C-f move to a header field (and create it if there isn't):
C-c C-f C-n move to Newsgroups: C-c C-f C-s move to Subj:
C-c C-f C-f move to Followup-To: C-c C-f C-k move to Keywords:
C-c C-f C-d move to Distribution: C-c C-f C-a move to Summary:
C-c C-y news-reply-yank-original (insert current message, in NEWS).
C-c C-q mail-fill-yanked-message (fill what was yanked).
C-c C-r caesar rotate all letters by 13 places in the article's body (rot13)."
(interactive)
(kill-all-local-variables)
(make-local-variable 'mail-reply-buffer)
(setq mail-reply-buffer nil)
(set-syntax-table text-mode-syntax-table)
(use-local-map news-reply-mode-map)
(setq local-abbrev-table text-mode-abbrev-table)
(setq major-mode 'news-reply-mode)
(setq mode-name "News Reply")
(make-local-variable 'paragraph-separate)
(make-local-variable 'paragraph-start)
(run-hooks 'text-mode-hook 'news-reply-mode-hook))
(defvar news-reply-yank-from ""
"Save `From:' field for `news-reply-yank-original'.")
(defvar news-reply-yank-message-id ""
"Save `Message-Id:' field for `news-reply-yank-original'.")
(defun news-reply-yank-original (arg)
"Insert the message being replied to, if any (in Mail mode).
Puts point before the text and mark after.
Indents each nonblank line ARG spaces (default 3).
Just \\[universal-argument] as argument means don't indent
and don't delete any header fields."
(interactive "P")
(mail-yank-original arg)
(exchange-point-and-mark)
(run-hooks 'news-reply-header-hook))
(defvar news-reply-header-hook
(lambda ()
(insert "In article " news-reply-yank-message-id
" " news-reply-yank-from " writes:\n\n"))
"Hook for inserting a header at the top of a yanked message.")
(defun news-reply-newsgroups ()
"Move point to end of `Newsgroups:' field.
RFC 850 constrains the `Newsgroups:' field to be a comma-separated list
of valid newsgroup names at your site. For example,
Newsgroups: news.misc,comp.misc,rec.misc"
(interactive)
(expand-abbrev)
(goto-char (point-min))
(mail-position-on-field "Newsgroups"))
(defun news-reply-followup-to ()
"Move point to end of `Followup-To:' field. Create the field if none.
One usually requests followups to only one newsgroup.
RFC 850 constrains the `Followup-To:' field to be a comma-separated list
of valid newsgroups names at your site, and it must be a subset of the
`Newsgroups:' field. For example:
Newsgroups: news.misc,comp.misc,rec.misc,misc.misc,soc.misc
Followup-To: news.misc,comp.misc,rec.misc"
(interactive)
(expand-abbrev)
(or (mail-position-on-field "Followup-To" t)
(progn (mail-position-on-field "newsgroups")
(insert "\nFollowup-To: ")))
)
(defun news-reply-distribution ()
"Move point to end of `Distribution:' optional field.
Create the field if none. Without this field the posting goes to all of
USENET. The field is used to restrict the posting to parts of USENET."
(interactive)
(expand-abbrev)
(mail-position-on-field "Distribution")
)
(defun news-reply-keywords ()
"Move point to end of `Keywords:' optional field. Create the field if none.
Used as an aid to the news reader, it can contain a few, well selected keywords
identifying the message."
(interactive)
(expand-abbrev)
(mail-position-on-field "Keywords"))
(defun news-reply-summary ()
"Move point to end of `Summary:' optional field. Create the field if none.
Used as an aid to the news reader, it can contain a succinct
summary (abstract) of the message."
(interactive)
(expand-abbrev)
(mail-position-on-field "Summary"))
(defun news-reply-signature ()
"The inews program appends `~/.signature' automatically."
(interactive)
(message "Posting news will append your signature automatically."))
(defun news-setup (to subject in-reply-to newsgroups replybuffer)
"Set up the news reply or posting buffer with the proper headers and mode."
(setq mail-reply-buffer replybuffer)
(let ((mail-setup-hook nil)
(mail-signature))
(if (null to)
(let ((mail-self-blind nil)
(mail-archive-file-name nil))
(mail-setup to subject in-reply-to nil replybuffer nil)
(beginning-of-line)
(delete-region (point) (progn (forward-line 1) (point)))
(goto-char (point-max)))
(mail-setup to subject in-reply-to nil replybuffer nil))
(goto-char (point-max))
(if (let ((case-fold-search t))
(re-search-backward "^Subject:" (point-min) t))
(progn (beginning-of-line)
(insert "Newsgroups: " (or newsgroups "") "\n")
(if (not newsgroups)
(backward-char 1)
(goto-char (point-max)))))
(let (actual-header-separator)
(rfc822-goto-eoh)
(setq actual-header-separator (buffer-substring
(point)
(save-excursion (end-of-line) (point))))
(setq paragraph-start
(concat "^" actual-header-separator "$\\|" paragraph-start))
(setq paragraph-separate
(concat "^" actual-header-separator "$\\|" paragraph-separate)))
(run-hooks 'news-setup-hook)))
(defun news-inews ()
"Send a news message using inews."
(interactive)
(let* (newsgroups subject
(case-fold-search nil))
(save-excursion
(save-restriction
(narrow-to-region (point-min) (mail-header-end))
(setq newsgroups (mail-fetch-field "newsgroups")
subject (mail-fetch-field "subject")))
(widen)
(goto-char (point-min))
(run-hooks 'news-inews-hook)
(mail-sendmail-undelimit-header)
(goto-char (point-max))
(or (= (preceding-char) ?\n)
(insert ?\n))
(message "Posting to USENET...")
(unwind-protect
(if (not (eq 0
(call-process-region (point-min) (point-max)
news-inews-program nil 0 nil
"-h"))) (error "Posting to USENET failed")
(message "Posting to USENET... done"))
(mail-sendmail-delimit-header)
(set-buffer-modified-p nil)))
(bury-buffer)))
(defun news-mail-reply ()
"Mail a reply to the author of the current article.
While composing the reply, use \\[news-reply-yank-original] to yank the
original message into it."
(interactive)
(let (from cc subject date to reply-to message-id
(buffer (current-buffer)))
(save-restriction
(narrow-to-region (point-min) (progn (goto-line (point-min))
(search-forward "\n\n")
(- (point) 1)))
(setq from (mail-fetch-field "from")
subject (mail-fetch-field "subject")
reply-to (mail-fetch-field "reply-to")
date (mail-fetch-field "date")
message-id (mail-fetch-field "message-id")))
(setq to from)
(pop-to-buffer "*mail*")
(mail nil
(if reply-to reply-to to)
subject
(let ((stop-pos (string-match " *at \\| *@ \\| *(\\| *<" from)))
(concat (if stop-pos (substring from 0 stop-pos) from)
"'s message "
(if message-id
(concat message-id " of ")
"of ")
date))
nil
buffer)))
(defun news-reply ()
"Compose and post a reply (aka a followup) to the current article on USENET.
While composing the followup, use \\[news-reply-yank-original] to yank the
original message into it."
(interactive)
(if (y-or-n-p "Are you sure you want to followup to all of USENET? ")
(let (from cc subject date to followup-to newsgroups message-of
references distribution message-id
(buffer (current-buffer)))
(save-restriction
(and (not (= 0 (buffer-size))) (equal major-mode 'news-mode) (progn
(news-show-all-headers) (narrow-to-region (point-min) (progn (goto-char (point-min))
(search-forward "\n\n")
(- (point) 1)))))
(setq from (mail-fetch-field "from")
news-reply-yank-from from
subject (mail-fetch-field "subject")
date (mail-fetch-field "date")
followup-to (mail-fetch-field "followup-to")
newsgroups (or followup-to
(mail-fetch-field "newsgroups"))
references (mail-fetch-field "references")
distribution (mail-fetch-field "distribution")
message-id (mail-fetch-field "message-id")
news-reply-yank-message-id message-id)
(pop-to-buffer "*post-news*")
(news-reply-mode)
(if (and (buffer-modified-p)
(not
(y-or-n-p "Unsent article being composed; erase it? ")))
()
(progn
(erase-buffer)
(and subject
(progn (if (string-match "\\`Re: " subject)
(while (string-match "\\`Re: " subject)
(setq subject (substring subject 4))))
(setq subject (concat "Re: " subject))))
(and from
(progn
(let ((stop-pos
(string-match " *at \\| *@ \\| *(\\| *<" from)))
(setq message-of
(concat
(if stop-pos (substring from 0 stop-pos) from)
"'s message "
(if message-id
(concat message-id " of ")
"of ")
date)))))
(news-setup
nil
subject
message-of
newsgroups
buffer)
(if followup-to
(progn (news-reply-followup-to)
(insert followup-to)))
(if distribution
(progn
(mail-position-on-field "Distribution")
(insert distribution)))
(mail-position-on-field "References")
(if references
(insert references))
(if (and references message-id)
(insert " "))
(if message-id
(insert message-id))
(goto-char (point-max))))))
(message "")))
(defun news-post-news (&optional noquery)
"Begin editing a new USENET news article to be posted.
Type \\[describe-mode] once editing the article to get a list of commands.
If NOQUERY is non-nil, we do not query before doing the work."
(interactive)
(if (or noquery
(y-or-n-p "Are you sure you want to post to all of USENET? "))
(let ((buffer (current-buffer)))
(save-restriction
(and (not (= 0 (buffer-size))) (equal major-mode 'news-mode) (progn
(news-show-all-headers) (narrow-to-region (point-min) (progn (goto-char (point-min))
(search-forward "\n\n")
(- (point) 1)))))
(setq news-reply-yank-from (mail-fetch-field "from")
news-reply-yank-message-id (mail-fetch-field "message-id")))
(pop-to-buffer "*post-news*")
(news-reply-mode)
(if (and (buffer-modified-p)
(not (y-or-n-p "Unsent article being composed; erase it? ")))
() (progn (erase-buffer)
(news-setup () () () () buffer))))
(message "")))
(defun news-mail-other-window ()
"Send mail in another window.
While composing the message, use \\[news-reply-yank-original] to yank the
original message into it."
(interactive)
(mail-other-window nil nil nil nil nil (current-buffer)))
(provide 'rnewspost)