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 |
---|
20 | the trailing `/'. It must end with `/', since it will be directly |
---|
21 | concatenated to other file names. Setting this to nil or an empty string |
---|
22 | will 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 |
---|
29 | repeatedly 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 |
---|
33 | discuss-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 |
---|
37 | In-Reply-To field, rather than using the discuss convention of |
---|
38 | In-Reply-To: [###] in Meeting.") |
---|
39 | |
---|
40 | (defvar discuss-auto-reply-to-alist nil |
---|
41 | "Association list of discuss meeting names (long forms) and default |
---|
42 | Reply-To addresses that should be inserted into replies by mail (to help |
---|
43 | ensure 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 |
---|
53 | meetings fed by mailing lists. If nil, the value of discuss-invisible-headers |
---|
54 | is used instead.") |
---|
55 | |
---|
56 | (defvar discuss-invisible-headers "^From \\|^Received:" |
---|
57 | "If discuss-visible-headers is nil, discuss-invisible-headers is a regexp |
---|
58 | matching the mail headers to be not shown by default in discuss meetings |
---|
59 | fed by mailing lists.") |
---|
60 | |
---|
61 | (defvar discuss-keep-discuss-ls nil |
---|
62 | "If nil, windows containing *discuss-ls* buffers will be deleted when |
---|
63 | leaving 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 |
---|
67 | meeting. 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 |
---|
80 | meetings.") |
---|
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 |
---|
114 | transaction buffer. Nil means this buffer is not a discuss-transaction |
---|
115 | buffer.") |
---|
116 | |
---|
117 | (defvar discuss-meeting-info nil |
---|
118 | "Buffer-local variable containing the info struction for the discuss |
---|
119 | transaction 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 | |
---|
130 | Currently 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 |
---|
136 | request 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. |
---|
145 | This looks a lot like RMAIL. This works by using ``edsc'' as a subjob. |
---|
146 | |
---|
147 | The 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 |
---|
169 | discuss 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 |
---|
186 | discuss subsystem. |
---|
187 | All normal editing commands are turned off. |
---|
188 | Instead, 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 |
---|
702 | the 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 | |
---|
899 | Flushes 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. |
---|
960 | If VERBOSE is non-nil, then print a message that we're waiting for the |
---|
961 | discuss 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 |
---|
1203 | argument means insert that character instead of a space before the |
---|
1204 | meeting (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)) |
---|