|
|
1.1 ! root 1: ;;; USENET news reader for gnu emacs ! 2: ;; Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc. ! 3: ! 4: ;; This file is part of GNU Emacs. ! 5: ! 6: ;; GNU Emacs is distributed in the hope that it will be useful, ! 7: ;; but WITHOUT ANY WARRANTY. No author or distributor ! 8: ;; accepts responsibility to anyone for the consequences of using it ! 9: ;; or for whether it serves any particular purpose or works at all, ! 10: ;; unless he says so in writing. Refer to the GNU Emacs General Public ! 11: ;; License for full details. ! 12: ! 13: ;; Everyone is granted permission to copy, modify and redistribute ! 14: ;; GNU Emacs, but only under the conditions described in the ! 15: ;; GNU Emacs General Public License. A copy of this license is ! 16: ;; supposed to have been given to you along with GNU Emacs so you ! 17: ;; can know your rights and responsibilities. It should be in a ! 18: ;; file named COPYING. Among other things, the copyright notice ! 19: ;; and this notice must be preserved on all copies. ! 20: ! 21: ;; Created Sun Mar 10,1985 at 21:35:01 ads and [email protected] ! 22: ;; Should do the point pdl stuff sometime ! 23: ;; finito except pdl.... Sat Mar 16,1985 at 06:43:44 ! 24: ;; lets keep the summary stuff out until we get it working .. ! 25: ;; [email protected] Wed Apr 10,1985 at 16:32:06 ! 26: ;; hack slash maim. [email protected] Thu 18 Apr, 1985 06:11:14 ! 27: ;; modified to correct reentrance bug, to not bother with groups that ! 28: ;; received no new traffic since last read completely, to find out ! 29: ;; what traffic a group has available much more quickly when ! 30: ;; possible, to do some completing reads for group names - should ! 31: ;; be much faster... ! 32: ;; [email protected], Thu Mar 13 09:03:28 1986 ! 33: ;; made news-{next,previous}-group skip groups with no new messages; and ! 34: ;; added checking for unsubscribed groups to news-add-news-group ! 35: ;; [email protected] Jul 18 1986 ! 36: ;; bound rmail-output to C-o; and changed header-field commands binding to ! 37: ;; agree with the new C-c C-f usage in sendmail ! 38: ;; tower@prep Sep 3 1986 ! 39: ;; added news-rotate-buffer-body ! 40: ;; tower@prep Oct 17 1986 ! 41: ;; made messages more user friendly, cleanuped news-inews ! 42: ;; move posting and mail code to new file rnewpost.el ! 43: ;; tower@prep Oct 29 1986 ! 44: ;; added caesar-region, rename news-caesar-buffer-body, hacked accordingly ! 45: ;; tower@prep Nov 21 1986 ! 46: ;; added (provide 'rnews) tower@prep 22 Apr 87 ! 47: (provide 'rnews) ! 48: (require 'mail-utils) ! 49: ! 50: (autoload 'rmail-output "rmailout" ! 51: "Append this message to Unix mail file named FILE-NAME." ! 52: t) ! 53: ! 54: (autoload 'news-reply "rnewspost" ! 55: "Compose and post a reply to the current article on USENET. ! 56: While composing the reply, use \\[mail-yank-original] to yank the original ! 57: message into it." ! 58: t) ! 59: ! 60: (autoload 'news-mail-other-window "rnewspost" ! 61: "Send mail in another window. ! 62: While composing the message, use \\[mail-yank-original] to yank the ! 63: original message into it." ! 64: t) ! 65: ! 66: (autoload 'news-post-news "rnewspost" ! 67: "Begin editing a new USENET news article to be posted." ! 68: t) ! 69: ! 70: (autoload 'news-mail-reply "rnewspost" ! 71: "Mail a reply to the author of the current article. ! 72: While composing the reply, use \\[mail-yank-original] to yank the original ! 73: message into it." ! 74: t) ! 75: ! 76: (defvar rmail-last-file (expand-file-name "~/mbox.news")) ! 77: ! 78: ;Now in paths.el. ! 79: ;(defvar news-path "/usr/spool/news/" ! 80: ; "The root directory below which all news files are stored.") ! 81: ! 82: (defvar news-startup-file "$HOME/.newsrc" "Contains ~/.newsrc") ! 83: (defvar news-certification-file "$HOME/.news-dates" "Contains ~/.news-dates") ! 84: ! 85: ;; random headers that we decide to ignore. ! 86: (defvar news-ignored-headers ! 87: "^Path:\\|^Posting-Version:\\|^Article-I.D.:\\|^Expires:\\|^Date-Received:\\|^References:\\|^Control:\\|^Xref:\\|^Lines:\\|^Posted:\\|^Relay-Version:\\|^Message-ID:\\|^Nf-ID:\\|^Nf-From:\\|^Approved:\\|^Sender:" ! 88: "All random fields within the header of a message.") ! 89: ! 90: (defvar news-mode-map nil) ! 91: (defvar news-read-first-time-p t) ! 92: ;; Contains the (dotified) news groups of which you are a member. ! 93: (defvar news-user-group-list nil) ! 94: ! 95: (defvar news-current-news-group nil) ! 96: (defvar news-current-group-begin nil) ! 97: (defvar news-current-group-end nil) ! 98: (defvar news-current-certifications nil ! 99: "An assoc list of a group name and the time at which it is ! 100: known that the group had no new traffic") ! 101: (defvar news-current-certifiable nil ! 102: "The time when the directory we are now working on was written") ! 103: ! 104: (defvar news-message-filter nil ! 105: "User specifiable filter function that will be called during ! 106: formatting of the news file") ! 107: ! 108: ;(defvar news-mode-group-string "Starting-Up" ! 109: ; "Mode line group name info is held in this variable") ! 110: (defvar news-list-of-files nil ! 111: "Global variable in which we store the list of files ! 112: associated with the current newsgroup") ! 113: (defvar news-list-of-files-possibly-bogus nil ! 114: "variable indicating we only are guessing at which files are available. ! 115: Not currently used.") ! 116: ! 117: ;; association list in which we store lists of the form ! 118: ;; (pointified-group-name (first last old-last)) ! 119: (defvar news-group-article-assoc nil) ! 120: ! 121: (defvar news-current-message-number 0 "Displayed Article Number") ! 122: (defvar news-total-current-group 0 "Total no of messages in group") ! 123: ! 124: (defvar news-unsubscribe-groups ()) ! 125: (defvar news-point-pdl () "List of visited news messages.") ! 126: (defvar news-no-jumps-p t) ! 127: (defvar news-buffer () "Buffer into which news files are read.") ! 128: ! 129: (defmacro news-push (item ref) ! 130: (list 'setq ref (list 'cons item ref))) ! 131: ! 132: (defmacro news-cadr (x) (list 'car (list 'cdr x))) ! 133: (defmacro news-cdar (x) (list 'cdr (list 'car x))) ! 134: (defmacro news-caddr (x) (list 'car (list 'cdr (list 'cdr x)))) ! 135: (defmacro news-cadar (x) (list 'car (list 'cdr (list 'car x)))) ! 136: (defmacro news-caadr (x) (list 'car (list 'car (list 'cdr x)))) ! 137: (defmacro news-cdadr (x) (list 'cdr (list 'car (list 'cdr x)))) ! 138: ! 139: (defmacro news-wins (pfx index) ! 140: (` (file-exists-p (concat (, pfx) "/" (int-to-string (, index)))))) ! 141: ! 142: (defvar news-max-plausible-gap 2 ! 143: "* In an rnews directory, the maximum possible gap size. ! 144: A gap is a sequence of missing messages between two messages that exist. ! 145: An empty file does not contribute to a gap -- it ends one.") ! 146: ! 147: (defun news-find-first-and-last (prefix base) ! 148: (and (news-wins prefix base) ! 149: (cons (news-find-first-or-last prefix base -1) ! 150: (news-find-first-or-last prefix base 1)))) ! 151: ! 152: (defmacro news-/ (a1 a2) ! 153: ;; a form of / that guarantees that (/ -1 2) = 0 ! 154: (if (zerop (/ -1 2)) ! 155: (` (/ (, a1) (, a2))) ! 156: (` (if (< (, a1) 0) ! 157: (- (/ (- (, a1)) (, a2))) ! 158: (/ (, a1) (, a2)))))) ! 159: ! 160: (defun news-find-first-or-last (pfx base dirn) ! 161: ;; first use powers of two to find a plausible ceiling ! 162: (let ((original-dir dirn)) ! 163: (while (news-wins pfx (+ base dirn)) ! 164: (setq dirn (* dirn 2))) ! 165: (setq dirn (news-/ dirn 2)) ! 166: ;; Then use a binary search to find the high water mark ! 167: (let ((offset (news-/ dirn 2))) ! 168: (while (/= offset 0) ! 169: (if (news-wins pfx (+ base dirn offset)) ! 170: (setq dirn (+ dirn offset))) ! 171: (setq offset (news-/ offset 2)))) ! 172: ;; If this high-water mark is bogus, recurse. ! 173: (let ((offset (* news-max-plausible-gap original-dir))) ! 174: (while (and (/= offset 0) (not (news-wins pfx (+ base dirn offset)))) ! 175: (setq offset (- offset original-dir))) ! 176: (if (= offset 0) ! 177: (+ base dirn) ! 178: (news-find-first-or-last pfx (+ base dirn offset) original-dir))))) ! 179: ! 180: (defun rnews () ! 181: "Read USENET news for groups for which you are a member and add or ! 182: delete groups. ! 183: You can reply to articles posted and send articles to any group. ! 184: ! 185: Type \\[describe-mode] once reading news to get a list of rnews commands." ! 186: (interactive) ! 187: (let ((last-buffer (buffer-name))) ! 188: (make-local-variable 'rmail-last-file) ! 189: (switch-to-buffer (setq news-buffer (get-buffer-create "*news*"))) ! 190: (news-mode) ! 191: (setq news-buffer-save last-buffer) ! 192: (setq buffer-read-only nil) ! 193: (erase-buffer) ! 194: (setq buffer-read-only t) ! 195: (set-buffer-modified-p t) ! 196: (sit-for 0) ! 197: (message "Getting new USENET news...") ! 198: (news-set-mode-line) ! 199: (news-get-certifications) ! 200: (news-get-new-news))) ! 201: ! 202: (defun news-group-certification (group) ! 203: (cdr-safe (assoc group news-current-certifications))) ! 204: ! 205: ! 206: (defun news-set-current-certifiable () ! 207: ;; Record the date that corresponds to the directory you are about to check ! 208: (let ((file (concat news-path ! 209: (string-subst-char ?/ ?. news-current-news-group)))) ! 210: (setq news-current-certifiable ! 211: (nth 5 (file-attributes ! 212: (or (file-symlink-p file) file)))))) ! 213: ! 214: (defun news-get-certifications () ! 215: ;; Read the certified-read file from last session ! 216: (save-excursion ! 217: (save-window-excursion ! 218: (setq news-current-certifications ! 219: (car-safe ! 220: (condition-case var ! 221: (let* ! 222: ((file (substitute-in-file-name news-certification-file)) ! 223: (buf (find-file-noselect file))) ! 224: (and (file-exists-p file) ! 225: (progn ! 226: (switch-to-buffer buf 'norecord) ! 227: (unwind-protect ! 228: (read-from-string (buffer-string)) ! 229: (kill-buffer buf))))) ! 230: (error nil))))))) ! 231: ! 232: (defun news-write-certifications () ! 233: ;; Write a certification file. ! 234: ;; This is an assoc list of group names with doubletons that represent ! 235: ;; mod times of the directory when group is read completely. ! 236: (save-excursion ! 237: (save-window-excursion ! 238: (with-output-to-temp-buffer ! 239: "*CeRtIfIcAtIoNs*" ! 240: (print news-current-certifications)) ! 241: (let ((buf (get-buffer "*CeRtIfIcAtIoNs*"))) ! 242: (switch-to-buffer buf) ! 243: (write-file (substitute-in-file-name news-certification-file)) ! 244: (kill-buffer buf))))) ! 245: ! 246: (defun news-set-current-group-certification () ! 247: (let ((cgc (assoc news-current-news-group news-current-certifications))) ! 248: (if cgc (setcdr cgc news-current-certifiable) ! 249: (news-push (cons news-current-news-group news-current-certifiable) ! 250: news-current-certifications)))) ! 251: ! 252: (defun news-set-minor-modes () ! 253: "Creates a minor mode list that has group name, total articles, ! 254: and attribute for current article." ! 255: (setq news-minor-modes (list (cons 'foo ! 256: (concat news-current-message-number ! 257: "/" ! 258: news-total-current-group ! 259: (news-get-attribute-string))))) ! 260: ;; Detect Emacs versions 18.16 and up, which display ! 261: ;; directly from news-minor-modes by using a list for mode-name. ! 262: (or (boundp 'minor-mode-alist) ! 263: (setq minor-modes news-minor-modes))) ! 264: ! 265: (defun news-set-message-counters () ! 266: "Scan through current news-groups filelist to figure out how many messages ! 267: are there. Set counters for use with minor mode display." ! 268: (if (null news-list-of-files) ! 269: (setq news-current-message-number 0))) ! 270: ! 271: (if news-mode-map ! 272: nil ! 273: (setq news-mode-map (make-keymap)) ! 274: (suppress-keymap news-mode-map) ! 275: (define-key news-mode-map "." 'beginning-of-buffer) ! 276: (define-key news-mode-map " " 'scroll-up) ! 277: (define-key news-mode-map "\177" 'scroll-down) ! 278: (define-key news-mode-map "n" 'news-next-message) ! 279: (define-key news-mode-map "c" 'news-make-link-to-message) ! 280: (define-key news-mode-map "p" 'news-previous-message) ! 281: (define-key news-mode-map "j" 'news-goto-message) ! 282: (define-key news-mode-map "q" 'news-exit) ! 283: (define-key news-mode-map "e" 'news-exit) ! 284: (define-key news-mode-map "\ej" 'news-goto-news-group) ! 285: (define-key news-mode-map "\en" 'news-next-group) ! 286: (define-key news-mode-map "\ep" 'news-previous-group) ! 287: (define-key news-mode-map "l" 'news-list-news-groups) ! 288: (define-key news-mode-map "?" 'describe-mode) ! 289: (define-key news-mode-map "g" 'news-get-new-news) ! 290: (define-key news-mode-map "f" 'news-reply) ! 291: (define-key news-mode-map "m" 'news-mail-other-window) ! 292: (define-key news-mode-map "a" 'news-post-news) ! 293: (define-key news-mode-map "r" 'news-mail-reply) ! 294: (define-key news-mode-map "o" 'news-save-item-in-file) ! 295: (define-key news-mode-map "\C-o" 'rmail-output) ! 296: (define-key news-mode-map "t" 'news-show-all-headers) ! 297: (define-key news-mode-map "x" 'news-force-update) ! 298: (define-key news-mode-map "A" 'news-add-news-group) ! 299: (define-key news-mode-map "u" 'news-unsubscribe-current-group) ! 300: (define-key news-mode-map "U" 'news-unsubscribe-group) ! 301: (define-key news-mode-map "\C-c\C-r" 'news-caesar-buffer-body)) ! 302: ! 303: (defun news-mode () ! 304: "News Mode is used by M-x rnews for reading USENET Newsgroups articles. ! 305: New readers can find additional help in newsgroup: news.announce.newusers . ! 306: All normal editing commands are turned off. ! 307: Instead, these commands are available: ! 308: ! 309: . move point to front of this news article (same as Meta-<). ! 310: Space scroll to next screen of this news article. ! 311: Delete scroll down previous page of this news article. ! 312: n move to next news article, possibly next group. ! 313: p move to previous news article, possibly previous group. ! 314: j jump to news article specified by numeric position. ! 315: M-j jump to news group. ! 316: M-n goto next news group. ! 317: M-p goto previous news group. ! 318: l list all the news groups with current status. ! 319: ? print this help message. ! 320: C-c C-r caesar rotate all letters by 13 places in the article's body (rot13). ! 321: g get new USENET news. ! 322: f post a reply article to USENET. ! 323: a post an original news article. ! 324: A add a newsgroup. ! 325: o save the current article in the named file (append if file exists). ! 326: C-o output this message to a Unix-format mail file (append it). ! 327: c \"copy\" (actually link) current or prefix-arg msg to file. ! 328: warning: target directory and message file must be on same device ! 329: (UNIX magic) ! 330: t show all the headers this news article originally had. ! 331: q quit reading news after updating .newsrc file. ! 332: e exit updating .newsrc file. ! 333: m mail a news article. Same as C-x 4 m. ! 334: x update last message seen to be the current message. ! 335: r mail a reply to this news article. Like m but initializes some fields. ! 336: u unsubscribe from current newsgroup. ! 337: U unsubscribe from specified newsgroup." ! 338: (interactive) ! 339: (kill-all-local-variables) ! 340: (make-local-variable 'news-read-first-time-p) ! 341: (setq news-read-first-time-p t) ! 342: (make-local-variable 'news-current-news-group) ! 343: ; (setq news-current-news-group "??") ! 344: (make-local-variable 'news-current-group-begin) ! 345: (setq news-current-group-begin 0) ! 346: (make-local-variable 'news-current-message-number) ! 347: (setq news-current-message-number 0) ! 348: (make-local-variable 'news-total-current-group) ! 349: (make-local-variable 'news-buffer-save) ! 350: (make-local-variable 'version-control) ! 351: (setq version-control 'never) ! 352: (make-local-variable 'news-point-pdl) ! 353: ; This breaks it. I don't have time to figure out why. -- RMS ! 354: ; (make-local-variable 'news-group-article-assoc) ! 355: (setq major-mode 'news-mode) ! 356: (if (boundp 'minor-mode-alist) ! 357: ;; Emacs versions 18.16 and up. ! 358: (setq mode-name '("NEWS" news-minor-modes)) ! 359: ;; Earlier versions display minor-modes via a special mechanism. ! 360: (setq mode-name "NEWS")) ! 361: (news-set-mode-line) ! 362: (set-syntax-table text-mode-syntax-table) ! 363: (use-local-map news-mode-map) ! 364: (setq local-abbrev-table text-mode-abbrev-table) ! 365: (run-hooks 'news-mode-hook)) ! 366: ! 367: (defun string-subst-char (new old string) ! 368: (let (index) ! 369: (setq old (regexp-quote (char-to-string old)) ! 370: string (substring string 0)) ! 371: (while (setq index (string-match old string)) ! 372: (aset string index new))) ! 373: string) ! 374: ! 375: ;; update read message number ! 376: (defmacro news-update-message-read (ngroup nno) ! 377: (list 'setcar ! 378: (list 'news-cdadr ! 379: (list 'assoc ngroup 'news-group-article-assoc)) ! 380: nno)) ! 381: ! 382: (defun news-parse-range (number-string) ! 383: "Parse string representing range of numbers of he form <a>-<b> ! 384: to a list (a . b)" ! 385: (let ((n (string-match "-" number-string))) ! 386: (if n ! 387: (cons (string-to-int (substring number-string 0 n)) ! 388: (string-to-int (substring number-string (1+ n)))) ! 389: (setq n (string-to-int number-string)) ! 390: (cons n n)))) ! 391: ! 392: ;(defun is-in (elt lis) ! 393: ; (catch 'foo ! 394: ; (while lis ! 395: ; (if (equal (car lis) elt) ! 396: ; (throw 'foo t) ! 397: ; (setq lis (cdr lis)))))) ! 398: ! 399: (defun news-get-new-news () ! 400: "Get new USENET news, if there is any for the current user." ! 401: (interactive) ! 402: (if (not (null news-user-group-list)) ! 403: (news-update-newsrc-file)) ! 404: (setq news-group-article-assoc ()) ! 405: (setq news-user-group-list ()) ! 406: (message "Looking up %s file..." news-startup-file) ! 407: (let ((file (substitute-in-file-name news-startup-file)) ! 408: (temp-user-groups ())) ! 409: (save-excursion ! 410: (let ((newsrcbuf (find-file-noselect file)) ! 411: start end endofline tem) ! 412: (set-buffer newsrcbuf) ! 413: (goto-char 0) ! 414: (while (search-forward ": " nil t) ! 415: (setq end (point)) ! 416: (beginning-of-line) ! 417: (setq start (point)) ! 418: (end-of-line) ! 419: (setq endofline (point)) ! 420: (setq tem (buffer-substring start (- end 2))) ! 421: (let ((range (news-parse-range ! 422: (buffer-substring end endofline)))) ! 423: (if (assoc tem news-group-article-assoc) ! 424: (message "You are subscribed twice to %s; I ignore second" ! 425: tem) ! 426: (setq temp-user-groups (cons tem temp-user-groups) ! 427: news-group-article-assoc ! 428: (cons (list tem (list (car range) ! 429: (cdr range) ! 430: (cdr range))) ! 431: news-group-article-assoc))))) ! 432: (kill-buffer newsrcbuf))) ! 433: (setq temp-user-groups (nreverse temp-user-groups)) ! 434: (message "Prefrobnicating...") ! 435: (switch-to-buffer news-buffer) ! 436: (setq news-user-group-list temp-user-groups) ! 437: (while (and temp-user-groups ! 438: (not (news-read-files-into-buffer ! 439: (car temp-user-groups) nil))) ! 440: (setq temp-user-groups (cdr temp-user-groups))) ! 441: (if (null temp-user-groups) ! 442: (message "No news is good news.") ! 443: (message "")))) ! 444: ! 445: (defun news-list-news-groups () ! 446: "Display all the news groups to which you belong." ! 447: (interactive) ! 448: (with-output-to-temp-buffer "*Newsgroups*" ! 449: (save-excursion ! 450: (set-buffer standard-output) ! 451: (insert ! 452: "News Group Msg No. News Group Msg No.\n") ! 453: (insert ! 454: "------------------------- -------------------------\n") ! 455: (let ((temp news-user-group-list) ! 456: (flag nil)) ! 457: (while temp ! 458: (let ((item (assoc (car temp) news-group-article-assoc))) ! 459: (insert (car item)) ! 460: (indent-to (if flag 52 20)) ! 461: (insert (int-to-string (news-cadr (news-cadr item)))) ! 462: (if flag ! 463: (insert "\n") ! 464: (indent-to 33)) ! 465: (setq temp (cdr temp) flag (not flag)))))))) ! 466: ! 467: ;; Mode line hack ! 468: (defun news-set-mode-line () ! 469: "Set mode line string to something useful." ! 470: (setq mode-line-process ! 471: (concat " " ! 472: (if (integerp news-current-message-number) ! 473: (int-to-string news-current-message-number) ! 474: "??") ! 475: "/" ! 476: (if (integerp news-current-group-end) ! 477: (int-to-string news-current-group-end) ! 478: news-current-group-end))) ! 479: (setq mode-line-buffer-identification ! 480: (concat "NEWS: " ! 481: news-current-news-group ! 482: ;; Enough spaces to pad group name to 17 positions. ! 483: (substring " " ! 484: 0 (max 0 (- 17 (length news-current-news-group)))))) ! 485: (set-buffer-modified-p t) ! 486: (sit-for 0)) ! 487: ! 488: (defun news-goto-news-group (gp) ! 489: "Takes a string and goes to that news group." ! 490: (interactive (list (completing-read "NewsGroup: " ! 491: news-group-article-assoc))) ! 492: (message "Jumping to news group %s..." gp) ! 493: (news-select-news-group gp) ! 494: (message "Jumping to news group %s... done." gp)) ! 495: ! 496: (defun news-select-news-group (gp) ! 497: (let ((grp (assoc gp news-group-article-assoc))) ! 498: (if (null grp) ! 499: (error "Group not subscribed to in file %s." news-startup-file) ! 500: (progn ! 501: (news-update-message-read news-current-news-group ! 502: (news-cdar news-point-pdl)) ! 503: (news-read-files-into-buffer (car grp) nil) ! 504: (news-set-mode-line))))) ! 505: ! 506: (defun news-goto-message (arg) ! 507: "Goes to the article ARG in current newsgroup." ! 508: (interactive "p") ! 509: (if (null current-prefix-arg) ! 510: (setq arg (read-no-blanks-input "Go to article: " ""))) ! 511: (news-select-message arg)) ! 512: ! 513: (defun news-select-message (arg) ! 514: (if (stringp arg) (setq arg (string-to-int arg))) ! 515: (let ((file (concat news-path ! 516: (string-subst-char ?/ ?. news-current-news-group) ! 517: "/" arg))) ! 518: (if (file-exists-p file) ! 519: (let ((buffer-read-only ())) ! 520: (if (= arg ! 521: (or (news-cadr (memq (news-cdar news-point-pdl) news-list-of-files)) ! 522: 0)) ! 523: (setcdr (car news-point-pdl) arg)) ! 524: (setq news-current-message-number arg) ! 525: (news-read-in-file file) ! 526: (news-set-mode-line)) ! 527: (error "Article %d nonexistent" arg)))) ! 528: ! 529: (defun news-force-update () ! 530: "updates the position of last article read in the current news group" ! 531: (interactive) ! 532: (setcdr (car news-point-pdl) news-current-message-number) ! 533: (message "Updated to %d" news-current-message-number)) ! 534: ! 535: (defun news-next-message (arg) ! 536: "Move ARG messages forward within one newsgroup. ! 537: Negative ARG moves backward. ! 538: If ARG is 1 or -1, moves to next or previous newsgroup if at end." ! 539: (interactive "p") ! 540: (let ((no (+ arg news-current-message-number))) ! 541: (if (or (< no news-current-group-begin) ! 542: (> no news-current-group-end)) ! 543: (cond ((= arg 1) ! 544: (news-set-current-group-certification) ! 545: (news-next-group)) ! 546: ((= arg -1) ! 547: (news-previous-group)) ! 548: (t (error "Article out of range"))) ! 549: (let ((plist (news-get-motion-lists ! 550: news-current-message-number ! 551: news-list-of-files))) ! 552: (if (< arg 0) ! 553: (news-select-message (nth (1- (- arg)) (car (cdr plist)))) ! 554: (news-select-message (nth (1- arg) (car plist)))))))) ! 555: ! 556: (defun news-previous-message (arg) ! 557: "Move ARG messages backward in current newsgroup. ! 558: With no arg or arg of 1, move one message ! 559: and move to previous newsgroup if at beginning. ! 560: A negative ARG means move forward." ! 561: (interactive "p") ! 562: (news-next-message (- arg))) ! 563: ! 564: (defun news-move-to-group (arg) ! 565: "Given arg move forward or backward to a new newsgroup." ! 566: (let ((cg news-current-news-group)) ! 567: (let ((plist (news-get-motion-lists cg news-user-group-list)) ! 568: ngrp) ! 569: (if (< arg 0) ! 570: (or (setq ngrp (nth (1- (- arg)) (news-cadr plist))) ! 571: (error "No previous news groups")) ! 572: (or (setq ngrp (nth arg (car plist))) ! 573: (error "No more news groups"))) ! 574: (news-select-news-group ngrp)))) ! 575: ! 576: (defun news-next-group () ! 577: "Moves to the next user group." ! 578: (interactive) ! 579: ; (message "Moving to next group...") ! 580: (news-move-to-group 0) ! 581: (while (null news-list-of-files) ! 582: (news-move-to-group 0))) ! 583: ; (message "Moving to next group... done.") ! 584: ! 585: (defun news-previous-group () ! 586: "Moves to the previous user group." ! 587: (interactive) ! 588: ; (message "Moving to previous group...") ! 589: (news-move-to-group -1) ! 590: (while (null news-list-of-files) ! 591: (news-move-to-group -1))) ! 592: ; (message "Moving to previous group... done.") ! 593: ! 594: (defun news-get-motion-lists (arg listy) ! 595: "Given a msgnumber/group this will return a list of two lists; ! 596: one for moving forward and one for moving backward." ! 597: (let ((temp listy) ! 598: (result ())) ! 599: (catch 'out ! 600: (while temp ! 601: (if (equal (car temp) arg) ! 602: (throw 'out (cons (cdr temp) (list result))) ! 603: (setq result (nconc (list (car temp)) result)) ! 604: (setq temp (cdr temp))))))) ! 605: ! 606: ;; miscellaneous io routines ! 607: (defun news-read-in-file (filename) ! 608: (erase-buffer) ! 609: (let ((start (point))) ! 610: (insert-file-contents filename) ! 611: (news-convert-format) ! 612: (goto-char start) ! 613: (forward-line 1) ! 614: (if (eobp) ! 615: (message "(Empty file?)") ! 616: (goto-char start)))) ! 617: ! 618: (defun news-convert-format () ! 619: (save-excursion ! 620: (save-restriction ! 621: (let* ((start (point)) ! 622: (end (condition-case () ! 623: (progn (search-forward "\n\n") (point)) ! 624: (error nil))) ! 625: has-from has-date) ! 626: (cond (end ! 627: (narrow-to-region start end) ! 628: (goto-char start) ! 629: (setq has-from (search-forward "\nFrom:" nil t)) ! 630: (cond ((and (not has-from) has-date) ! 631: (goto-char start) ! 632: (search-forward "\nDate:") ! 633: (beginning-of-line) ! 634: (kill-line) (kill-line))) ! 635: (news-delete-headers start) ! 636: (goto-char start))))))) ! 637: ! 638: (defun news-show-all-headers () ! 639: "Redisplay current news item with all original headers" ! 640: (interactive) ! 641: (let (news-ignored-headers ! 642: (buffer-read-only ())) ! 643: (erase-buffer) ! 644: (news-set-mode-line) ! 645: (news-read-in-file ! 646: (concat news-path ! 647: (string-subst-char ?/ ?. news-current-news-group) ! 648: "/" (int-to-string news-current-message-number))))) ! 649: ! 650: (defun news-delete-headers (pos) ! 651: (goto-char pos) ! 652: (and (stringp news-ignored-headers) ! 653: (while (re-search-forward news-ignored-headers nil t) ! 654: (beginning-of-line) ! 655: (delete-region (point) ! 656: (progn (re-search-forward "\n[^ \t]") ! 657: (forward-char -1) ! 658: (point)))))) ! 659: ! 660: (defun news-exit () ! 661: "Quit news reading session and update the .newsrc file." ! 662: (interactive) ! 663: (if (y-or-n-p "Do you really wanna quit reading news ? ") ! 664: (progn (message "Updating %s..." news-startup-file) ! 665: (news-update-newsrc-file) ! 666: (news-write-certifications) ! 667: (message "Updating %s... done" news-startup-file) ! 668: (message "Now do some real work") ! 669: (and (fboundp 'bury-buffer) (bury-buffer (current-buffer))) ! 670: (switch-to-buffer news-buffer-save) ! 671: (setq news-user-group-list ())) ! 672: (message ""))) ! 673: ! 674: (defun news-update-newsrc-file () ! 675: "Updates the .newsrc file in the users home dir." ! 676: (let ((newsrcbuf (find-file-noselect ! 677: (substitute-in-file-name news-startup-file))) ! 678: (tem news-user-group-list) ! 679: group) ! 680: (save-excursion ! 681: (if (not (null news-current-news-group)) ! 682: (news-update-message-read news-current-news-group ! 683: (news-cdar news-point-pdl))) ! 684: (switch-to-buffer newsrcbuf) ! 685: (while tem ! 686: (setq group (assoc (car tem) ! 687: news-group-article-assoc)) ! 688: (if (= (news-cadr (news-cadr group)) (news-caddr (news-cadr group))) ! 689: nil ! 690: (goto-char 0) ! 691: (if (search-forward (concat (car group) ": ") nil t) ! 692: (kill-line nil) ! 693: (insert (car group) ": \n") (backward-char 1)) ! 694: (insert (int-to-string (car (news-cadr group))) "-" ! 695: (int-to-string (news-cadr (news-cadr group))))) ! 696: (setq tem (cdr tem))) ! 697: (while news-unsubscribe-groups ! 698: (setq group (assoc (car news-unsubscribe-groups) ! 699: news-group-article-assoc)) ! 700: (goto-char 0) ! 701: (if (search-forward (concat (car group) ": ") nil t) ! 702: (progn ! 703: (backward-char 2) ! 704: (kill-line nil) ! 705: (insert "! " (int-to-string (car (news-cadr group))) ! 706: "-" (int-to-string (news-cadr (news-cadr group)))))) ! 707: (setq news-unsubscribe-groups (cdr news-unsubscribe-groups))) ! 708: (save-buffer) ! 709: (kill-buffer (current-buffer))))) ! 710: ! 711: ! 712: (defun news-unsubscribe-group (group) ! 713: "Removes you from newgroup GROUP." ! 714: (interactive (list (completing-read "Unsubscribe from group: " ! 715: news-group-article-assoc))) ! 716: (news-unsubscribe-internal group)) ! 717: ! 718: (defun news-unsubscribe-current-group () ! 719: "Removes you from the newsgroup you are now reading." ! 720: (interactive) ! 721: (if (y-or-n-p "Do you really want to unsubscribe from this group ? ") ! 722: (news-unsubscribe-internal news-current-news-group))) ! 723: ! 724: (defun news-unsubscribe-internal (group) ! 725: (let ((tem (assoc group news-group-article-assoc))) ! 726: (if tem ! 727: (progn ! 728: (setq news-unsubscribe-groups (cons group news-unsubscribe-groups)) ! 729: (news-update-message-read group (news-cdar news-point-pdl)) ! 730: (if (equal group news-current-news-group) ! 731: (news-next-group)) ! 732: (message "")) ! 733: (error "Not subscribed to group: %s" group)))) ! 734: ! 735: (defun news-save-item-in-file (file) ! 736: "Save the current article that is being read by appending to a file." ! 737: (interactive "FSave item in file: ") ! 738: (append-to-file (point-min) (point-max) file)) ! 739: ! 740: (defun news-get-pruned-list-of-files (gp-list end-file-no) ! 741: "Given a news group it finds all files in the news group. ! 742: The arg must be in slashified format. ! 743: Using ls was found to be too slow in a previous version." ! 744: (let ! 745: ((answer ! 746: (and ! 747: (not (and end-file-no ! 748: (equal (news-set-current-certifiable) ! 749: (news-group-certification gp-list)) ! 750: (setq news-list-of-files nil ! 751: news-list-of-files-possibly-bogus t))) ! 752: (let* ((file-directory (concat news-path ! 753: (string-subst-char ?/ ?. gp-list))) ! 754: tem ! 755: (last-winner ! 756: (and end-file-no ! 757: (news-wins file-directory end-file-no) ! 758: (news-find-first-or-last file-directory end-file-no 1)))) ! 759: (setq news-list-of-files-possibly-bogus t news-list-of-files nil) ! 760: (if last-winner ! 761: (progn ! 762: (setq news-list-of-files-possibly-bogus t ! 763: news-current-group-end last-winner) ! 764: (while (> last-winner end-file-no) ! 765: (news-push last-winner news-list-of-files) ! 766: (setq last-winner (1- last-winner))) ! 767: news-list-of-files) ! 768: (if (or (not (file-directory-p file-directory)) ! 769: (not (file-readable-p file-directory))) ! 770: nil ! 771: (setq news-list-of-files ! 772: (condition-case error ! 773: (directory-files file-directory) ! 774: (file-error ! 775: (if (string= (nth 2 error) "permission denied") ! 776: (message "Newsgroup %s is read-protected" ! 777: gp-list) ! 778: (signal 'file-error (cdr error))) ! 779: nil))) ! 780: (setq tem news-list-of-files) ! 781: (while tem ! 782: (if (or (not (string-match "^[0-9]*$" (car tem))) ! 783: ;; dont get confused by directories that look like numbers ! 784: (file-directory-p ! 785: (concat file-directory "/" (car tem))) ! 786: (<= (string-to-int (car tem)) end-file-no)) ! 787: (setq news-list-of-files ! 788: (delq (car tem) news-list-of-files))) ! 789: (setq tem (cdr tem))) ! 790: (if (null news-list-of-files) ! 791: (progn (setq news-current-group-end 0) ! 792: nil) ! 793: (setq news-list-of-files ! 794: (mapcar 'string-to-int news-list-of-files)) ! 795: (setq news-list-of-files (sort news-list-of-files '<)) ! 796: (setq news-current-group-end ! 797: (elt news-list-of-files ! 798: (1- (length news-list-of-files)))) ! 799: news-list-of-files))))))) ! 800: (or answer (progn (news-set-current-group-certification) nil)))) ! 801: ! 802: (defun news-read-files-into-buffer (group reversep) ! 803: (let* ((files-start-end (news-cadr (assoc group news-group-article-assoc))) ! 804: (start-file-no (car files-start-end)) ! 805: (end-file-no (news-cadr files-start-end)) ! 806: (buffer-read-only nil)) ! 807: (setq news-current-news-group group) ! 808: (setq news-current-message-number nil) ! 809: (setq news-current-group-end nil) ! 810: (news-set-mode-line) ! 811: (news-get-pruned-list-of-files group end-file-no) ! 812: (news-set-mode-line) ! 813: ;; @@ should be a lot smarter than this if we have to move ! 814: ;; @@ around correctly. ! 815: (setq news-point-pdl (list (cons (car files-start-end) ! 816: (news-cadr files-start-end)))) ! 817: (if (null news-list-of-files) ! 818: (progn (erase-buffer) ! 819: (setq news-current-group-end end-file-no) ! 820: (setq news-current-group-begin end-file-no) ! 821: (setq news-current-message-number end-file-no) ! 822: (news-set-mode-line) ! 823: ; (message "No new articles in " group " group.") ! 824: nil) ! 825: (setq news-current-group-begin (car news-list-of-files)) ! 826: (if reversep ! 827: (setq news-current-message-number news-current-group-end) ! 828: (if (> (car news-list-of-files) end-file-no) ! 829: (setcdr (car news-point-pdl) (car news-list-of-files))) ! 830: (setq news-current-message-number news-current-group-begin)) ! 831: (news-set-message-counters) ! 832: (news-set-mode-line) ! 833: (news-read-in-file (concat news-path ! 834: (string-subst-char ?/ ?. group) ! 835: "/" ! 836: (int-to-string ! 837: news-current-message-number))) ! 838: (news-set-message-counters) ! 839: (news-set-mode-line) ! 840: t))) ! 841: ! 842: (defun news-add-news-group (gp) ! 843: "Resubscribe to or add a USENET news group named GROUP (a string)." ! 844: ; @@ (completing-read ...) ! 845: ; @@ could be based on news library file ../active (slightly facist) ! 846: ; @@ or (expensive to compute) all directories under the news spool directory ! 847: (interactive "sAdd news group: ") ! 848: (let ((file-dir (concat news-path (string-subst-char ?/ ?. gp)))) ! 849: (save-excursion ! 850: (if (null (assoc gp news-group-article-assoc)) ! 851: (let ((newsrcbuf (find-file-noselect ! 852: (substitute-in-file-name news-startup-file)))) ! 853: (if (file-directory-p file-dir) ! 854: (progn ! 855: (switch-to-buffer newsrcbuf) ! 856: (goto-char 0) ! 857: (if (search-forward (concat gp "! ") nil t) ! 858: (progn ! 859: (message "Re-subscribing to group %s." gp) ! 860: ;;@@ news-unsubscribe-groups isn't being used ! 861: ;;(setq news-unsubscribe-groups ! 862: ;; (delq gp news-unsubscribe-groups)) ! 863: (backward-char 2) ! 864: (delete-char 1) ! 865: (insert ":")) ! 866: (progn ! 867: (message ! 868: "Added %s to your list of newsgroups." gp) ! 869: (end-of-buffer) ! 870: (insert gp ": 1-1\n"))) ! 871: (search-backward gp nil t) ! 872: (let (start end endofline tem) ! 873: (search-forward ": " nil t) ! 874: (setq end (point)) ! 875: (beginning-of-line) ! 876: (setq start (point)) ! 877: (end-of-line) ! 878: (setq endofline (point)) ! 879: (setq tem (buffer-substring start (- end 2))) ! 880: (let ((range (news-parse-range ! 881: (buffer-substring end endofline)))) ! 882: (setq news-group-article-assoc ! 883: (cons (list tem (list (car range) ! 884: (cdr range) ! 885: (cdr range))) ! 886: news-group-article-assoc)))) ! 887: (save-buffer) ! 888: (kill-buffer (current-buffer))) ! 889: (message "Newsgroup %s doesn't exist." gp))) ! 890: (message "Already subscribed to group %s." gp))))) ! 891: ! 892: (defun news-make-link-to-message (number newname) ! 893: "Forges a link to an rnews message numbered number (current if no arg) ! 894: Good for hanging on to a message that might or might not be ! 895: automatically deleted." ! 896: (interactive "P ! 897: FName to link to message: ") ! 898: (add-name-to-file ! 899: (concat news-path ! 900: (string-subst-char ?/ ?. news-current-news-group) ! 901: "/" (if number ! 902: (prefix-numeric-value number) ! 903: news-current-message-number)) ! 904: newname)) ! 905: ! 906: ;;; caesar-region written by [email protected] Nov 86 ! 907: ;;; modified by tower@prep Nov 86 ! 908: (defun caesar-region (&optional n) ! 909: "Caesar rotation of region by N, default 13, for decrypting netnews." ! 910: (interactive (if current-prefix-arg ; Was there a prefix arg? ! 911: (list (prefix-numeric-value current-prefix-arg)) ! 912: (list nil))) ! 913: (cond ((not (numberp n)) (setq n 13)) ! 914: ((< n 0) (setq n (- 26 (% (- n) 26)))) ! 915: (t (setq n (% n 26)))) ;canonicalize N ! 916: (if (not (zerop n)) ; no action needed for a rot of 0 ! 917: (progn ! 918: (if (or (not (boundp 'caesar-translate-table)) ! 919: (/= (aref caesar-translate-table ?a) (+ ?a n))) ! 920: (let ((i 0) (lower "abcdefghijklmnopqrstuvwxyz") upper) ! 921: (message "Building caesar-translate-table...") ! 922: (setq caesar-translate-table (make-vector 256 0)) ! 923: (while (< i 256) ! 924: (aset caesar-translate-table i i) ! 925: (setq i (1+ i))) ! 926: (setq lower (concat lower lower) upper (upcase lower) i 0) ! 927: (while (< i 26) ! 928: (aset caesar-translate-table (+ ?a i) (aref lower (+ i n))) ! 929: (aset caesar-translate-table (+ ?A i) (aref upper (+ i n))) ! 930: (setq i (1+ i))) ! 931: (message "Building caesar-translate-table... done"))) ! 932: (let ((from (region-beginning)) ! 933: (to (region-end)) ! 934: (i 0) str len) ! 935: (setq str (buffer-substring from to)) ! 936: (setq len (length str)) ! 937: (while (< i len) ! 938: (aset str i (aref caesar-translate-table (aref str i))) ! 939: (setq i (1+ i))) ! 940: (goto-char from) ! 941: (kill-region from to) ! 942: (insert str))))) ! 943: ! 944: ;;; news-caesar-buffer-body written by [email protected] Wed Oct 1, 1986 ! 945: ;;; hacked further by [email protected] ! 946: (defun news-caesar-buffer-body (&optional rotnum) ! 947: "Caesar rotates all letters in the current buffer by 13 places. ! 948: Used to encode/decode possibly offensive messages (commonly in net.jokes). ! 949: With prefix arg, specifies the number of places to rotate each letter forward. ! 950: Mail and USENET news headers are not rotated." ! 951: (interactive (if current-prefix-arg ; Was there a prefix arg? ! 952: (list (prefix-numeric-value current-prefix-arg)) ! 953: (list nil))) ! 954: (save-excursion ! 955: (let ((buffer-status buffer-read-only)) ! 956: (setq buffer-read-only nil) ! 957: ;; setup the region ! 958: (set-mark (if (progn (goto-char (point-min)) ! 959: (search-forward ! 960: (concat "\n" ! 961: (if (equal major-mode 'news-mode) ! 962: "" ! 963: mail-header-separator) ! 964: "\n") nil t)) ! 965: (point) ! 966: (point-min))) ! 967: (goto-char (point-max)) ! 968: (caesar-region rotnum) ! 969: (setq buffer-read-only buffer-status))))
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.