edit-text.el 61.9 KB
Newer Older
1
;;;;; -*-coding: raw-text;-*-
Linus Tolke's avatar
Linus Tolke committed
2
3
;;;;;
;;;;; $Id$
4
;;;;; Copyright (C) 1991, 1996  Lysator Academic Computer Association.
Linus Tolke's avatar
Linus Tolke committed
5
6
7
8
9
;;;;;
;;;;; This file is part of the LysKOM server.
;;;;; 
;;;;; LysKOM is free software; you can redistribute it and/or modify it
;;;;; under the terms of the GNU General Public License as published by 
10
;;;;; the Free Software Foundation; either version 2, or (at your option) 
Linus Tolke's avatar
Linus Tolke committed
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
;;;;; any later version.
;;;;; 
;;;;; LysKOM is distributed in the hope that it will be useful, but WITHOUT
;;;;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
;;;;; FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
;;;;; for more details.
;;;;; 
;;;;; You should have received a copy of the GNU General Public License
;;;;; along with LysKOM; see the file COPYING.  If not, write to
;;;;; Lysator, c/o ISY, Linkoping University, S-581 83 Linkoping, SWEDEN,
;;;;; or the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, 
;;;;; MA 02139, USA.
;;;;;
;;;;; Please mail bug reports to bug-lyskom@lysator.liu.se. 
;;;;;
Per Cederqvist's avatar
.    
Per Cederqvist committed
26
27
28
29
30
31
32
33
34
;;;; ================================================================
;;;; ================================================================
;;;;
;;;; File: edit-text.el
;;;;
;;;; This file contains functions which lets the LysKOM user edit
;;;; a text in a window. It also defines a new mode - lyskom-edit-mode.
;;;;

35
36
37
38
39
(setq lyskom-clientversion-long 
      (concat lyskom-clientversion-long
	      "$Id$\n"))


Per Cederqvist's avatar
.    
Per Cederqvist committed
40
41
;;;; ================================================================

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
;;; Set variables to make lyskom-edit-mode a minor mode. This
;;; simplifies some stuff a lot

(defvar lyskom-edit-mode nil
  "Mode variable for lyskom-edit-mode")
(make-variable-buffer-local 'lyskom-edit-mode)

(defvar lyskom-edit-sending-mode nil
  "Mode variable for lyskom-edit-sending-mode")
(make-variable-buffer-local 'lyskom-edit-sending-mode)

(defvar lyskom-edit-sent-mode nil
  "Mode variable for lyskom-edit-sent-mode")
(make-variable-buffer-local 'lyskom-edit-sent-mode)

(put 'lyskom-edit-mode 'permanent-local t)

(or (assq 'lyskom-edit-mode minor-mode-alist)
    (setq minor-mode-alist (cons '(lyskom-edit-mode " LysKOM Edit")
                                 minor-mode-alist)))

(or (assq 'lyskom-edit-sending-mode minor-mode-alist)
    (setq minor-mode-alist (cons '(lyskom-edit-sending-mode " LysKOM Sending")
                                 minor-mode-alist)))

(or (assq 'lyskom-edit-sent-mode minor-mode-alist)
    (setq minor-mode-alist (cons '(lyskom-edit-sent-mode " LysKOM Sent")
                                 minor-mode-alist)))

(or (assq 'lyskom-edit-mode minor-mode-map-alist)
    (setq minor-mode-map-alist
	  (cons (cons 'lyskom-edit-mode lyskom-edit-mode-map)
		minor-mode-map-alist)))

(or (assq 'lyskom-edit-sending-mode minor-mode-map-alist)
    (setq minor-mode-map-alist
	  (cons (cons 'lyskom-edit-sending-mode lyskom-edit-mode-map)
		minor-mode-map-alist)))

(or (assq 'lyskom-edit-sent-mode minor-mode-map-alist)
    (setq minor-mode-map-alist
	  (cons (cons 'lyskom-edit-sending-mode lyskom-edit-mode-map)
		minor-mode-map-alist)))


Per Cederqvist's avatar
.    
Per Cederqvist committed
87
88
89
90

(defvar lyskom-edit-mode-name "LysKOM edit"
  "Name of the mode.")

91
92
93
(defvar lyskom-edit-text-sent nil
  "Non-nil when a text has been sent")

Linus Tolke's avatar
Linus Tolke committed
94
95
96
97
98
99
100
101
102
103
104
105
106
107
(defvar lyskom-is-dedicated-edit-window nil
  "Status variable for an edit-window.")

(defvar lyskom-edit-handler nil
  "Status variable for an edit-buffer.
See lyskom-edit-handler-data.")

(defvar lyskom-edit-handler-data nil
  "Status variable for an edit-buffer.
See lyskom-edit-handler.")

(defvar lyskom-edit-return-to-configuration nil
  "Status variable for an edit-buffer.")

108
;;; Error signaled by lyskom-edit-parse-headers
109
(put 'lyskom-edit-text-abort 'error-conditions
110
     '(error lyskom-error lyskom-edit-error lyskom-edit-text-abort))
111

112
(put 'lyskom-unknown-header 'error-conditions
113
     '(error lyskom-error lyskom-edit-error lyskom-unknown-header))
114
115

(put 'lyskom-no-subject 'error-conditions
116
     '(error lyskom-error lyskom-edit-error lyskom-no-subject))
David Byers's avatar
David Byers committed
117

118
119
120
(put 'lyskom-edit-error 'error-conditions
     '(error lyskom-error lyskom-edit-error))

Per Cederqvist's avatar
.    
Per Cederqvist committed
121
122
123
124
125
126
127
128
129
130
131
132
133
(defun lyskom-edit-text (proc misc-list subject body
			      &optional handler &rest data)
  "Edit a text in a new buffer.
PROC is the associated process.
MISC-LIST is the default misc-list.
SUBJECT is subject (a string).
BODY is the default text-body (a string, normally empty.)
HANDLER is a function to call when the text has been created.
DATA is extra data to send to the function. HANDLER is called with
	(apply HANDLER text-no DATA)
where text-no is the number of the text.
Does lyskom-end-of-command."
  (setq lyskom-is-writing t)
134
  (lyskom-dispatch-edit-text proc misc-list subject body
135
                             handler data))
136
137
138
139


(defun lyskom-dispatch-edit-text (proc misc-list subject body
				       &optional handler &rest data)
140
  "Same as lyskom-edit-text except that it doesn't set lyskom-is-writing."
David Byers's avatar
X    
David Byers committed
141
142
143
144
  (let ((buffer (lyskom-get-buffer-create 'write-texts
                                          (concat 
                                           (buffer-name (process-buffer proc))
                                           "-edit")))
Per Cederqvist's avatar
.    
Per Cederqvist committed
145
	(config (current-window-configuration)))
David Byers's avatar
X    
David Byers committed
146
147

    (lyskom-display-buffer buffer)
148
149
150
    (text-mode)
    (lyskom-ignore-errors
      (run-hooks 'lyskom-edit-mode-mode-hook))
David Byers's avatar
X    
David Byers committed
151
    (lyskom-edit-mode)
Per Cederqvist's avatar
.    
Per Cederqvist committed
152
153
154
155
156
157
    (make-local-variable 'lyskom-edit-handler)
    (make-local-variable 'lyskom-edit-handler-data)
    (make-local-variable 'lyskom-edit-return-to-configuration)
    (setq lyskom-edit-handler handler)
    (setq lyskom-edit-handler-data data)
    (setq lyskom-edit-return-to-configuration config)
David Byers's avatar
David Byers committed
158
    (buffer-disable-undo)
Per Cederqvist's avatar
.    
Per Cederqvist committed
159
    (lyskom-edit-insert-miscs misc-list subject body)
David Byers's avatar
David Byers committed
160
    (buffer-enable-undo)
161
    (goto-char (point-min))
162
163
    (re-search-forward (regexp-quote (lyskom-get-string
				      'header-subject))
164
165
		       (point-max)
		       'end)
166
167
    (if (not (looking-at "\\s-*$"))
        (goto-char (point-max)))
168
    (lyskom-message "%s" (lyskom-get-string 'press-C-c-C-c)))
David Byers's avatar
David Byers committed
169
  (set-buffer lyskom-buffer)
Linus Tolke's avatar
Linus Tolke committed
170
  )
Per Cederqvist's avatar
.    
Per Cederqvist committed
171
172


David Byers's avatar
David Byers committed
173

174
(defun lyskom-edit-insert-miscs (misc-list subject body &optional aux-list)
Per Cederqvist's avatar
.    
Per Cederqvist committed
175
176
177
  "Insert MISC-LIST into header of text.
recpt		-> Mottagare: <%d> %s.
cc-recpt	-> Extra kopia: <%d> %s.
David Byers's avatar
David Byers committed
178
bcc-recpt       -> Fr knnedom: <%d> %s.
Per Cederqvist's avatar
.    
Per Cederqvist committed
179
180
181
182
comm-to		-> Kommentar till text %d.
footn-to	-> Fotnot till text %d."
  (let ((edit-buffer (current-buffer))
	(where-put-misc (point-min-marker))
David Byers's avatar
David Byers committed
183
	(main-buffer lyskom-buffer))
Per Cederqvist's avatar
.    
Per Cederqvist committed
184
185
186
187
188
189
190
    (set-buffer main-buffer)
    (setq misc-list (cdr misc-list))
    (while (not (null misc-list))
      (let ((key (car (car misc-list)))
	    (data (cdr (car misc-list))))
	(cond
	 ((eq key 'recpt)
191
192
193
	  (lyskom-edit-insert-misc-conf (blocking-do 'get-conf-stat data)
					(lyskom-get-string 'recipient)
					where-put-misc data))
Per Cederqvist's avatar
.    
Per Cederqvist committed
194
	 ((eq key 'cc-recpt)
195
196
197
	  (lyskom-edit-insert-misc-conf (blocking-do 'get-conf-stat data)
					(lyskom-get-string 'carbon-copy)
					where-put-misc data))
David Byers's avatar
David Byers committed
198
199
200
201
	 ((eq key 'bcc-recpt)
	  (lyskom-edit-insert-misc-conf (blocking-do 'get-conf-stat data)
					(lyskom-get-string 'blank-carbon-copy)
					where-put-misc data))
Per Cederqvist's avatar
.    
Per Cederqvist committed
202
	 ((eq key 'comm-to)
203
204
205
	  (lyskom-edit-get-commented-author (blocking-do 'get-text-stat data)
					    (lyskom-get-string 'comment)
					    where-put-misc data))
Per Cederqvist's avatar
.    
Per Cederqvist committed
206
	 ((eq key 'footn-to)
207
208
209
210
	  (lyskom-edit-get-commented-author (blocking-do 'get-text-stat data)
					    (lyskom-get-string 'footnote)
					    where-put-misc data)))
	(setq misc-list (cdr misc-list))))
211
212
213
214
    (mapcar (function
             (lambda (item)
               (let ((data (lyskom-aux-item-definition-call
                            item '(edit-insert print)
David Byers's avatar
David Byers committed
215
                            item lyskom-pers-no)))
216
217
218
219
220
                 (when data
                   (lyskom-princ
                    (concat (lyskom-get-string 'aux-item-prefix) data "\n")
                    where-put-misc)))))
            aux-list)
221
    (princ (lyskom-format 'text-mass subject 
222
223
			  (substitute-command-keys
			   (lyskom-get-string 'header-separator))
224
			  body 
225
			  (lyskom-get-string 'header-subject))
226
227
228
229
	   where-put-misc)
    (set-buffer edit-buffer)
    (goto-char where-put-misc)
    ))
Per Cederqvist's avatar
.    
Per Cederqvist committed
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245


(defun lyskom-edit-goto-char (marker)
  "Positions the editing at MARKER."
  (let ((curbuf (current-buffer)))
    (set-buffer (marker-buffer marker))
    (save-window-excursion
      (goto-char marker))
    (set-buffer curbuf)))


(defun lyskom-edit-insert-misc-conf (conf-stat string stream number)
  "Insert Mottagare: or Extra kopia: in edit-buffer.
Args: CONF-STAT STRING STREAM NUMBER
CONF-STAT is the conf-stat of the conference that is about to be put in,
STRING is the string that is inserted.
246
STREAM is the buffer or a marker telling the position.
Per Cederqvist's avatar
.    
Per Cederqvist committed
247
NUMBER is the number of the person. Used if the conf-stat is nil."
David Byers's avatar
X    
David Byers committed
248
249
250
251
252
  (lyskom-princ  (lyskom-format "%#1s <%#2m> %#3M\n" 
                                string
                                (or conf-stat number)
                                (or conf-stat ""))
                 stream))
Per Cederqvist's avatar
.    
Per Cederqvist committed
253
254
255
256


(defun lyskom-edit-get-commented-author (text-stat string stream number)
  (if text-stat
257
258
259
      (lyskom-edit-insert-commented-author 
       (blocking-do 'get-conf-stat (text-stat->author text-stat))
       string stream number)
Per Cederqvist's avatar
.    
Per Cederqvist committed
260
261
262
263
    (lyskom-edit-insert-commented-author nil string stream number)))


(defun lyskom-edit-insert-commented-author (conf-stat string stream number)
David Byers's avatar
X    
David Byers committed
264
265
266
267
268
269
270
271
  (lyskom-princ (lyskom-format 'comment-to-by
                               string
                               number
                               (if conf-stat
                                   (lyskom-format 'by conf-stat)
                                 ""))
                stream))

David Kågedal's avatar
David Kågedal committed
272

Per Cederqvist's avatar
.    
Per Cederqvist committed
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289


(defun lyskom-create-misc-list (&rest misc-pairs)
  "Create a misc-list.
Note that a misc-list is very different from a misc-info-list.
A misc-list is used when creating a new text, and sent to the server.
A misc-info-list is what is received from the server. Although the server
has the same format for the two things, this client uses two quite
different formats.

The arguments to this function is any number of pairs of data. The first
item in each pair should be one of recpt, cc-recpt, comm-to or footn-to.
The second item should be the corresponding conf- or text-no.

The result is a list of dotted pairs:
	('recpt . conf-no)
	('cc-recpt . conf-no)
David Byers's avatar
David Byers committed
290
	('bcc-recpt . conf-no)
Per Cederqvist's avatar
.    
Per Cederqvist committed
291
292
293
	('comm-to . text-no)
	('footn-to . text-no).
First element is a type-tag."
David Byers's avatar
David Byers committed
294
   (let ((result (cons 'MISC-LIST nil)))
Per Cederqvist's avatar
.    
Per Cederqvist committed
295
296
297
298
299
300
301
302
303
304
305
    (while (not (null misc-pairs))
      (nconc result (cons (cons (car misc-pairs)
				(car (cdr misc-pairs)))
			  nil))
      (setq misc-pairs (cdr (cdr misc-pairs))))
    result))


;;; ================================================================
;;;                   lyskom-edit-mode

Linus Tolke's avatar
Linus Tolke committed
306
307
308
309
310
311
(defvar lyskom-edit-mode-hook nil
  "*List of functions to be called when entering lyskom-edit-mode.
Watch out! None of these functions are allowed to do kill-all-local-variables
because kom-edit-send and other functions depend on some variables to be able
to enter the text in the correct lyskom-process.")

312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
(defvar lyskom-edit-mode-mode-hook nil
  "*List of functions to be called when entering lyskom-edit-mode.
Watch out! None of these functions are allowed to do kill-all-local-variables
because kom-edit-send and other functions depend on some variables to be able
to enter the text in the correct lyskom-process.

This one differs from lyskom-edit-mode-hook in that it is called before
the lyskom-special key bindings are added.")


;;;(defun lyskom-edit-mode ()
;;;  "\\<lyskom-edit-mode-map>Mode for editing texts for LysKOM.
;;;Commands:
;;;\\[kom-edit-send]   sends the text when you are ready. The buffer will be
;;;          deleted if (and only if) the server accepts the text.
;;;\\[kom-edit-quit]   aborts the editing. You will get back to the LysKOM buffer.
;;;
;;;\\[kom-edit-show-commented]   shows the commented text in a temporary buffer.
;;;
;;;\\[kom-edit-add-recipient]   asks for another recipient and adds him to the header.
;;;\\[kom-edit-add-copy]   as \\[kom-edit-add-recipient] but adds him as copy-recipient.
;;;
;;;\\[kom-edit-insert-commented]   inserts the commented of footnoted text.
;;;\\[kom-edit-insert-text]   inserts the shown text, you tell the number."
;;;  (interactive)
;;;  (let ((tmp-keymap nil))
;;;    (kill-all-local-variables)
;;;    (text-mode)
;;;
;;;    (run-hooks 'lyskom-edit-mode-mode-hook)
;;;
;;;    (setq tmp-keymap (and (current-local-map)
;;;                          (copy-keymap (current-local-map))))
;;;
;;;    (lyskom-set-menus 'lyskom-edit-mode lyskom-edit-mode-map)
;;;    (setq mode-line-buffer-identification '("LysKOM (server: %b)"))
;;;    (setq major-mode 'lyskom-edit-mode)
;;;    (setq mode-name lyskom-edit-mode-name)
;;;
;;;    (if tmp-keymap
;;;        (let ((new-keymap (make-sparse-keymap)))
;;;          (make-local-variable 'lyskom-edit-mode-map)
;;;          (setq lyskom-edit-mode-map 
;;;                (lyskom-default-value 'lyskom-edit-mode-map))
;;;
;;;          (lyskom-xemacs-or-gnu
;;;           (set-keymap-parents new-keymap
;;;                               (list lyskom-edit-mode-map
;;;                                     tmp-keymap))
;;;           (progn (set-keymap-parent new-keymap lyskom-edit-mode-map)
;;;                  (lyskom-overlay-keymap lyskom-edit-mode-map
;;;                                         tmp-keymap
;;;                                         new-keymap)))
;;;          (use-local-map new-keymap))
;;;
;;;      (lyskom-use-local-map lyskom-edit-mode-map))
;;;    
;;;
;;;    (auto-save-mode 1)
;;;    (auto-fill-mode 1)
;;;    (make-local-variable 'paragraph-start)
;;;    (make-local-variable 'paragraph-separate)
;;;    (setq paragraph-start (concat "^" 
;;;                                  (regexp-quote 
;;;                                   (substitute-command-keys
;;;                                    (lyskom-get-string 'header-separator)))
;;;                                  "$\\|" paragraph-start))
;;;    (setq paragraph-separate (concat "^" 
;;;                                     (regexp-quote 
;;;                                      (substitute-command-keys
;;;                                       (lyskom-get-string 'header-separator)))
;;;                                     "$\\|" paragraph-separate))
;;;    (run-hooks 'lyskom-edit-mode-hook)))


(defun lyskom-edit-mode (&optional arg)
Per Cederqvist's avatar
.    
Per Cederqvist committed
388
389
  "\\<lyskom-edit-mode-map>Mode for editing texts for LysKOM.
Commands:
Linus Tolke's avatar
Linus Tolke committed
390
391
392
393
394
395
396
397
398
399
\\[kom-edit-send]   sends the text when you are ready. The buffer will be
	  deleted if (and only if) the server accepts the text.
\\[kom-edit-quit]   aborts the editing. You will get back to the LysKOM buffer.

\\[kom-edit-show-commented]   shows the commented text in a temporary buffer.

\\[kom-edit-add-recipient]   asks for another recipient and adds him to the header.
\\[kom-edit-add-copy]   as \\[kom-edit-add-recipient] but adds him as copy-recipient.

\\[kom-edit-insert-commented]   inserts the commented of footnoted text.
400
401
402
403
404
405
406
407
408
409
\\[kom-edit-insert-text]   inserts the shown text, you tell the number.

Even though this is a minor mode, it's not intended to be turned on and off,
so it's not as clean as it ought to be."
  (interactive "P")
  (setq lyskom-edit-mode
        (if (null arg)
            (not lyskom-edit-mode)
          (> (prefix-numeric-value arg) 0)))

410
411
  (lyskom-set-menus 'lyskom-edit-mode lyskom-edit-mode-map)

412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
  (when lyskom-edit-mode
    (lyskom-edit-sending-mode 0)
    (lyskom-edit-sent-mode 0)
    (auto-fill-mode 1)
    (auto-save-mode 1)
    (when (not (local-variable-p 'lyskom-edit-text-sent (current-buffer)))
      (make-local-variable 'lyskom-edit-text-sent)
      (setq lyskom-edit-text-sent nil))
    (make-local-variable 'paragraph-start)
    (make-local-variable 'paragraph-separate)
    (setq paragraph-start (concat "^" 
                                  (regexp-quote 
                                   (substitute-command-keys
                                    (lyskom-get-string 'header-separator)))
                                  "$\\|" paragraph-start))
    (setq paragraph-separate (concat "^" 
                                     (regexp-quote 
                                      (substitute-command-keys
                                       (lyskom-get-string 'header-separator)))
                                     "$\\|" paragraph-separate))
432
433
434
435
    (make-local-variable 'comment-start)
    (make-local-variable 'comment-end)
    (setq comment-start kom-cite-string
	  comment-end "")
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
    (run-hooks 'lyskom-edit-mode-hook)))

(defun lyskom-edit-sending-mode (arg)
  (interactive "P")
  (setq lyskom-edit-sending-mode 
        (if (null arg)
            (not lyskom-edit-sending-mode)
          (> (prefix-numeric-value arg) 0)))

  (when lyskom-edit-sending-mode
    (lyskom-edit-mode 0)
    (lyskom-edit-sent-mode 0)))

(defun lyskom-edit-sent-mode (arg)
  (interactive "P")
  (setq lyskom-edit-sent-mode 
        (if (null arg)
            (not lyskom-edit-sent-mode)
          (> (prefix-numeric-value arg) 0)))

  (when lyskom-edit-sent-mode
    (lyskom-edit-sending-mode 0)
    (lyskom-edit-mode 0)))
Per Cederqvist's avatar
.    
Per Cederqvist committed
459
460
461
462
463
464


;;; ================================================================
;;;   Functions bound to keyboard seqences in lyskom-edit-mode
;;;

465
466
467
(defun kom-edit-send-anonymous ()
  "Send the text anonymously to the server."
  (interactive)
468
  (lyskom-edit-send 'initiate-create-anonymous-text nil))
Per Cederqvist's avatar
.    
Per Cederqvist committed
469
470
471
472

(defun kom-edit-send ()
  "Send the text to the server."
  (interactive)
David Byers's avatar
David Byers committed
473
474
   (if (and (lyskom-default-value 'lyskom-is-anonymous)
            (lyskom-j-or-n-p 'do-send-anonymous t))
David Byers's avatar
David Byers committed
475
476
       (lyskom-edit-send 'initiate-create-anonymous-text t)
     (lyskom-edit-send 'initiate-create-text nil)))
477

478
479
480
481
(defun lyskom-edit-send (send-function &optional is-anonymous)
  "Send the text to the server by calling SEND-FUNCTION.
If optional IS-ANONYMOUS is non-nil, assume that the text is being submitted
anonymously and take actions to avoid revealing the sender."
482
  (condition-case err
483
      (if (or (not lyskom-edit-text-sent) ;++MINOR checked mode-name against lyskom-edit-mode-name
David Byers's avatar
David Byers committed
484
485
486
	      (j-or-n-p (lyskom-get-string 'already-sent)))
	  (progn 
	    (let ((buffer (current-buffer))
487
488
489
490
491
		  (headers nil)
                  (misc-list nil)
                  (subject nil)
                  (message nil)
                  (aux-list nil))
David Byers's avatar
David Byers committed
492
493
494

	      (save-excursion
		(setq headers (lyskom-edit-parse-headers)
495
496
497
		      misc-list (apply 'lyskom-create-misc-list 
                                       (elt headers 1))
                      aux-list (elt headers 2)
David Byers's avatar
David Byers committed
498
		      subject (car headers)))
David Byers's avatar
David Byers committed
499
500

              ;;
501
502
503
              ;; Check that there is a subject
              ;;

David Byers's avatar
David Byers committed
504
505
	      (if (or (null subject)
                      (string= subject ""))
David Byers's avatar
David Byers committed
506
507
		  (let ((old (point)))
		    (goto-char (point-min))
508
		    (re-search-forward (lyskom-get-string 'header-subject)
David Byers's avatar
David Byers committed
509
510
511
				       nil t)
		    (end-of-line)
		    (if (/= (point) old)
512
			(signal 'lyskom-no-subject '(enter-subject-idi)))))
513
514
515
516
517
518
519
520
521
522

              ;;
              ;; Check the recipients
              ;;

              (let ((extra-headers
                     (lyskom-edit-send-check-recipients misc-list
                                                        subject)))
                (if extra-headers
                    (setq misc-list (apply 'lyskom-create-misc-list
523
524
                                           (nconc (elt headers 1)
						  extra-headers)))))
525

David Byers's avatar
David Byers committed
526
527
528
529
530
531
532
533
              ;;
              ;; Run user hooks
              ;; ####: ++++: FIXME: We should quit more graciously.

              (if (not (run-hook-with-args-until-failure 
                        'lyskom-send-text-hook))
                  (signal 'lyskom-edit-text-abort nil))
                                                
534
535
536
537
              ;;
              ;; Transform the message text
              ;;

538
	      (setq message
David Byers's avatar
David Byers committed
539
540
541
542
                    (if (fboundp lyskom-send-text-transform-function)
                        (funcall lyskom-send-text-transform-function
                                 (lyskom-edit-extract-text))
                      (lyskom-edit-extract-text)))
543

544
545
;++MINOR	      (setq mode-name "LysKOM sending")
              (lyskom-edit-sending-mode 1)
David Byers's avatar
David Byers committed
546
	      (save-excursion
David Byers's avatar
David Byers committed
547
548
                (let ((full-message
                       (cond ((and lyskom-allow-missing-subject
549
550
                                   (or (null subject)
                                       (string= subject ""))
David Byers's avatar
David Byers committed
551
552
553
554
                                   (not (string-match ".*\n" message)))
                              message)
                             (t (concat (or subject "") "\n" message)))))

David Byers's avatar
David Byers committed
555
		(set-buffer lyskom-buffer)
David Byers's avatar
David Byers committed
556
		;; Don't change the prompt if we won't see our own text
David Byers's avatar
David Byers committed
557
		(if (and kom-created-texts-are-read
558
                         (not is-anonymous))
David Byers's avatar
David Byers committed
559
560
561
		    (setq lyskom-dont-change-prompt t))
		(setq lyskom-is-writing nil)
		(lyskom-tell-internat 'kom-tell-send)
David Byers's avatar
David Byers committed
562
		(funcall send-function
563
564
                         'sending
                         'lyskom-create-text-handler
David Byers's avatar
David Byers committed
565
                         full-message
566
                         misc-list
567
568
569
570
571
572
573
574
                         (unless is-anonymous
                           (cons (lyskom-create-aux-item
                                  0 15 0 0
                                  (lyskom-create-aux-item-flags
                                   nil nil nil nil nil nil nil nil)
                                  0 (concat "lyskom.el "
                                            lyskom-clientversion))
                                 aux-list))
David Byers's avatar
David Byers committed
575
                         buffer
576
                         is-anonymous))))
David Byers's avatar
David Byers committed
577
            (lyskom-undisplay-buffer)
David Byers's avatar
David Byers committed
578
	    (goto-char (point-max))))
David Byers's avatar
David Byers committed
579
    ;;
580
    ;; Catch no-subject and other things
David Byers's avatar
David Byers committed
581
582
    ;;

583
    (lyskom-edit-text-abort
584
585
     (apply 'lyskom-message (cdr-safe err)))
    (lyskom-no-subject
David Byers's avatar
David Byers committed
586
     (lyskom-beep kom-ding-on-no-subject)
David Byers's avatar
David Byers committed
587
588
     (if (cdr-safe (cdr-safe err))
	 (goto-char (car-safe (cdr-safe (cdr-safe err)))))
589
     (lyskom-message "%s" (lyskom-get-string (car (cdr err))))
590
     (condition-case nil
David Byers's avatar
David Byers committed
591
592
         (let ((text ""))
           (save-excursion
David Byers's avatar
David Byers committed
593
             (set-buffer lyskom-buffer)
David Byers's avatar
David Byers committed
594
595
596
597
             (if (and (string= "kom.lysator.liu.se" lyskom-server-name)
                      (eq lyskom-pers-no 698))
                 (setq text "rende, IDI!")))
           (save-excursion (insert text)))
598
599
       (error nil)))
    (lyskom-unknown-header
600
     (lyskom-message "%s" (lyskom-get-string (car (cdr err)))))))
David Byers's avatar
David Byers committed
601

David Byers's avatar
David Byers committed
602
(eval-when-compile (defvar ispell-dictionary nil))
David Byers's avatar
David Byers committed
603
604
605
(eval-when-compile (defvar ispell-message-text-end nil))
(eval-when-compile (defvar ispell-message-start-skip nil))
(eval-when-compile (defvar ispell-message-end-skip nil))
David Byers's avatar
David Byers committed
606
607


608
609
610
611
612
613
614
(defun lyskom-ispell-text ()
  "Check spelling of the text body.
Put this in lyskom-send-text-hook"
  (kom-ispell-message)
  t)


David Byers's avatar
David Byers committed
615
616
617
618
619
620
(eval-when-compile
  (defvar ispell-dictionary nil)
  (defvar ispell-message-text-end nil)
  (defvar ispell-message-start-skip nil)
  (defvar ispell-message-end-skip nil))

621
622
623
624
625
(defun kom-ispell-message ()
  "Check spelling of the text.
kom-ispell-dictionary is the dictionary to use to check spelling.
Based on ispell-message."
  (interactive)
David Byers's avatar
David Byers committed
626
  (require 'ispell)
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
  (let ((ispell-dictionary (or kom-ispell-dictionary ispell-dictionary))
        (kill-ispell (or (not (boundp 'ispell-dictionary))
                         (not (string= kom-ispell-dictionary
                                       ispell-dictionary))))
        (result nil))
    (when kill-ispell (ispell-kill-ispell t))

    ;; Checking code

    (save-excursion
      (goto-char (point-min))
      (let* ((internal-messagep 
              (save-excursion
                (re-search-forward
                 (concat "^"
                         (regexp-quote
                          (substitute-command-keys
                           (lyskom-get-string 'header-separator)))
                         "$")
                 nil t)))
             (limit 
              (copy-marker
               (cond ((not ispell-message-text-end) (point-max))
                     ((char-or-string-p ispell-message-text-end)
                      (if (re-search-forward ispell-message-text-end nil t)
                          (match-beginning 0)
                        (point-max)))
                     (t (min (point-max) (funcall ispell-message-text-end))))))
David Byers's avatar
David Byers committed
655
656
657
             (cite-regexp 
              (regexp-quote
               (lyskom-default-value 'kom-cite-string)))
658
659
660
661
662
663
664
             (cite-regexp-start (concat "^[ \t]*$\\|" cite-regexp))
             (cite-regexp-end (concat "^\\(" cite-regexp "\\)"))
             (old-case-fold-search case-fold-search)
             (case-fold-search t)
             (ispell-checking-message t)
             (subject-string 
              (concat "^" (regexp-quote (lyskom-get-string 'subject)))))
665
        (lyskom-ignore ispell-checking-message)
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
        (goto-char (point-min))
        (while (if internal-messagep
                   (< (point) internal-messagep)
                 (not (eobp)))
          (if (looking-at subject-string)
              (progn (goto-char (match-end 0))
                     (let ((case-fold-search old-case-fold-search))
                       (ispell-region (point)
                                      (progn
                                        (end-of-line)
                                        (point)))))
            (forward-line 1)))

        (while (< (point) limit)
          (while (and (looking-at cite-regexp-start)
                      (< (point) limit)
                      (zerop (forward-line 1))))

          (if (< (point) limit)
              (let* ((start (point))
                     (end-c (and (re-search-forward cite-regexp-end limit 'end)
                                 (match-beginning 0)))
                     (end-fwd (and (goto-char start)
David Byers's avatar
David Byers committed
689
                                   (boundp 'ispell-message-start-skip)
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
                                   (re-search-forward ispell-message-start-skip
                                                      limit 'end)))
                     (end (or (and end-c end-fwd (min end-c end-fwd))
                              end-c 
                              end-fwd
                              (marker-position limit))))
                (goto-char start)
                (setq result (ispell-region start end))
                  (if (and end-fwd (= end end-fwd))
                      (progn (goto-char end)
                             (re-search-forward ispell-message-end-skip 
                                                limit 'end))
                    (goto-char end)))))
          (set-marker limit nil)
          result))

    (when kill-ispell (ispell-kill-ispell t))
    result))

709
710
711
712
713
714
715
716
717
718
719
720
(defun lyskom-is-permitted-author (conf-stat)
  (and conf-stat
       (or (eq 0 (conf-stat->permitted-submitters conf-stat))
           (lyskom-is-supervisor conf-stat))))

(defun lyskom-is-supervisor (conf-stat &optional memo)
  "Return non-nil if lyskom-pers-no is a supervisor of CONF-STAT."
  (cond ((null conf-stat) nil)
        ((memq (conf-stat->conf-no conf-stat) memo) nil)
        ((eq lyskom-pers-no (conf-stat->conf-no conf-stat)) t)
        ((eq lyskom-pers-no (conf-stat->supervisor conf-stat)) t)
        ((eq 0 (conf-stat->supervisor conf-stat)) nil)
David Byers's avatar
David Byers committed
721
        ((lyskom-get-membership (conf-stat->conf-no conf-stat) t) t)
722
723
724
725
        ((lyskom-is-supervisor
          (blocking-do 'get-conf-stat (conf-stat->supervisor conf-stat))
          (cons (conf-stat->conf-no conf-stat) memo)))))

David Byers's avatar
David Byers committed
726

727
728
729
730
731
732
733
(defun lyskom-edit-send-check-recipients (misc-list subject) 
  "Check that the recipients of this text are OK. Ask the user to
confirm multiple recipients; check that the author of the commented
text is a member of some recipient of this text."
  (let* ((comm-to-list nil)
         (recipient-list nil)
         (author-list nil)
734
         (author-is-member nil)
David Byers's avatar
David Byers committed
735
         (text-stat nil)
736
         (collector (make-collector))
737
         (extra-headers nil)
David Byers's avatar
David Byers committed
738
         (buffer (current-buffer))
David Byers's avatar
David Byers committed
739
         (me (save-excursion (set-buffer lyskom-buffer)
740
                             lyskom-pers-no))
David Byers's avatar
David Byers committed
741
742
         (num-me 0)
         (num-real-recpt 0))
743
    (lyskom-ignore text-stat)              ; Have no idea if its ever used...
744
745
746

    ;;
    ;; List all texts this text is a comment to
David Byers's avatar
David Byers committed
747
    ;; List all recipients of the text
748
749
750
751
752
753
754
    ;;

    (lyskom-traverse misc (cdr misc-list)
      (cond ((eq (car misc) 'comm-to)
             (setq comm-to-list (cons (cdr misc)
                                      comm-to-list)))
            ((or (eq (car misc) 'recpt)
David Byers's avatar
David Byers committed
755
756
                 (eq (car misc) 'cc-recpt)
                 (eq (car misc) 'bcc-recpt))
David Byers's avatar
David Byers committed
757
758
759
             (when (eq (car misc) 'recpt)
               (setq num-real-recpt (1+ num-real-recpt))
               (when (eq (cdr misc) me) (setq num-me (1+ num-me))))
760
761
             (setq recipient-list (cons (cdr misc) recipient-list)))))

David Byers's avatar
David Byers committed
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
    ;;
    ;; Check that there are recipients
    ;;

    (when (null recipient-list)
      (lyskom-error "%s" (lyskom-format 'no-recipients)))

    ;;
    ;; Check for duplicate recipients
    ;;

    (let ((tmp recipient-list))
      (while tmp
        (when (memq (car tmp) (cdr tmp))
          (lyskom-error "%s" (lyskom-format 'duplicate-recipients (car tmp))))
        (setq tmp (cdr tmp))))

David Byers's avatar
David Byers committed
779
780
781
782
783
784
785
786
787
788
789
790
791
792
    ;;
    ;; Check for new comments
    ;;

    (when (save-excursion (set-buffer lyskom-buffer)
                           (cond ((null kom-check-for-new-comments) nil)
                                 ((functionp kom-check-for-new-comments)
                                  (funcall kom-check-for-new-comments
                                           buffer misc-list subject))
                                 (t t)))
      (lyskom-message (lyskom-format 'checking-comments))
      (save-excursion
        (set-buffer lyskom-buffer)
        (set-collector->value collector nil)
793
	
David Byers's avatar
David Byers committed
794
795
796
797
798
799
800
801
802
        (mapcar (function (lambda (text-stat)
                            (cache-del-text-stat text-stat)
                            (initiate-get-text-stat 'sending 
                                                    'collector-push
                                                    text-stat
                                                    collector)))
                comm-to-list)
        (lyskom-wait-queue 'sending)
                                             
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
	(lyskom-traverse
	 text-stat (collector->value collector)
	 (when text-stat
	   (when (catch 'unread
		   (lyskom-traverse
		    misc-item (text-stat->misc-info-list text-stat)
		    (when (and (eq (misc-info->type misc-item) 'COMM-IN)
			       (not (lyskom-text-read-at-least-once-p 
				     (blocking-do
				      'get-text-stat
				      (misc-info->comm-in misc-item)))))
		      (throw 'unread t))))
	     (unless (lyskom-j-or-n-p
		      (lyskom-format 'have-unread-comment text-stat))
	       (signal 'lyskom-edit-text-abort
		       (list "%s"
			     (lyskom-get-string 
			      'please-check-commented-texts))))))))
David Byers's avatar
David Byers committed
821
      (lyskom-message (lyskom-format 'checking-comments-done)))
822
823
    
    
824
825
826
827
    ;;
    ;; Confirm multiple recipients
    ;;
    
David Byers's avatar
David Byers committed
828
829

    (set-collector->value collector nil)
David Byers's avatar
David Byers committed
830

David Byers's avatar
David Byers committed
831
832
833
    (if (and (lyskom-default-value 'kom-confirm-multiple-recipients)
             (not (eq (lyskom-default-value 'kom-confirm-multiple-recipients)
                      'before))
David Byers's avatar
David Byers committed
834
835
             (> (- num-real-recpt num-me) 1))

836
837
838
839
840
841
842
843
844
        (save-excursion
          (goto-char (point-min))
          (if (not 
               (lyskom-j-or-n-p
                (lyskom-format 'comment-all-relevant-p) t))
              (signal 'lyskom-edit-text-abort 
                      (list "%s" 
                            (lyskom-get-string 
                             'please-edit-recipients))))))
845

David Byers's avatar
David Byers committed
846
    (if (and (lyskom-default-value 'kom-check-commented-author-membership)
847
             (assq 'comm-to (cdr misc-list)))
848
        (progn
849
          (lyskom-message (lyskom-get-string 'checking-rcpt))
850
851
852
853
854

          ;;
          ;; For each commented text, get the author
          ;;
        
855
856
857
858
859
860
          (mapcar 
           (lambda (x)
             (let ((text (blocking-do 'get-text-stat x)))
               (when text
                 (add-to-list 'author-list (text-stat->author text)))))
           comm-to-list)
861

862
          ;;
863
          ;; For each author, see if the author is a direct recipient
864
865
866
867
868
869
870
871
872
873
          ;; of the text. If so, there is no point in continuing.
          ;; (People can unsubscribe from their mailboxes, but if they
          ;; do, this code won't help anyway.)
          ;;

          (lyskom-traverse misc (cdr misc-list)
            (cond ((eq (car misc) 'comm-to)
                   (setq comm-to-list (cons (cdr misc)
                                            comm-to-list)))
                  ((or (eq (car misc) 'recpt)
David Byers's avatar
David Byers committed
874
                       (eq (car misc) 'bcc-recpt)
875
876
877
878
879
                       (eq (car misc) 'cc-recpt))
                   (if (or (memq (cdr misc) author-list)
                           (eq (cdr misc) me))
                       (setq author-list (delq (cdr misc) author-list))))))

880
          ;;
881
882
          ;; For each author, get his or her memberships in all
          ;; recipient conferences.
883
884
885
          ;;

          (save-excursion
David Byers's avatar
David Byers committed
886
            (set-buffer lyskom-buffer)
887
888
889
890
891
892
893
            (mapcar (function
                     (lambda (author-number)
                       (mapcar
                        (function
                         (lambda (conference-number)
                           (initiate-query-read-texts 
                            'sending
David Byers's avatar
X    
David Byers committed
894
895
896
                            'collector-push
                            author-number conference-number
                            collector)))
897
                        recipient-list)
898

899
                       (lyskom-wait-queue 'sending)
900
901
902
903
904
                       (setq author-is-member
                             (and (car (collector->value collector))
                                  (not (membership-type->passive
                                        (membership->type
                                         (car (collector->value collector)))))))
905

906
                       (if (and (not author-is-member)
David Kågedal's avatar
David Kågedal committed
907
				(not (zerop author-number))
908
909
                                (lyskom-is-permitted-author
                                 (blocking-do 'get-conf-stat author-number))
910
911
912
913
914
915
916
917
918
919
                                (lyskom-j-or-n-p
                                 (let ((kom-deferred-printing nil))
                                   (lyskom-format
                                    'add-recipient-p
                                    author-number)) t))
                           (setq extra-headers
                                 (nconc (list 'recpt 
                                              author-number)
                                        extra-headers)))))
                    author-list))))
920

921
    extra-headers))
922
    
David Byers's avatar
David Byers committed
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
(defun lyskom-send-enriched (message)
  (condition-case err
      (let ((buf (lyskom-get-buffer-create 'lyskom-enriched 
                                           "lyskom-enriched" 
                                           t)))
        (unwind-protect
            (save-excursion
              (set-buffer buf)
              (insert message)
              (goto-char (point-min))
              (format-encode-buffer 'text/enriched)
              (goto-char (point-min))
              (search-forward "\n\n")
              (if (and (not (string= (buffer-substring (point)
                                                       (point-max)) message))
                       (save-excursion
                         (set-buffer lyskom-buffer)
                         (lyskom-j-or-n-p 
                          (lyskom-get-string 'send-formatted) t)))
                  (concat "enriched:\n" (buffer-string))
                message))
          (kill-buffer buf)))
    (error (if (lyskom-j-or-n-p
                (lyskom-format (lyskom-get-string 'transform-error)
                               (error-message-string err)))
               message
             (signal 'lyskom-edit-text-abort nil)))))

Per Cederqvist's avatar
.    
Per Cederqvist committed
951
952
953
954
955
956
957
958
959


(defun kom-edit-quit ()
  "Kill the text (if any) written so far and continue reading."
  (interactive)
  (let ((edit-buffer (current-buffer)))
    (goto-char (point-max))
    (setq lyskom-is-writing nil)
    (lyskom-tell-internat 'kom-tell-regret)
David Byers's avatar
X    
David Byers committed
960
961
962
963
    (lyskom-save-excursion (set-buffer edit-buffer)
                           (delete-auto-save-file-if-necessary))
    (lyskom-undisplay-buffer edit-buffer)
    (kill-buffer edit-buffer))
Per Cederqvist's avatar
.    
Per Cederqvist committed
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
  (garbage-collect))			;Take care of the garbage.


(defun kom-edit-show-commented ()
  "Show the commented text in another window."
  (interactive)
  (lyskom-edit-get-commented 'lyskom-edit-show-commented))


(defun kom-edit-insert-commented ()
  "Insert the commented text with '>' first on each line"
  (interactive)
  (lyskom-edit-get-commented 'lyskom-edit-insert-commented))


(defun kom-edit-insert-digit-text ()
  (interactive)
981
  (setq unread-command-events (cons last-command-event unread-command-events))
Per Cederqvist's avatar
.    
Per Cederqvist committed
982
983
984
985
986
  (call-interactively 'kom-edit-insert-text nil))


(defun kom-edit-insert-text (no)
  "Insert the text number NO with '>' first on each line"
Linus Tolke's avatar
Linus Tolke committed
987
988
989
990
991
992
993
  (interactive (list
		(cond
		 ((null current-prefix-arg)
		  (string-to-int 
		   (read-from-minibuffer 
		    (format "%s" (lyskom-get-string 'which-text-include)))))
		 ((prefix-numeric-value current-prefix-arg)))))
David Byers's avatar
David Byers committed
994
995
  (let ((buffer (current-buffer))
        (window (selected-window)))
David Byers's avatar
David Byers committed
996
    (set-buffer lyskom-buffer)
David Byers's avatar
David Byers committed
997
998
999
1000
1001
    (initiate-get-text 'edit
                       'lyskom-edit-insert-commented 
                       no
                       buffer
                       window)
Per Cederqvist's avatar
.    
Per Cederqvist committed
1002
1003
1004
1005
1006
1007
1008
1009
1010
    (set-buffer buffer)
    (sit-for 0)))
    

(defun lyskom-edit-get-commented (thendo)
  "Get the commented text and then do THENDO with it."
  (let ((p (point)))
    (save-excursion
      (let* ((buffer (current-buffer))
David Byers's avatar
David Byers committed
1011
             (window (selected-window))
1012
             (headers (condition-case nil
1013
                          (elt (lyskom-edit-parse-headers) 1)
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
                        (lyskom-edit-error nil))) ; Ignore these errors
             (no nil))
        (while headers
          (if (or (eq (car headers) 'comm-to)
                  (eq (car headers) 'footn-to))
              (setq no (car (cdr headers))
                    headers nil)
            (setq headers (cdr (cdr headers)))))
        (cond
         (no
          (goto-char p)
David Byers's avatar
David Byers committed
1025
          (set-buffer lyskom-buffer)
David Byers's avatar
David Byers committed
1026
          (initiate-get-text 'edit thendo no buffer window)
1027
1028
1029
1030
          (set-buffer buffer))
         (t
          (lyskom-message "%s" (lyskom-get-string 'no-such-text-m))))))
    (sit-for 0)))
Per Cederqvist's avatar
.    
Per Cederqvist committed
1031
1032
1033
1034
1035
1036
1037
1038


;;; ================================================================
;;;	  Add recipient, copy-recipient - Addera mottagare 
;;;
;;;  Author: Anders Gertz
;;;  Changed by: Linus Tolke

David Byers's avatar
David Byers committed
1039
1040
1041
1042
1043
1044
1045
(defun kom-edit-add-comment ()
  "Adds a text as commented to the text being edited."
  (interactive)
  (let* ((edit-buffer (current-buffer))
         (insert-at (point-min-marker))
         (text-no (lyskom-read-number (lyskom-get-string 'text-to-comment-q)))
         (text-stat (blocking-do 'get-text-stat text-no)))
1046
    (lyskom-ignore edit-buffer)
David Byers's avatar
David Byers committed
1047
1048
1049
1050
1051
1052
1053
1054
1055
    (lyskom-save-excursion
     (if text-stat
         (lyskom-edit-get-commented-author 
          (blocking-do 'get-text-stat text-no)
          (lyskom-get-string 'comment)
          insert-at text-no)
       (lyskom-error "%s" (lyskom-get-string 'no-such-text-m))))))


Per Cederqvist's avatar
.    
Per Cederqvist committed
1056
1057
1058
1059
(defun kom-edit-add-recipient ()
  "Adds a conference as recipient to the text being edited."
  (interactive)
  (lyskom-edit-add-recipient/copy (lyskom-get-string 'added-recipient)
David Byers's avatar
David Byers committed
1060
1061
                                 nil
                                  'recpt))
Per Cederqvist's avatar
.    
Per Cederqvist committed
1062
1063


David Byers's avatar
David Byers committed
1064
1065
1066
1067
(defun kom-edit-add-bcc ()
  "Adds a conference as bcc recipient to the text being edited."
  (interactive)
  (lyskom-edit-add-recipient/copy (lyskom-get-string 'added-blank-carbon-copy)
David Byers's avatar
David Byers committed
1068
1069
                                  nil
                                  'bcc-recpt))
David Byers's avatar
David Byers committed
1070
1071


Per Cederqvist's avatar
.    
Per Cederqvist committed
1072
1073
1074
1075
(defun kom-edit-add-copy ()
  "Adds a conference to which a copy of the edited text will be sent."
  (interactive)
  (lyskom-edit-add-recipient/copy (lyskom-get-string 'added-carbon-copy)
David Byers's avatar
David Byers committed
1076
1077
                                  nil
                                  'cc-recpt))
Per Cederqvist's avatar
.    
Per Cederqvist committed
1078

David Byers's avatar
David Byers committed
1079
1080
1081
1082
1083
1084
(defun kom-edit-move-text ()
  "Adds a conference as a recipient, and changes all other recipients to
CC recipients."
  (interactive)
  (lyskom-edit-add-recipient/copy (lyskom-get-string 'who-to-move-to-q)
                                  'lyskom-edit-move-recipients))
Per Cederqvist's avatar
.    
Per Cederqvist committed
1085

David Byers's avatar
David Byers committed
1086

David Byers's avatar
David Byers committed
1087
1088
1089
1090
1091
(defun lyskom-edit-move-recipients (conf-stat insert-at edit-buffer)
  (save-excursion
    (set-buffer edit-buffer)
    (let* ((tmp (lyskom-edit-parse-headers))
           (subject (car tmp))
David Byers's avatar
David Byers committed
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
           (miscs (mapcar (lambda (x) (if (eq (car x) 'recpt) 
                                          (cons 'cc-recpt (cdr x)) x))
                  (cdr (lyskom-edit-translate-headers (elt tmp 1)))))
           (aux-list (elt tmp 2))
           (elem nil))


      ;; If the new target is already a recipient, convert it to the right 
      ;; kind. Otherwise insert the new target after the last comm-to

      (setq elem (lyskom-edit-find-misc miscs '(recpt cc-recpt bcc-recpt) 
                                        (conf-stat->conf-no conf-stat)))
      (if elem
          (setcar elem 'recpt)
        (lyskom-insert-in-list
         (cons 'recpt (conf-stat->conf-no conf-stat))
         miscs
         (car (cdr (memq (lyskom-edit-find-misc miscs '(footn-to comm-to) 
                                                nil t)
                         miscs)))))

      (lyskom-edit-replace-headers subject (cons 'MISC-LIST miscs) aux-list))))
David Byers's avatar
David Byers committed
1114
1115
1116
                                  


David Byers's avatar
David Byers committed
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
(defun lyskom-edit-do-add-recipient/copy (recpt-type recpt-no edit-buffer)
  (lyskom-save-excursion
    (set-buffer edit-buffer)
    (let* ((headers (lyskom-edit-parse-headers))
           (miscs (lyskom-edit-translate-headers (elt headers 1)))
           (elem (lyskom-edit-find-misc miscs '(cc-recpt bcc-recpt recpt)
                                        recpt-no)))

      (cond (elem (setcar elem recpt-type))
            (t (setq miscs
                     (append miscs (list (cons recpt-type recpt-no))))))
      (lyskom-edit-replace-headers (elt headers 0)
                                   miscs
                                   (elt headers 2)))))
           
    
David Byers's avatar
David Byers committed
1133
1134


David Byers's avatar
David Byers committed
1135
1136
1137
1138
1139
1140
(defun lyskom-edit-add-recipient/copy (prompt 
                                       &optional what-to-do recpt-type)
  "Adds a new recipient or a cc-recipient to the text which is being edited.
PROMPT is the prompt to use to ask the user for a recipient.
WHAT-TO-DO is a function to call to do the insertion.
RECPT-TYPE is the type of recipient to add."
1141
  (let ((edit-buffer (current-buffer))
1142
	(insert-at (point-min-marker))
1143
	(conf-stat (lyskom-read-conf-stat prompt '(all) nil "" t)))
Per Cederqvist's avatar
.    
Per Cederqvist committed
1144
    (lyskom-save-excursion
David Byers's avatar
David Byers committed
1145
     (save-excursion
David Byers's avatar
David Byers committed
1146
     (set-buffer lyskom-buffer)
1147
1148
     ;; +++ The information about msg-of-day might be old. We should
     ;; make sure it is up-to-date.
1149
     (let ((text-no (conf-stat->msg-of-day conf-stat)))
David Byers's avatar
David Byers committed
1150
1151
       

1152
       (if (zerop text-no)
David Byers's avatar
David Byers committed
1153
1154
1155

           ;; If we have no notice on the recipient, just go ahead

David Byers's avatar
David Byers committed
1156
1157
           (if what-to-do
               (funcall what-to-do conf-stat insert-at edit-buffer)
David Byers's avatar
David Byers committed
1158
1159
1160
1161
1162
1163
             (lyskom-edit-do-add-recipient/copy recpt-type
                                                (conf-stat->conf-no conf-stat)
                                                edit-buffer))

         ;; Otherwise, show the notive and keep on going

1164
1165
1166
1167
1168
1169
1170
1171
1172
	 (let ((text (blocking-do 'get-text text-no)))
	   (if (and text (get-buffer-window edit-buffer))
	       (let ((win-config (current-window-configuration)))
		 ;;(set-buffer buffer)
		 (with-output-to-temp-buffer "*Motd*"
		   (princ (lyskom-format 'conf-has-motd-no
					 (text->text-no text)
					 (text->text-mass text))))
		 (and (j-or-n-p (lyskom-get-string 'still-want-to-add))
David Byers's avatar
David Byers committed
1173
1174
                      (if what-to-do
                          (funcall what-to-do conf-stat insert-at edit-buffer)
David Byers's avatar
David Byers committed
1175
1176
1177
                        (lyskom-edit-do-add-recipient/copy recpt-type
                                                           (conf-stat->conf-no conf-stat)
                                                           edit-buffer)))
1178
		 (set-window-configuration win-config))
David Byers's avatar
David Byers committed
1179
1180
             (if what-to-do
                 (funcall what-to-do conf-stat insert-at edit-buffer)
David Byers's avatar
David Byers committed
1181
1182
1183
             (lyskom-edit-do-add-recipient/copy recpt-type
                                                (conf-stat->conf-no conf-stat)
                                                edit-buffer))))))))))
Per Cederqvist's avatar
.    
Per Cederqvist committed
1184

1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
(defun kom-edit-add-cross-reference ()
  (interactive)
  (let* ((completions (list (cons (lyskom-get-string 'conference) 'conf)
                            (cons (lyskom-get-string 'person) 'pers)
                            (cons (lyskom-get-string 'text) 'text)))
         (completion-ignore-case t)
         (type (cdr (lyskom-string-assoc
                     (completing-read (lyskom-get-string 'xref-type)
                                      completions nil t)
                     completions)))
         (obj nil)
         (prompt nil)
         (item nil))
    (cond 
     ((eq type 'text)
      (setq prompt (lyskom-get-string 'which-text-to-xref))
      (while (null obj)
        (setq obj (blocking-do 'get-text-stat
                               (lyskom-read-number prompt)))
        (setq prompt (lyskom-get-string 'which-text-to-xref-err )))
      (setq item
            (lyskom-create-aux-item 0 3 0 0 
                                    (lyskom-create-aux-item-flags
                                     nil nil nil nil nil nil nil nil)
                                    0 (format "T%d"
                                              (text-stat->text-no obj)))))

     ((eq type 'conf)
      (setq prompt (lyskom-get-string 'which-conf-to-xref))
      (while (null obj)
        (setq obj (lyskom-read-conf-no prompt '(conf) nil nil t))
        (setq item
              (lyskom-create-aux-item 0 3 0 0
                                      (lyskom-create-aux-item-flags
                                       nil nil nil nil nil nil nil nil)
                                      0 (format "C%d" obj)))))
        
     ((eq type 'pers)
      (setq prompt (lyskom-get-string 'which-pers-to-xref))
      (while (null obj)
        (setq obj (lyskom-read-conf-no prompt '(pers) nil nil t))
        (setq item
              (lyskom-create-aux-item 0 3 0 0
                                      (lyskom-create-aux-item-flags
                                       nil nil nil nil nil nil nil nil)
                                      0 (format "P%d" obj)))))
        
     (t nil))

    (lyskom-edit-insert-aux-item item)))

(defun kom-edit-add-read-confirm-request ()
  (interactive)
  (lyskom-edit-insert-aux-item
   (lyskom-create-aux-item 0 6 0 0
                           (lyskom-create-aux-item-flags
                            nil nil nil nil nil nil nil nil)
                           0 "")))

(defun kom-edit-add-no-comments ()
  (interactive)
  (lyskom-edit-insert-aux-item
   (lyskom-create-aux-item 0 4 0 0
                           (lyskom-create-aux-item-flags
                            nil nil nil nil nil nil nil nil)
                           0 "")))

(defun kom-edit-add-personal-comments ()
  (interactive)
  (lyskom-edit-insert-aux-item
   (lyskom-create-aux-item 0 5 0 0
                           (lyskom-create-aux-item-flags
                            nil nil nil nil nil nil nil nil)
                           0 "")))
  
    



(defun lyskom-edit-insert-aux-item (item)
  "Insert the aux item ITEM in the current buffer"
  (save-excursion
    (goto-char (point-min))
    (re-search-forward
     (concat "^"
             (regexp-quote
              (substitute-command-keys
               (lyskom-get-string 'header-separator)))
             "$")
     nil t)
    (beginning-of-line)
    (forward-line -1)
    (insert
     (concat (lyskom-format
              (format "%%#1@%%[%s%%]%%#2s" (lyskom-get-string 'aux-item-prefix))
              (lyskom-default-button 'aux-edit-menu (cons (current-buffer)
                                                          (point-marker)))
              (lyskom-aux-item-definition-call item 
                                               '(edit-insert print)
                                               item 
                                               lyskom-pers-no))
              "\n")))
  )


(defun lyskom-edit-toggle-secret-aux (buf arg text)
  (interactive)
  (lyskom-save-excursion
    (set-buffer (car arg))
    (goto-char (cdr arg))
    (lyskom-edit-toggle-aux-item-flag buf arg text 'secret)))

(defun lyskom-edit-toggle-anonymous-aux (buf arg text)
  (interactive)
  (save-excursion
    (set-buffer (car arg))
    (goto-char (cdr arg))
    (lyskom-edit-toggle-aux-item-flag buf arg text 'anonymous)))

(defun lyskom-edit-toggle-inherit-aux (buf arg text)
  (interactive)
  (save-excursion
    (set-buffer (car arg))
    (goto-char (cdr arg))
    (lyskom-edit-toggle-aux-item-flag buf arg text 'inherit)))

(defun lyskom-edit-delete-aux (buf arg text)
  (interactive)
  (save-excursion
    (set-buffer (car arg))
    (goto-char (cdr arg))
    (beginning-of-line)
    (delete-region (point) (save-excursion (forward-line 1) (point)))))


(defun lyskom-edit-insert-aux-item-flags (flags)
  (save-excursion
    (let ((str (mapconcat 'identity
                          (delq nil
                                (list
                                 (and (aux-item-flags->secret flags)
                                      (lyskom-get-string 'secret-aux-flag))
                                 (and (aux-item-flags->anonymous flags)
                                      (lyskom-get-string 'anonymous-aux-flag))
                                 (and (aux-item-flags->inherit flags)
                                      (lyskom-get-string 'inherit-aux-flag))))
                          ", ")))
      (when (not (string= str ""))
          (end-of-line)
          (insert (format " [%s]" str))))))


(defun lyskom-edit-toggle-aux-item-flag (buf arg text flag)
  (beginning-of-line)
  (let ((flags (lyskom-edit-extract-aux-item-flags)))
    (when (re-search-forward "\\s-?\\[[^]]*\\]\\s-*$" 
                             (save-excursion (end-of-line) (point)) t)
      (delete-region (match-beginning 0) (match-end 0)))
    (funcall (intern (format "set-aux-item-flags->%s" flag))
             flags
             (not
              (funcall (intern (format "aux-item-flags->%s" flag)) flags)))
    (lyskom-edit-insert-aux-item-flags flags)))

Per Cederqvist's avatar
.    
Per Cederqvist committed
1349
1350


1351
1352
  

Per Cederqvist's avatar
.    
Per Cederqvist committed
1353
1354
1355
1356
1357
;;; ================================================================
;;;   Help functions for the functions bound to keyboard sequences 
;;;                       in lyskom-edit-mode.


David Byers's avatar
David Byers committed
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
(defun lyskom-edit-find-misc (misc-list type data &optional last)
  "Return the first misc-info pair in MISC-LIST of type TYPE containing DATA.
If TYPE is a list, then any type in TYPE is considered to match. If DATA
is nil, then any DATA is considered to match.
If optional LAST is non-nil, then return the last match instead of the first."
  (when (eq (car misc-list) 'MISC-LIST) (setq misc-list (cdr misc-list)))
  (let ((result nil)
        (elem nil))
    (while (and misc-list (or last (null result)))
      (setq elem (car misc-list))
      (setq misc-list (cdr misc-list))
      (when (cond ((listp type) (and (memq (car elem) type)
                                     (or (null data) (eq data (cdr elem)))))
                  ((symbolp type) (and (eq type (car elem))
                                       (or (null data) (eq data (cdr elem)))))
                  (t (or (null data) (eq data (cdr elem)))))
        (setq result elem)))
    result))

1377
(defun lyskom-edit-translate-headers (misc-list)
David Byers's avatar
David Byers committed
1378
  "Translate result of lyskom-edit-parse-header to something we can send
1379
to lyskom-edit-replace-headers"
David Byers's avatar
David Byers committed
1380
1381
1382
1383
1384
1385
1386
  (let ((result nil))
    (while misc-list
      (setq result (cons (cons (car misc-list) (car (cdr misc-list)))
                         result))
      (setq misc-list (cdr (cdr misc-list))))
    (cons 'MISC-LIST (nreverse result))))

1387
(defun lyskom-edit-replace-headers (subject misc-list aux-list)
David Byers's avatar
David Byers committed
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
  "Replace all headers with SUBJECT and MISC-LIST"
  (save-excursion
    (let ((start nil)
          (end nil))
      (goto-char (point-min))
      (setq start (point-marker))
      (set-marker-insertion-type start t)
      (search-forward (substitute-command-keys
                       (lyskom-get-string 'header-separator)))
      (end-of-line)
      (setq end (point-marker))
      (goto-char (point-min))
1400
      (lyskom-edit-insert-miscs misc-list subject "" aux-list)
David Byers's avatar
David Byers committed
1401
1402
1403
1404
      (delete-region start end)
      (goto-char end)
      (delete-char 1))))

1405
(defun lyskom-looking-at-header (header match-number)
1406
  "Check if point is at the beginning of a header of type HEADER.
David Kågedal's avatar
David Kågedal committed
1407
1408
Return the corresponding number (conf no etc.) if MATCH-NUMBER is
non-nil. If MATCH-NUMBER is 'angled, only match a number inside <>."
1409
  (if (looking-at
1410
       (concat (lyskom-get-string header)
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
	       (cond ((eq match-number 'angled)
		      "[^0-9]*<\\([0-9]+\\)>")
		     (match-number
		      "[^0-9]*\\([0-9]+\\)")
		     (nil
		      ""))))
      (if match-number
	  (string-to-int (buffer-substring (match-beginning 1)
					   (match-end 1)))
	t)
1421
1422
1423
1424
1425
1426
1427
1428
    nil))

(defun lyskom-edit-parse-headers ()
  "Parse the headers of an article.
They are returned as a list where the first element is the subject,
and the rest is a list (HEADER DATA HEADER DATA ...), where HEADER is
either 'recpt, 'cc-recpt, 'comm-to or 'footn-to. This is to make it
easy to use the result in a call to `lyskom-create-misc-list'."
Per Cederqvist's avatar
.    
Per Cederqvist committed
1429
  (goto-char (point-min))
1430
1431
1432
  (let ((misc nil)
        (subject nil)
        (aux nil))
1433
1434
    (save-restriction
      ;; Narrow to headers
1435
1436
      (search-forward (substitute-command-keys
		       (lyskom-get-string 'header-separator)))
1437
1438
1439
1440
1441
      (beginning-of-line)
      (narrow-to-region (point-min) (point))
      (goto-char (point-min))
      (while (< (point) (point-max))
	(let ((case-fold-search t)
1442
	      (n nil))
Per Cederqvist's avatar
.    
Per Cederqvist committed
1443
	  (cond
1444
	   ((setq n (lyskom-looking-at-header 'recipient-prefix 'angled))
1445
	    (setq misc (nconc misc (list 'recpt n))))
1446
	   ((setq n (lyskom-looking-at-header 'carbon-copy-prefix 'angled))
1447
	    (setq misc (nconc misc (list 'cc-recpt n))))
David Byers's avatar
David Byers committed
1448
1449
	   ((setq n (lyskom-looking-at-header 'blank-carbon-copy-prefix
                                              'angled))
1450
	    (setq misc (nconc misc (list 'bcc-recpt n))))
1451
	   ((setq n (lyskom-looking-at-header 'comment-prefix t))
1452