Annotation of 43BSD/contrib/emacs/lisp/rnews.el, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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