source: trunk/athena/bin/discuss/edsc/discuss.el.in @ 23280

Revision 23280, 41.2 KB checked in by broder, 15 years ago (diff)
Remove hard-coded paths from Emacs discuss-mode, in favor if retrieving them from autoconf.
Line 
1;;; Emacs lisp code to remote control a "discuss" shell process to
2;;; provide an emacs-based interface to the discuss conferencing system.
3;;;
4;;; Copyright (C) 1989, 1993 by the Massachusetts Institute of Technology
5;;; Developed by the MIT Student Information Processing Board (SIPB).
6;;; Written by Stan Zanarotti, Bill Sommerfeld and Theodore Ts'o.
7;;; For copying information, see the file mit-copyright.h in this release.
8;;;
9;;; $Id: discuss.el,v 1.41 1999-06-04 14:11:13 danw Exp $
10;;;
11
12;;
13;; WARNING --- change discuss-source-dir when installing this file!
14;;
15
16(provide 'discuss)
17
18(defvar discuss-source-dir nil
19  "Source directory from which this version of discuss is loaded, including
20the trailing `/'.  It must end with `/', since it will be directly
21concatenated to other file names.  Setting this to nil or an empty string
22will cause load-path to be used.")
23
24(defvar discuss-pathname "#libexecdir#/edsc"
25  "*Name of program to run as slave process for discuss.")
26
27(defvar discuss-DWIM nil
28  "If true, enable Do_What_I_Mean mode.  Allows the user to read discuss by
29repeatedly hitting the space bar.  For the truly lazy user.")
30
31(defvar discuss-safe-delete nil
32  "If true, discuss asks for confirmation before deleting a transaction with
33discuss-delete-trn.")
34
35(defvar discuss-reply-by-mail-with-message-id nil
36  "If true, use the Message-Id field in a message for generating the
37In-Reply-To field, rather than using the discuss convention of
38In-Reply-To: [###] in Meeting.")
39
40(defvar discuss-auto-reply-to-alist nil
41  "Association list of discuss meeting names (long forms) and default
42Reply-To addresses that should be inserted into replies by mail (to help
43ensure that people don't drop the CC to the discuss meeting.)")
44
45(defvar discuss-font-lock-keywords '(("^\\(From: .*\\)" 1 'bold t)
46                                     ("^\\(Subject: .*\\)" 1 'bold t))
47  "Keywords to highlight in transactions if using font-lock mode.
48(Add (add-hook 'discuss-show-trn-hooks 'font-lock-mode) to your
49.emacs to enable discuss font-lock mode.)")
50
51(defvar discuss-visible-headers nil
52  "If non-nil, a regexp matching the mail headers to display in discuss
53meetings fed by mailing lists. If nil, the value of discuss-invisible-headers
54is used instead.")
55
56(defvar discuss-invisible-headers "^From \\|^Received:"
57  "If discuss-visible-headers is nil, discuss-invisible-headers is a regexp
58matching the mail headers to be not shown by default in discuss meetings
59fed by mailing lists.")
60
61(defvar discuss-keep-discuss-ls nil
62  "If nil, windows containing *discuss-ls* buffers will be deleted when
63leaving transaction mode.")
64
65(defvar discuss-use-short-meeting-name nil
66  "If nil, transaction mode buffers will use the full name of the discuss
67meeting. If non-nil, they will use the short name.")
68
69(defvar discuss-mtgs-mode-map nil
70  "Keymap used by the meetings-list mode of the discuss subsystem.")
71
72(defvar discuss-list-mode-map nil
73  "Keymap used by the transaction-list mode of the discuss subsystem.")
74
75(defvar discuss-trn-mode-map nil
76  "Keymap used by the transaction mode of the discuss subsystem.")
77
78(defvar discuss-main-buffer "*meetings*"
79  "Name of main buffer for discuss, which holds a list of the current
80meetings.")
81
82(defvar discuss-version nil "Version of discuss code loaded.")
83(defun discuss-version nil (interactive) (message discuss-version))
84
85(defvar discuss-process nil
86  "Structure discribing the slave discuss subprocess.")
87
88(defvar discuss-cont nil
89  "Internal hook to call when discuss subprocess is done.")
90
91(defvar discuss-unwind nil
92  "Internal hook to call when discuss subprocess returns an error.")
93
94(defvar discuss-in-progress nil
95  "t if a request to the slave subprocess is outstanding.")
96
97(defvar discuss-form nil
98  "Lisp form returned by the subprocess.")
99
100(defvar discuss-meeting-list nil
101  "Meeting list.")
102
103(defvar discuss-meeting-completion-list nil
104  "Meeting list changed into the right format for completion-read.")
105
106(defvar discuss-show-num 0
107  "Current discuss transaction number.")
108
109(defvar discuss-show-headers nil
110  "Whether or not all headers are being displayed on the current transaction.")
111
112(defvar discuss-meeting nil
113  "Buffer-local variable containing the name of the meeting of a discuss
114transaction buffer.  Nil means this buffer is not a discuss-transaction
115buffer.")
116
117(defvar discuss-meeting-info nil
118  "Buffer-local variable containing the info struction for the discuss
119transaction buffer.")
120
121(defvar discuss-cur-mtg-buf nil
122  "Name of buffer for current Discuss meeting.")
123
124(defvar discuss-cur-direction 0
125  "Current discuss direction.")
126
127(defvar discuss-async t
128  "*Run discuss commands asynchronously.
129
130Currently ignored (always async).")
131
132(defvar discuss-in-show-trn nil)
133
134(defvar discuss-error nil
135  "Contains error message returned by edsc process.  If nil, means last
136request completed successfully.")
137
138
139;;; Major modes defined by this package.
140
141;;; List of all meetings.
142
143(defun discuss-mtgs-mode ()
144  "Major mode for providing an emacs discuss subsystem.
145This looks a lot like RMAIL.  This works by using ``edsc'' as a subjob.
146
147The following commands are available:
148\\[describe-mode]       List available commands.
149\\[discuss-forward-meeting]     Go to next meeting that has unread transactions.
150\\[discuss-prev-meeting]        Go to previous meeting has unread transactions.
151\\[discuss-lsm] List meetings.
152\\[discuss-goto]        Go to meeting listed on line.
153\\[discuss-add-mtg]     Add meeting.
154\\[discuss-del-mtg]     Delete meeting listed on line.
155\\[discuss-catchup]     Mark a meeting as read (catch up).
156\\[discuss-quit]        Quit Discuss."
157  (interactive)
158  (kill-all-local-variables)
159  (setq major-mode 'discuss-mtgs-mode)
160  (setq mode-name "Discuss (meetings)")
161  (use-local-map discuss-mtgs-mode-map)
162  (setq buffer-read-only t)
163  (run-hooks 'discuss-mode-hooks))
164
165;;; Meeting list mode.
166
167(defun discuss-list-mode ()
168  "Major mode for looking at listings of a meeting under the
169discuss subsystem."
170  (interactive)
171  (kill-all-local-variables)
172  (setq major-mode 'discuss-list-mode)
173  (setq mode-name "Discuss (list)")
174  (use-local-map discuss-list-mode-map)
175  (setq buffer-read-only t)
176  (make-local-variable 'trans-buffer)
177  (setq trans-buffer nil)
178  (make-local-variable 'meeting-name)
179  (setq meeting-name nil)
180  (run-hooks 'discuss-list-hooks))
181
182;;; Transaction mode.
183
184(defun discuss-trn-mode ()
185"Major mode for looking at transactions of a meeting under the
186discuss subsystem.
187All normal editing commands are turned off.
188Instead, these commands are available:
189
190\\[describe-mode]       List available commands.
191\\[discuss-scroll-up]   Scroll to next screen of this transaction.
192\\[scroll-down] Scroll to previous screen of this transaction.
193\\[discuss-ls]  List headers of remaining transactions.
194\\[discuss-next-trn]    Move to Next transaction.
195\\[discuss-prev-trn]    Move to Previous transaction.
196\\[discuss-last-trn]    Move to Last transaction in meeting.
197\\[discuss-first-trn]   Move to First transaction in meeting.
198\\[discuss-nref]        Move to Next transaction in chain.
199\\[discuss-pref]        Move to Previous transaction in chain.
200\\[discuss-fref]        Move to First transaction in chain.
201\\[discuss-lref]        Move to Last transaction in chain.
202\\[discuss-show-trn]    Goto a specific transaction.
203\\[discuss-delete-trn]  Delete transaction (and move forwards).
204\\[discuss-delete-trn-backwards]        Delete transaction (and move backwards).
205\\[discuss-retrieve-trn]        Retrieve (undelete) a deleted transaction.
206\\[discuss-update]      Redisplay this transaction from the top.
207\\[discuss-show-trn-with-headers]       Redisplay this transaction with full mail headers.
208\\[discuss-reply]       Reply to this transaction (via discuss.)
209\\[discuss-reply-by-mail]       Reply to this transaction (via mail.)
210\\[discuss-forward]     Forward this transaction via mail.
211\\[discuss-trn-output]  Append this transaction to a UNIX file.
212\\[discuss-talk]        Talk.  Enter a new transaction.
213\\[discuss-toggle-trn-flag]     Toggle the flag on this transaction.
214\\[discuss-set-seen-and-leave-mtg]      Mark transaction as highest-seen and leave meeting.
215\\[discuss-catchup]     Catch up.  Mark all of the transactions in this meeting as read.
216\\[discuss-add-mtg]     Add meeting (if this transaction is a meeting annoucement).
217\\[discuss-leave-mtg]   Quit (leave) meeting."
218  (interactive)
219  (kill-all-local-variables)
220  (setq major-mode 'discuss-trn-mode)
221  (setq mode-name "Discuss (transaction)")
222  (use-local-map discuss-trn-mode-map)
223  (setq buffer-read-only t)
224  (make-local-variable 'discuss-current-transaction)
225  (setq discuss-current-transaction 0)
226  (make-local-variable 'discuss-highest-seen)
227  (setq discuss-highest-seen 0)
228  (make-local-variable 'discuss-output-last-file)
229  (make-local-variable 'discuss-meeting)
230  (make-local-variable 'discuss-meeting-info)
231  (setq discuss-output-last-file nil)
232  (run-hooks 'discuss-trn-hooks))
233
234
235;;; Main entry point:  Start up a slave process and listen for requests.
236
237(defun discuss (&optional arg)
238  "Enter discuss mode for emacs and list meetings."
239  (interactive "P")
240  (message "Starting discuss....")
241  (if (not (and (get-buffer discuss-main-buffer)
242                (buffer-name (get-buffer discuss-main-buffer))
243                (> (length discuss-meeting-list) 0)))
244      (progn
245        (switch-to-buffer (get-buffer-create discuss-main-buffer))
246        (discuss-mtgs-mode)
247        (setq discuss-meeting-list nil)
248        (if arg
249            (message "Hit `g' and enter a meeting name.")       
250          (discuss-lsm)))
251    (switch-to-buffer discuss-main-buffer)))
252
253;;; Entry points typically entered through key sequences.
254
255(defun discuss-list-meetings ()
256  "List discuss meetings."
257  (interactive)
258  (message "Listing meetings..."
259  (switch-to-buffer (get-buffer discuss-main-buffer))
260  (let ((buffer-read-only nil))
261    (erase-buffer))
262  (discuss-send-cmd "(gml)\n" 'discuss-end-of-lsm 'discuss-read-form)))
263
264(fset 'discuss-lsm (symbol-function 'discuss-list-meetings))
265
266;;(defmacro cadr (x)
267;;  (list 'car (list 'cdr x)))
268(defun cadr (x) (car (cdr x)))
269
270;;(defmacro caddr (x)
271;;  (` (car (cdr (cdr (, x))))))
272(defun caddr (x) (car (cdr (cdr x))))
273
274;;(defmacro cddr (x)
275;;  (` (cdr (cdr (, x)))))
276(defun cddr (x) (cdr (cdr x)))
277
278(defun discuss-lsm-1 (entry)
279  (insert (cond ((eq (car entry) 1)
280                 " c       ")
281                ((stringp (car entry))
282                 "   X     ")
283                (t
284                 "         "))
285          (cadr entry))
286  (cond ((stringp (car entry))
287         (insert " (" (car entry) ")"))
288        ((cddr entry)
289         (mapcar 'discuss-lsm-2 (cddr entry))))
290  (insert "\n"))
291
292(defun discuss-lsm-2 (name)
293  (insert ", " name))
294
295;; Compliments of jik
296(defun flatten (list)
297  (if (eq nil list) '())
298  (let* ((newlist (copy-list (car list)))
299        (restoflist (cdr list))
300        (pointer newlist))
301    (while (not (eq nil restoflist))
302      (while (not (eq nil (cdr pointer)))
303        (setq pointer (cdr pointer)))
304      (setcdr pointer (copy-list (car restoflist)))
305      (setq restoflist (cdr restoflist)))
306    newlist))
307
308(defun copy-list (list)
309  (if (eq nil list)
310      '()
311    (cons (car list) (copy-list (cdr list)))))
312
313(defun discuss-end-of-lsm ()
314  (message "Listing meetings...")
315  (let ((orig-buffer (current-buffer)))
316    (set-buffer discuss-main-buffer)
317    (setq discuss-meeting-list (apply 'vector discuss-form))
318    (setq discuss-meeting-completion-list
319          (mapcar (function (lambda (x) (cons x 0)))
320                  (flatten (mapcar 'cdr discuss-form))))
321    (let ((buffer-read-only nil))
322      (erase-buffer)
323      (goto-char (point-min))
324      (insert " Flags   Meeting name\n"
325              " -----   ------------\n")
326      (mapcar 'discuss-lsm-1 discuss-form)
327      (goto-char (point-max))
328      (backward-delete-char 1))
329    (goto-char (point-min))
330    (forward-line 2)
331    (set-buffer orig-buffer))
332  (message "Listing meetings...done."))
333
334(defun discuss-find-meeting (meeting)
335  (let ((i 0)
336        (eol (length discuss-meeting-list)))
337    (while (and (< i eol)
338                (not (member meeting (aref discuss-meeting-list i))))
339        (setq i (1+ i)))
340    (if (< i eol)
341        (aref discuss-meeting-list i)
342      nil)))
343
344
345(defun discuss-quit ()
346  "Exits Discuss mode."
347  (interactive)
348  (if discuss-cur-mtg-buf
349      (discuss-leave-mtg))
350  (discuss-restart)
351  (switch-to-buffer (other-buffer))
352  (bury-buffer discuss-main-buffer))
353
354(defun discuss-goto (&optional meeting)
355  "Go to a meeting."
356  (interactive (list (if (or current-prefix-arg
357                             (not (equal (buffer-name) discuss-main-buffer))
358                             (= (point) 1))
359                         (completing-read "Meeting name:  "
360                                          discuss-meeting-completion-list
361                                          nil t ""))))
362  (if (not meeting)
363      (let ((curline (- (count-lines 1 (min (1+ (point)) (point-max))) 3)))
364        (if (< curline 0)
365            (error "Not looking at a meeting."))
366        (setq meeting (cadr (aref discuss-meeting-list
367                                  curline)))))
368  (if (not (and discuss-cur-mtg-buf
369               (buffer-name discuss-cur-mtg-buf)
370               (equal discuss-current-meeting meeting)))
371      (progn
372        (if discuss-cur-mtg-buf
373            (discuss-leave-mtg))
374        (setq discuss-cur-mtg-buf
375              (get-buffer-create (if discuss-use-short-meeting-name
376                                     (caddr (discuss-find-meeting meeting))
377                                   (concat "*" meeting " meeting*"))))
378        (switch-to-buffer discuss-cur-mtg-buf)
379        (discuss-trn-mode))
380    (progn
381      (set-buffer discuss-cur-mtg-buf)
382      (discuss-send-cmd (format "(ss %d %s)\n"
383                                discuss-highest-seen
384                                discuss-meeting)
385                        nil
386                        (if discuss-old-ss nil 'discuss-read-form))))
387  (switch-to-buffer discuss-cur-mtg-buf)
388  (setq discuss-meeting meeting)
389  (setq discuss-current-meeting meeting)   ;;; denigrated
390  (setq discuss-output-last-file (concat discuss-meeting ".trans"))
391  (discuss-send-cmd (format "(gmi %s)\n" meeting)
392                    'discuss-end-of-goto 'discuss-read-form
393                    'discuss-goto-error))
394
395(defun discuss-goto-error ()
396  "Called to back out when there's an error in going to a meeting."
397  (kill-buffer (buffer-name discuss-cur-mtg-buf))
398  (setq discuss-cur-mtg-buf nil)
399  (setq discuss-current-meeting nil)
400  (switch-to-buffer discuss-main-buffer))
401
402(defun discuss-end-of-goto ()
403  (let ((last (nth 4 discuss-form)))
404    ;
405    ; To have gotten this far, we must have had status access....
406    ;
407    (if (not (string-match "r" (nth 10 discuss-form)))
408        (progn
409          (discuss-goto-error)
410          (error "Insufficient access to read transactions in %s"
411                 (nth 1 discuss-current-meeting-info))))
412    (setq discuss-highest-seen (nth 11 discuss-form))
413    (if (> discuss-highest-seen last)
414        (progn
415          (beep)
416          (message "Warning!  Last seen transaction higher than last transaction")
417          (sit-for 1)
418          (setq discuss-highest-seen last)))
419    (message "%s meeting: %d new, %d last."
420             (cadr discuss-form)
421             (- last discuss-highest-seen)
422             last)
423    (set-buffer discuss-cur-mtg-buf)
424    (setq discuss-current-meeting-info discuss-form)
425    (cond ((not (zerop discuss-current-transaction)) nil)
426          ((zerop (nth 3 discuss-form)) (error "Empty meeting."))
427          ((or (zerop discuss-highest-seen) (>= discuss-highest-seen last))
428           (discuss-show-trn last))
429          (t (discuss-send-cmd (format "(nut %d %s)\n"
430                                       discuss-highest-seen
431                                       discuss-meeting)
432;                              'discuss-next-goto
433                               '(lambda () (progn (discuss-show-trn
434                                                   (car discuss-form))))
435                               'discuss-read-form)))))
436
437;(defun discuss-next-goto ()
438;  (discuss-show-trn (car discuss-form)))
439
440;;;
441;;; This is broken --- only works in transaction buffer.  Of course, this is
442;;; is the only place that you'd really want to use it.  Actually, it
443;;; sort of works in meetings-mode too, but only barely so.
444;;; This should be cleaned up.  -- TYT
445;;;
446(defun discuss-stat (&optional meeting)
447  "Go to a meeting."
448  (interactive (list (if (eq (current-buffer) discuss-cur-mtg-buf)
449                         discuss-meeting
450                       (if (or current-prefix-arg
451                               (not (equal (buffer-name) discuss-main-buffer))
452                               (= (point) 1))
453                         (completing-read "Meeting name:  "
454                                          discuss-meeting-completion-list
455                                          nil t "")))))
456  (if (not meeting)
457      (let ((curline (- (count-lines 1 (min (1+ (point)) (point-max))) 3)))
458        (if (< curline 0)
459            (error "Not looking at a meeting."))
460        (setq meeting (cadr (aref discuss-meeting-list
461                                  curline)))))
462  (discuss-send-cmd (format "(gmi %s)\n" meeting)
463                    'discuss-end-of-stat 'discuss-read-form))
464
465(defun discuss-end-of-stat ()
466  (setq discuss-current-meeting-info discuss-form)
467  (setq discuss-meeting-info discuss-form)
468  (let ((last (nth 4 discuss-form))
469        (highest-seen (nth 11 discuss-form)))
470    (if (and (equal (cadr discuss-form) discuss-current-meeting)
471             (not (= discuss-highest-seen 0)))
472        (setq highest-seen discuss-highest-seen))    ;; This is wrong...
473    (message "%s meeting: %d new, %d last."
474             (cadr discuss-form)
475             (- last highest-seen)
476             last)))
477
478(defun discuss-show-trn-with-headers ()
479  "Show transaction with full headers."
480  (interactive)
481  (discuss-show-trn discuss-current-transaction t))
482
483(defun discuss-show-trn (trn-num &optional show-headers)
484  "Show transaction number N (prefix argument)."
485  (interactive
486   (list (if (not (numberp current-prefix-arg))
487             (string-to-int (read-string "Transaction number: "))
488           current-prefix-arg)))
489  (if (and trn-num (numberp trn-num))
490      (progn
491        (setq discuss-show-num trn-num)
492        (setq discuss-show-headers show-headers)
493        (discuss-send-cmd (format "(gtfc %d %d %s)\n"
494                                  discuss-cur-direction
495                                  trn-num
496                                  discuss-current-meeting)
497                          'discuss-end-show-trn
498                          'discuss-read-form))))
499
500(defun discuss-end-show-trn ()
501  (let ((transaction-file (car discuss-form)))
502    (set-buffer discuss-cur-mtg-buf)
503    (setq discuss-current-transaction-info (cdr discuss-form))
504    (setq discuss-current-transaction discuss-show-num)
505    (setq discuss-highest-seen (max discuss-highest-seen
506                                    discuss-current-transaction))
507    (if (>= discuss-current-transaction
508            (nth 4 discuss-current-meeting-info))
509        (let ((discuss-in-show-trn t))
510          (discuss-update)
511          (discuss-block-til-ready nil)))
512
513    (setq mode-line-process (format " %d/%d"
514                                    discuss-current-transaction
515                                    (nth 4 discuss-current-meeting-info)))
516    (let ((buffer-read-only nil))
517      (erase-buffer)
518      (insert-file-contents transaction-file)
519      (if (not discuss-show-headers)
520          (discuss-clean-msg-header))
521      (goto-char (point-min)))
522    (if (= (caddr discuss-current-transaction-info) 0)
523        (progn
524          (message "Last transaction in %s" discuss-meeting)
525          (discuss-mark-read-meeting discuss-meeting)
526          (discuss-next-meeting t)))
527    (make-local-variable 'font-lock-defaults)
528    (setq font-lock-defaults '(discuss-font-lock-keywords t))
529    (run-hooks 'discuss-show-trn-hooks)))
530
531(defun discuss-clean-msg-header ()
532  (save-excursion
533    (goto-char (point-min))
534    (next-line 2)       ; skip title and subject
535    (if (looking-at "From \\|[^ ]+:")
536        (let ((start (point)))
537          (save-restriction
538            (if (search-forward "\n\n" nil 'move)
539                (backward-char 1))
540            (narrow-to-region start (point))
541            (goto-char (point-min))
542            (condition-case nil
543                (if discuss-visible-headers
544                    (while (< (point) (point-max))
545                      (cond ((looking-at discuss-visible-headers)
546                             (re-search-forward "\n[^ \t]"))
547                            (t
548                             (delete-region (point)
549                                            (progn (re-search-forward "\n[^ \t]")
550                                                   (- (point) 1))))))
551                  (while (re-search-forward discuss-invisible-headers nil t)
552                    (beginning-of-line)
553                    (delete-region (point) (progn (re-search-forward "\n[^ \t]")
554                                                  (- (point) 1)))
555                    (beginning-of-line)))
556              (error nil)))))))
557
558(defun discuss-update ()
559  "Update Discuss display to show new transactions."
560  (interactive)
561  (discuss-send-cmd (format "(gmi %s)\n" discuss-meeting)
562                    'discuss-end-of-update 'discuss-read-form))
563
564(defun discuss-end-of-update ()
565  (setq discuss-current-meeting-info discuss-form)
566  (save-excursion
567    (set-buffer discuss-cur-mtg-buf)
568    (if (not discuss-in-show-trn)
569        (discuss-show-trn discuss-current-transaction))))
570
571(defun discuss-next-trn ()
572  "Show next transaction."
573  (interactive)
574  (if (or (not discuss-current-transaction)
575          (= discuss-current-transaction 0))
576      (error "Not looking at transactions")
577    (let ((next (caddr discuss-current-transaction-info)))
578      (if (= next 0)
579          (progn
580            (discuss-send-cmd (format "(gti %d %s)\n"
581                                      discuss-current-transaction
582                                      discuss-current-meeting)
583                              nil 'discuss-read-form)
584            (discuss-block-til-ready nil)
585            (setq discuss-current-transaction-info discuss-form)
586            (if (= 0 (caddr discuss-current-transaction-info))
587                (if discuss-DWIM
588                    (discuss-leave-mtg)
589                  (error "No next transaction."))
590              (progn
591                (setq discuss-cur-direction 1)
592                (discuss-send-cmd (format "(im %s)\n" discuss-current-meeting)
593                                  nil 'discuss-read-form)
594                (discuss-next-trn))))
595        (progn
596          (setq discuss-cur-direction 1)
597          (discuss-show-trn next))))))
598
599(defun discuss-prev-trn ()
600  "Show previous transaction."
601  (interactive)
602  (if (or (not discuss-current-transaction)
603          (= discuss-current-transaction 0))
604      (error "Not looking at transactions")
605    (let ((prev (cadr discuss-current-transaction-info)))
606      (if (= prev 0)
607          (error "No previous transaction.")
608        (progn
609          (setq discuss-cur-direction 2)
610          (discuss-show-trn prev))))))
611
612
613(defun discuss-nref ()
614  "Show next transaction in chain."
615  (interactive)
616  (if (or (not discuss-current-transaction)
617          (= discuss-current-transaction 0))
618      (error "Not looking at transactions")
619    (let ((nref (nth 4 discuss-current-transaction-info)))
620      (if (= nref 0)
621          (error "No next reference.")
622        (progn
623          (setq discuss-cur-direction 3)
624          (discuss-show-trn nref))))))
625
626(defun discuss-pref ()
627  "Show previous transaction in chain."
628  (interactive)
629  (if (or (not discuss-current-transaction)
630          (= discuss-current-transaction 0))
631      (error "Not looking at transactions")
632    (let ((pref (nth 3 discuss-current-transaction-info)))
633      (if (= pref 0)
634          (error "No previous reference.")
635        (progn
636          (setq discuss-cur-direction 4)
637          (discuss-show-trn pref))))))
638
639(defun discuss-lref ()
640  "Show last transaction in chain."
641  (interactive)
642  (if (or (not discuss-current-transaction)
643          (= discuss-current-transaction 0))
644      (error "Not looking at transactions")
645    (let ((lref (nth 6 discuss-current-transaction-info)))
646      (if (= lref 0)
647          (error "No last reference.")
648        (progn
649          (setq discuss-cur-direction 4)
650          (discuss-show-trn lref))))))
651
652(defun discuss-fref ()
653  "Show first transaction in chain."
654  (interactive)
655  (if (or (not discuss-current-transaction)
656          (= discuss-current-transaction 0))
657      (error "Not looking at transactions")
658    (let ((fref (nth 5 discuss-current-transaction-info)))
659      (if (= fref 0)
660          (error "No first reference.")
661        (progn
662          (setq discuss-cur-direction 3)
663          (discuss-show-trn fref))))))
664
665(defun discuss-first-trn ()
666  "Show first transaction of meeting."
667  (interactive)
668  (let ((first (nth 3 discuss-current-meeting-info)))
669    (setq discuss-cur-direction 1)
670    (discuss-show-trn first)))
671
672(defun discuss-last-trn ()
673  "Show last transaction of meeting."
674  (interactive)
675  (let ((last (nth 4 discuss-current-meeting-info)))
676    (setq discuss-cur-direction 2)
677    (discuss-show-trn last)))
678
679(defun discuss-toggle-trn-flag ()
680  "Toggle the per-transaction flag."
681  (interactive)
682  (let ((old-flag (nth 13 discuss-current-transaction-info)))
683    (if old-flag
684        (progn
685          (discuss-send-cmd (format "(it %d %s)\n"
686                                    discuss-current-transaction
687                                    discuss-meeting)
688                            'nil 'discuss-read-form)
689          (message "Toggling the transaction flag....")
690          (discuss-send-cmd (format "(sfl %d %d %s)\n"
691                                    (logxor old-flag 2)
692                                    discuss-current-transaction
693                                    discuss-meeting)
694                            'discuss-end-of-toggle 'discuss-read-form)))))
695
696(defun discuss-end-of-toggle ()
697  (discuss-show-trn discuss-current-transaction)
698  (message ""))
699
700(defun discuss-set-seen-and-leave-mtg (arg)
701  "Sets the highest transaction number seen in the current meeting to
702the argument or the current transaction and leaves the meeting."
703  (interactive "p")
704  (if (not discuss-cur-mtg-buf)
705      (error "Not looking at a meeting.")
706    (if current-prefix-arg
707        (setq discuss-highest-seen arg)
708      (setq discuss-highest-seen discuss-current-transaction))
709    (discuss-next-meeting t t)
710    (discuss-mark-unread-meeting discuss-current-meeting)
711    (discuss-leave-mtg)))
712
713(defun discuss-leave-mtg ()
714  "Leave the current discuss meeting."
715  (interactive)
716  (if (buffer-name discuss-cur-mtg-buf)
717      (progn
718        (set-buffer discuss-cur-mtg-buf)
719        (if (not (= discuss-highest-seen 0))
720            (discuss-send-cmd (format "(ss %d %s)\n"
721                                      discuss-highest-seen
722                                      discuss-meeting)
723                              nil
724                              (if discuss-old-ss nil 'discuss-read-form)))
725        (kill-buffer (buffer-name discuss-cur-mtg-buf))
726        (setq discuss-cur-mtg-buf nil)
727        (setq discuss-current-meeting nil)
728        (if (and (not discuss-keep-discuss-ls) (get-buffer "*discuss-ls*"))
729            (progn
730              (delete-windows-on (get-buffer "*discuss-ls*"))
731              (bury-buffer (get-buffer "*discuss-ls*"))))
732        (switch-to-buffer discuss-main-buffer))))
733
734(defun discuss-catchup (&optional meeting)
735  "Mark all messages in the current meeting as read."
736  (interactive
737   (list (or discuss-cur-mtg-buf
738             (if (or current-prefix-arg (= (point) 1))
739                 (completing-read "Meeting name:  "
740                                  discuss-meeting-completion-list
741                                  nil t "")))))
742
743  ;; If meeting is nil or a string, we are in the *meetings* buffer.  Use the
744  ;; meeting on the current line.
745  (if (or (not meeting) (stringp meeting))
746      (let ((curline (- (count-lines 1 (min (1+ (point)) (point-max))) 3)))
747        (if meeting
748            nil
749          (if (< curline 0)
750              (error "Not looking at a meeting."))
751          (setq meeting (cadr (aref discuss-meeting-list curline))))
752        (message "Catching up in %s" meeting)
753        (discuss-send-cmd (format "(gmi %s)\n" meeting)
754                          'discuss-end-of-catchup 'discuss-read-form))
755    ;; Otherwise just set discuss-highest-seen.
756    (setq discuss-highest-seen (nth 6 discuss-current-meeting-info))
757    (discuss-mark-read-meeting (nth 1 discuss-current-meeting-info))
758    (discuss-next-meeting t)
759    (discuss-leave-mtg)
760    ))
761
762(defun discuss-end-of-catchup ()
763  (let ((meeting (nth 1 discuss-form))
764        (highest (nth 6 discuss-form)))
765    (discuss-send-cmd (format "(ss %d %s)\n" highest meeting)
766                      nil
767                      (if discuss-old-ss nil 'discuss-read-form))
768    (discuss-mark-read-meeting meeting)
769    (discuss-next-meeting t)
770    (message "Done.")
771    ))
772
773(defun discuss-delete-trn-backwards (trn-num)
774  (interactive
775   (cond (current-prefix-arg
776          (if discuss-cur-mtg-buf
777              (list (string-to-int (read-input "Transaction to delete: ")))
778            (error "Not currently visiting a meeting.")))
779         ((eq (current-buffer) discuss-cur-mtg-buf)
780          (list discuss-current-transaction))
781         (t
782          (if discuss-cur-mtg-buf
783              (list (string-to-int (read-input "Transaction to delete: ")))
784            (error "Not currently visiting a meeting.")))
785         ))
786  (discuss-delete-trn trn-num t))
787
788(defun discuss-delete-trn (trn-num &optional backwards)
789  (interactive
790   (cond (current-prefix-arg
791          (if discuss-cur-mtg-buf
792              (list (string-to-int (read-input "Transaction to delete: ")))
793            (error "Not currently visiting a meeting.")))
794         ((eq (current-buffer) discuss-cur-mtg-buf)
795          (list discuss-current-transaction))
796         (t
797          (if discuss-cur-mtg-buf
798              (list (string-to-int (read-input "Transaction to delete: ")))
799            (error "Not currently visiting a meeting.")))
800         ))
801  ;; Probably we should make sure the transaction can be deleted before
802  ;; asking this question, but the cache code is too confusing...
803  (if (and discuss-safe-delete
804           (not (yes-or-no-p (format "Delete transaction %d? " trn-num))))
805      nil
806    (let ((info discuss-current-transaction-info)
807          other)
808      (if (and info
809               (= discuss-current-transaction trn-num))
810          (progn
811            (if backwards
812                (setq discuss-current-transaction (cadr info)
813                      other (caddr info))
814              (setq discuss-current-transaction (caddr info)
815                    other (cadr info)))
816            (if (= discuss-current-transaction 0)
817                (setq discuss-current-transaction other))
818            (if (= discuss-current-transaction 0)
819                (progn
820                  (message "No more transactions in meeting!")
821                  (beep)))
822            ))
823      (discuss-send-cmd (format "(itn %d %s)\n"
824                                trn-num
825                                discuss-meeting)
826                        'nil 'discuss-read-form)
827      (message "Deleting %d...." trn-num)
828      (discuss-send-cmd (format "(dt %d %s)\n" trn-num discuss-meeting)
829                        'discuss-end-del-trn 'discuss-read-form))))
830
831(defun discuss-end-del-trn ()
832  (message "Done.")
833  (discuss-show-trn discuss-current-transaction))
834
835(defun discuss-retrieve-trn (trn-num)
836  "Retrieve a deleted transaction."
837  (interactive "nTransaction to retrieve: ")
838  (setq discuss-current-transaction trn-num)
839  (message "Retrieving %d...." trn-num)
840  (discuss-send-cmd (format "(rt %d %s)\n" trn-num discuss-meeting)
841                    'discuss-end-rt-trn 'discuss-read-form))
842
843(defun discuss-end-rt-trn ()
844  (message "Done.")
845  (discuss-send-cmd (format "(itn %d %s)\n"
846                            discuss-current-transaction
847                            discuss-meeting)
848                    'nil 'discuss-read-form)
849  (discuss-show-trn discuss-current-transaction))
850
851(defun discuss-la-invalidate-relatives (trn-num)
852  (discuss-send-cmd (format "(itn %d %s)\n"
853                            trn-num
854                            discuss-meeting)
855                    'nil 'discuss-read-form)
856  )
857
858(defun discuss-format-trn-num (num)
859  (format "[%s%d]"
860          (cond ((<= num 9) "000")
861                ((<= num 99) "00")
862                ((<= num 999) "0")
863                (t ""))
864          num))
865
866;;; Discuss DWIM
867(defun discuss-scroll-up ()
868  (interactive)
869  (condition-case err
870      (scroll-up nil)
871    (error
872     (if (and discuss-DWIM
873              (equal err '(end-of-buffer)))
874         (if (equal discuss-current-transaction
875                    (nth 4 discuss-current-meeting-info))
876             (discuss-leave-mtg)
877           (discuss-next-trn))
878       (signal (car err) (cdr err))))))
879
880
881;;; Routines for communicating with slave process.  Since things are
882;;; asynchronous when communicating with the process, we may have to
883;;; spin on a flag if something else is in progress.
884;;;
885;;; The optional arguments to discuss-send-cmd are a function to be
886;;; called by the filter-func when the end-of-operation is seen and a
887;;; function to be used as a filter (it gets called with the process and
888;;; a string when the process outputs something.
889;;;
890;;; It is possible that if discuss-in-progress gets set to true
891;;; accidentally that things could get deadlocked; I think that can be
892;;; avoided in the purely, but I'm not sure.. (knowing how easily elisp
893;;; breaks unexpectedly, I should put in a lock timeout and a function to
894;;; unlock things).
895
896(defun discuss-restart ()
897  "Used to save the world when edsc gets hung or dies...
898
899Flushes the discuss cache and destroys the edsc process."
900  (interactive)
901  (if (and discuss-process
902           (equal (process-status discuss-process) 'run))
903      (send-string discuss-process "(quit)\n"))
904  (setq discuss-process nil
905        discuss-in-progress nil))
906
907(defun discuss-send-cmd (cmd &optional end-func filter-func unwind-func)
908  "Send an command to the edsc process."
909  (if (not discuss-process)
910      (let ((process-connection-type nil))
911        (if (not (file-exists-p discuss-pathname))
912            (error "%s does not exist!" discuss-pathname))
913        (setq discuss-process (start-process "discuss-shell"
914                                             nil
915                                             discuss-pathname))
916        (set-process-sentinel discuss-process 'discuss-edsc-sentinel)
917        (discuss-send-cmd "(gpv)\n" nil 'discuss-read-form)
918        (discuss-block-til-ready t)
919        (let* ((discuss-vers (cond (discuss-form
920                                    (car discuss-form))
921                                   ((equal discuss-error
922                                          "Unimplemented operation")
923                                    10)
924                                   (t
925                                    (error "Edsc returned error: %s"
926                                           discuss-error))))
927               (ver-string
928                (format "%d.%d"
929                        (/ discuss-vers 10)
930                        (- discuss-vers (* (/ discuss-vers 10) 10)))))
931          (if (> 23 discuss-vers)
932              (setq discuss-version-string "")
933            (setq discuss-version-string (cadr discuss-form)))
934          (setq discuss-old-ss (= 23 discuss-vers))
935          (if (> 25 discuss-vers)
936              (progn
937                (discuss-restart)
938                (error
939                 "Bad version of edsc (%s) --- you need at least version 2.5."
940                 ver-string))
941            (progn
942              (message "Started edsc process.... version %s %s)"
943                       ver-string discuss-version-string)
944              (sit-for 1))))))
945
946  ;; block until we have control over things..
947  (discuss-block-til-ready t)
948  (if filter-func
949      (setq discuss-in-progress t))
950  (save-excursion
951    (setq discuss-debug-cmd cmd)
952    (setq discuss-reading-string "")
953    (setq discuss-cont end-func)
954    (setq discuss-unwind unwind-func)
955    (if filter-func (set-process-filter discuss-process filter-func))
956    (send-string discuss-process cmd)))
957
958(defun discuss-block-til-ready (verbose)
959  "Block, waiting until the previous operation for discuss finished.
960If VERBOSE is non-nil, then print a message that we're waiting for the
961discuss server while we spin-block."
962  (if discuss-in-progress
963      (progn
964        (while discuss-in-progress
965          (if verbose
966              (message "waiting for discuss..."))
967          (sit-for 1)
968          (accept-process-output))
969        (message ""))))
970
971;;;
972;;; This gets called when something nasty has happened to our edsc.
973;;;
974(defun discuss-edsc-sentinel (process signal)
975  (let ((buffer (process-buffer process))
976        (status (process-status process)))
977    (cond
978     ((eq status 'exit)
979      (discuss-restart))
980     ((eq status 'signal)
981      (ding)
982      (message "discuss-shell: %s."
983               (substring signal 0 -1))
984      (discuss-restart))
985     )))
986
987;;; Routines to filter the output from discuss.
988;;; These are pretty simplistic
989
990(defun discuss-read-form (process string)
991  (setq discuss-reading-string (concat discuss-reading-string string))
992  (let* ((end-of-line (string-match "\n" discuss-reading-string)))
993    (if end-of-line
994        (let ((flag-char (substring discuss-reading-string 0 1))
995              (first-line (substring discuss-reading-string 1
996                                     end-of-line)))
997          (setq discuss-error nil)
998          (cond ((equal flag-char "-") ; warning
999                 (message first-line)
1000                 (setq discuss-reading-string
1001                       (substring discuss-reading-string (1+ end-of-line)))
1002                 (discuss-read-form process ""))
1003                ((equal flag-char "l") ; Sun os ld.so warning crock
1004                 (message "l" first-line)
1005                 (setq discuss-reading-string
1006                       (substring discuss-reading-string (1+ end-of-line)))
1007                 (discuss-read-form process ""))
1008                ((equal flag-char ";") ; error
1009                 (setq discuss-error first-line)
1010                 (message discuss-error)
1011                 (ding)
1012                 (setq discuss-reading-string
1013                       (substring discuss-reading-string (1+ end-of-line)))
1014                 (setq discuss-in-progress nil)
1015                 (setq discuss-form nil)
1016                 (if discuss-unwind
1017                     (apply discuss-unwind nil)))
1018                (t
1019                 (setq discuss-form
1020                       (car (read-from-string (concat "(" first-line))))
1021                 (setq discuss-in-progress nil)
1022                 (if discuss-cont
1023                     (apply discuss-cont nil))))))))
1024
1025
1026; run this at each load
1027(defun discuss-initialize nil
1028  (setq discuss-version
1029        "$Id: discuss.el,v 1.41 1999-06-04 14:11:13 danw Exp $")
1030
1031;;;
1032;;; Lots of autoload stuff....
1033;;;
1034
1035(autoload 'discuss-talk (concat discuss-source-dir "discuss-enter")
1036          "Enter a new discuss transaction." t)
1037
1038(autoload 'discuss-reply (concat discuss-source-dir "discuss-enter")
1039          "Reply to an existing discuss transaction." t)
1040
1041(autoload 'discuss-randrp (concat discuss-source-dir "discuss-enter")
1042          "Random reply in a meeting." t)
1043
1044(autoload 'discuss-ls (concat discuss-source-dir "discuss-ls")
1045          "List the headings of the transactions in a meeting." t)
1046
1047(autoload 'discuss-list-acl (concat discuss-source-dir "discuss-acl")
1048          "List the ACL of a meeting." t)
1049
1050(autoload 'discuss-forward (concat discuss-source-dir "discuss-misc")
1051          "Forward a transaction via mail." t)
1052
1053(autoload 'discuss-forward-to-meeting
1054          (concat discuss-source-dir "discuss-misc")
1055          "Forward a transaction to another discuss meeting." t)
1056
1057(autoload 'discuss-reply-by-mail (concat discuss-source-dir "discuss-misc")
1058          "Forward a transaction via mail." t)
1059
1060(autoload 'discuss-add-mtg (concat discuss-source-dir "discuss-misc")
1061          "Add a discuss meeting" t)
1062
1063(autoload 'discuss-del-mtg (concat discuss-source-dir "discuss-misc")
1064          "Delete a discuss meeting" t)
1065
1066;;; Keymaps, here at the end, where the trash belongs..
1067
1068(if discuss-mtgs-mode-map
1069    nil
1070  (setq discuss-mtgs-mode-map (make-keymap))
1071  (suppress-keymap discuss-mtgs-mode-map)
1072  (define-key discuss-mtgs-mode-map "a" 'discuss-add-mtg)
1073  (define-key discuss-mtgs-mode-map "d" 'discuss-del-mtg)
1074  (define-key discuss-mtgs-mode-map "n" 'discuss-forward-meeting)
1075  (define-key discuss-mtgs-mode-map "p" 'discuss-prev-meeting)
1076  (define-key discuss-mtgs-mode-map " " 'discuss-next-meeting)
1077  (define-key discuss-mtgs-mode-map "\177" 'discuss-prev-meeting)
1078  (define-key discuss-mtgs-mode-map "l" 'discuss-lsm)
1079  (define-key discuss-mtgs-mode-map "g" 'discuss-goto)
1080  (define-key discuss-mtgs-mode-map "q" 'discuss-quit)
1081  (define-key discuss-mtgs-mode-map "s" 'discuss-stat)
1082  (define-key discuss-mtgs-mode-map "c" 'discuss-catchup)
1083  (define-key discuss-mtgs-mode-map "?" 'describe-mode))
1084
1085(if discuss-trn-mode-map
1086    nil
1087  (setq discuss-trn-mode-map (make-keymap))
1088  (suppress-keymap discuss-trn-mode-map)
1089  (define-key discuss-trn-mode-map "." 'discuss-update)
1090  (define-key discuss-trn-mode-map "," 'discuss-show-trn-with-headers)
1091  (define-key discuss-trn-mode-map " " 'discuss-scroll-up)
1092  (define-key discuss-trn-mode-map "\177" 'scroll-down)
1093  (define-key discuss-trn-mode-map "n" 'discuss-next-trn)
1094  (define-key discuss-trn-mode-map "p" 'discuss-prev-trn)
1095  (define-key discuss-trn-mode-map "d" 'discuss-delete-trn)
1096  (define-key discuss-trn-mode-map "R" 'discuss-retrieve-trn)
1097  (define-key discuss-trn-mode-map "\M-n" 'discuss-nref)
1098  (define-key discuss-trn-mode-map "\M-p" 'discuss-pref)
1099  (define-key discuss-trn-mode-map "g" 'discuss-show-trn)
1100  (define-key discuss-trn-mode-map "<" 'discuss-first-trn)
1101  (define-key discuss-trn-mode-map ">" 'discuss-last-trn)
1102  (define-key discuss-trn-mode-map "f" 'discuss-forward)
1103  (define-key discuss-trn-mode-map "F" 'discuss-toggle-trn-flag)
1104  (define-key discuss-trn-mode-map "h" 'discuss-trn-summary)
1105  (define-key discuss-trn-mode-map "\e\C-h" 'discuss-trn-summary)
1106  (define-key discuss-trn-mode-map "t" 'discuss-talk)
1107  (define-key discuss-trn-mode-map "r" 'discuss-reply)
1108  (define-key discuss-trn-mode-map "\C-c\C-r" 'discuss-randrp)
1109  (define-key discuss-trn-mode-map "\M-r" 'discuss-reply-by-mail)
1110  (define-key discuss-trn-mode-map "\C-o" 'discuss-trn-output)
1111  (define-key discuss-trn-mode-map "i" 'discuss-trn-input)
1112  (define-key discuss-trn-mode-map "q" 'discuss-leave-mtg)
1113  (define-key discuss-trn-mode-map "?" 'describe-mode)
1114  (define-key discuss-trn-mode-map "s" 'discuss-stat)
1115  (define-key discuss-trn-mode-map "a" 'discuss-add-mtg)
1116  (define-key discuss-trn-mode-map "\C-d" 'discuss-delete-trn-backwards)
1117  (define-key discuss-trn-mode-map "\M-f" 'discuss-fref)
1118  (define-key discuss-trn-mode-map "\M-l" 'discuss-lref)
1119  (define-key discuss-trn-mode-map "=" 'discuss-ls)
1120  (define-key discuss-trn-mode-map "c" 'discuss-catchup)
1121  (define-key discuss-trn-mode-map "l" 'discuss-set-seen-and-leave-mtg)
1122)
1123
1124
1125  (fmakunbound 'discuss-initialize)
1126  )                                     ;end of discuss-initialize
1127(discuss-initialize)
1128
1129;;; discuss-trn-output mostly stolen from rmail-output...
1130;;; converted by [eichin:19881026.1505EST]
1131;(defvar discuss-output-last-file nil
1132;  "*Default file for discuss saves")
1133
1134(defun discuss-trn-output (file-name)
1135  "Append this message to file named FILE-NAME."
1136  (interactive
1137   (list
1138    (read-file-name
1139     (concat "Append to: (default "
1140             (file-name-nondirectory discuss-output-last-file)
1141             ") ")
1142     (file-name-directory discuss-output-last-file)
1143     discuss-output-last-file)))
1144  (setq file-name (expand-file-name file-name))
1145  (setq discuss-output-last-file file-name)
1146  (let ((discuss-trn-buf (current-buffer))
1147        (tembuf (get-buffer-create " discuss-trn-output"))
1148        (case-fold-search t))
1149    (save-excursion
1150      (set-buffer tembuf)
1151      (erase-buffer)
1152      (insert-buffer-substring discuss-trn-buf)
1153      (goto-char (point-max))
1154      (insert "\n")                    ;other modifying here as well
1155      (append-to-file (point-min) (point-max) file-name))
1156    (kill-buffer tembuf)))
1157
1158;;;
1159;;; this is just a quick hack, but I don't see an `better' way to do it...
1160;;;
1161(defun discuss-next-meeting (&optional quiet dontgo)
1162  "Find the next changed meeting in the discuss *meetings* buffer, or wrap."
1163  (interactive)
1164  (let ((buffer (current-buffer)))
1165    (set-buffer discuss-main-buffer)
1166    ;; If we're in DWIM mode, and we're currently looking at a changed
1167    ;; meeting, go to it.
1168    (if (and discuss-DWIM
1169             (not dontgo)
1170             (re-search-backward "^ c" (save-excursion (beginning-of-line)
1171                                                       (point))
1172                                 t))
1173        (discuss-goto)
1174      (if (not (re-search-forward "^ c " nil t))
1175          (progn
1176            (goto-char (point-min))
1177            (if (not (re-search-forward "^ c " nil t))
1178                (if (not quiet)
1179                    (message "No new meetings, try discuss-lsm instead."))
1180              ))))
1181    (set-buffer buffer)))
1182
1183(defun discuss-forward-meeting (&optional quiet)
1184  "Find the next changed meeting in the discuss *meetings* buffer, or wrap."
1185  (interactive)
1186  (let ((discuss-DWIM nil))
1187    (discuss-next-meeting quiet)))
1188
1189(defun discuss-prev-meeting ()
1190  "Find the previous changed meeting in the discuss *meetings* buffer, or wrap."
1191  (interactive)
1192  (beginning-of-line)
1193  (if (not (re-search-backward "^ c " nil t))
1194      (progn
1195        (goto-char (point-max))
1196        (if (not (re-search-backward "^ c " nil t))
1197            (message "No new meetings, try discuss-lsm instead.")
1198          )))
1199  (forward-char 3))
1200
1201(defun discuss-mark-read-meeting (meeting &optional inschar)
1202  "Mark a meeting as read on the discuss-mode listing.  An optional
1203argument means insert that character instead of a space before the
1204meeting (usually a c)."
1205  (setq inschar (or inschar ?\ ))
1206  (save-excursion
1207    (set-buffer discuss-main-buffer)
1208    (goto-char (point-min))
1209    (if (not (re-search-forward (concat " " (regexp-quote meeting)
1210                                        "\\(,\\|$\\)")
1211                             nil t))
1212        (progn
1213          (ding)
1214          (message "Couldn't update changed flag for meeting %s." meeting))
1215      (beginning-of-line)
1216      (forward-char 1)
1217      (let ((buffer-read-only nil))
1218        (insert-char inschar 1)
1219        (delete-char 1)
1220        ))))
1221
1222(defun discuss-mark-unread-meeting (meeting)
1223  "Mark a meeting as unread on the discuss-mode listing."
1224  (discuss-mark-read-meeting meeting ?c))
Note: See TracBrowser for help on using the repository browser.