review.el 76.8 KB
Newer Older
David Byers's avatar
David Byers committed
1
;;;;; -*-coding: iso-8859-1;-*-
Linus Tolke's avatar
Linus Tolke committed
2
3
;;;;;
;;;;; $Id$
4
;;;;; Copyright (C) 1991-2002  Lysator Academic Computer Association.
Linus Tolke's avatar
Linus Tolke committed
5
;;;;;
6
;;;;; This file is part of the LysKOM Emacs LISP client.
Linus Tolke's avatar
Linus Tolke committed
7
8
9
;;;;; 
;;;;; 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
35
36
37
38
;;;; ================================================================
;;;; ================================================================
;;;;
;;;; File: review.el
;;;;
;;;; This file contains functions to review articles in different ways.
;;;; Both the review commands themselves, the functions called by them
;;;; and the underlying functions are here.
;;;;
;;;; Most, if not all, of these functions are written by Linus Tolke.
;;;;


39
40
41
42
(setq lyskom-clientversion-long 
      (concat lyskom-clientversion-long
	      "$Id$\n"))

43
44
45
(eval-when-compile
  (require 'lyskom-command "command"))

David Byers's avatar
David Byers committed
46
47
48
49
(put 'lyskom-cant-review-error 'error-conditions '(error lyskom-error lyskom-review-error))
(put 'lyskom-cant-review-error 'error-message "Can't review")
(put 'lyskom-review-error 'error-condiions '(error lyskom-error))
(put 'lyskom-review-error 'error-message "Review error")
50

51

David Byers's avatar
David Byers committed
52
53
54
;;; ======================================================================
;;; State-saving variables
;;;
55
;;; All these need to be buffer-local
David Byers's avatar
David Byers committed
56

57
58
59
60
61
(def-kom-var lyskom-last-review-by nil local)
(def-kom-var lyskom-last-review-to nil local)
(def-kom-var lyskom-last-review-num nil local)
(def-kom-var lyskom-last-review-pmark nil local)
(def-kom-var lyskom-last-review-cmark nil local)
David Byers's avatar
David Byers committed
62
(def-kom-var lyskom-last-review-filter nil local)
63
64
65
66
67
68
(def-kom-var lyskom-last-review-saved-result-list nil local)
(def-kom-var lyskom-last-review-saved-by-list nil local)
(def-kom-var lyskom-last-review-saved-to-list nil local)
(def-kom-var lyskom-last-review-saved-result-size 0 local)
(def-kom-var lyskom-last-review-saved-smallest nil local)
(def-kom-var lyskom-last-review-saved-largest nil local)
David Byers's avatar
   
David Byers committed
69
(def-kom-var lyskom-last-review-comments nil local)
70
(def-kom-var lyskom-have-review nil local)
David Byers's avatar
David Byers committed
71

72
73
74
75
76
(def-kom-var lyskom-last-unread-by nil local)
(def-kom-var lyskom-last-unread-to nil local)
(def-kom-var lyskom-last-unread-num nil local)
(def-kom-var lyskom-last-unread-pmark nil local)
(def-kom-var lyskom-last-unread-cmark nil local)
David Byers's avatar
David Byers committed
77
(def-kom-var lyskom-last-unread-filter nil local)
78
79
80
81
82
83
84
(def-kom-var lyskom-last-unread-saved-result-list nil local)
(def-kom-var lyskom-last-unread-saved-by-list nil local)
(def-kom-var lyskom-last-unread-saved-to-list nil local)
(def-kom-var lyskom-last-unread-saved-result-size 0 local)
(def-kom-var lyskom-last-unread-saved-smallest nil local)
(def-kom-var lyskom-last-unread-saved-largest nil local)
(def-kom-var lyskom-have-unread nil local)
David Byers's avatar
David Byers committed
85

David Byers's avatar
David Byers committed
86
87
88
(defvar lyskom-default-review-filter nil
  "Default filter for reviewing texts")

David Byers's avatar
David Byers committed
89

90
91
92
93
94
(defun lyskom-remove-zeroes (a)
  "Returns a copy of list where all zeroes are removed."
  (delq 0 (copy-sequence a)))


David Byers's avatar
David Byers committed
95
96
97
;;; ================================================================
;;; Temoporary change of mark-as-read

David Byers's avatar
David Byers committed
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
(defun lyskom-maybe-run-mouse-2 (command)
  (lyskom-xemacs-or-gnu 
   nil
   (when (and (eq command 'mouse-drag-region)
	      unread-command-events
	      (eventp (car unread-command-events))
	      (eq (lyskom-event-type 
		   (car unread-command-events)) 'mouse-2))
     (let* ((sequence (vector (car unread-command-events)))
	    (command (or (lookup-key (current-local-map) 
				     sequence)
			 (lookup-key global-map sequence))))
       (setq unread-command-events (cdr unread-command-events))
       (when (commandp command) 
	 (call-interactively command))))))

David Byers's avatar
David Byers committed
114
115
116
117
118
(defun kom-toggle-mark-as-read-prefix ()
  "Read one key sequence and run one command with state of
kom-review-marks-texts-as-read toggled."
  (interactive)
  (let* ((kom-review-marks-texts-as-read (not kom-review-marks-texts-as-read))
119
120
121
122
123
124
125
126
127
128
129
130
131
	 (sequence (read-key-sequence
		    (format "%s: " 
			    (lyskom-get-string
			     (if kom-review-marks-texts-as-read 
				 'review-marking-as-read
			       'review-not-marking-as-read)))))
	 (command (or (lookup-key (current-local-map) sequence)
		      (lookup-key global-map sequence))))
    (when (or (null command) (eq command 'kom-mouse-null))
      (setq sequence (read-key-sequence ""))
      (setq command (or (lookup-key (current-local-map) sequence)
			(lookup-key global-map sequence))))
    (when (commandp command) 
David Byers's avatar
David Byers committed
132
133
      (call-interactively command))
    (lyskom-maybe-run-mouse-2 command)))
David Byers's avatar
David Byers committed
134

135
136
137
138
139
140
141
142
143
144
145
146
147
(defun kom-toggle-cache-prefix ()
  "Read one key sequence and run one command with state of
kom-review-marks-texts-as-read toggled."
  (interactive)
  (let* ((kom-review-uses-cache (not kom-review-uses-cache))
         (sequence (read-key-sequence
                    (format "%s: " 
                            (lyskom-get-string
                             (if kom-review-uses-cache 
                                 'review-using-cache
                               'review-not-using-cache)))))
         (command (lookup-key (current-local-map) sequence)))
    (when (commandp command)
David Byers's avatar
David Byers committed
148
149
      (call-interactively command))
    (lyskom-maybe-run-mouse-2 command)))
150

David Byers's avatar
David Byers committed
151
152
153
154
155
156
157
158
159
160
161
162
;; (defun kom-toggle-topic-prefix ()
;;   "Read one key sequence and run one command with the review
;; filter set to only show texts that are not comments."
;;   (interactive)
;;   (let* ((lyskom-default-review-filter 'lyskom-review-filter-roots)
;; 	 (sequence (read-key-sequence
;; 		    (format "%s: " "Enbart urinlgg")))
;; 	 (command (lookup-key (current-local-map) sequence)))
;;     (when (commandp command)
;;       (call-interactively command))))


David Byers's avatar
David Byers committed
163

Per Cederqvist's avatar
.    
Per Cederqvist committed
164
165
166
;;; ================================================================
;;;              ]terse av, till - Review by X to Conference Y.

David Byers's avatar
David Byers committed
167
;;; Author: David Byers
168

Per Cederqvist's avatar
.    
Per Cederqvist committed
169

170
(def-kom-command kom-review-all ()
171
  "Review all texts written by a particular author to a particular
172
173
174
175
conference. This can also be accomplished by using `kom-review-by-to'
and specifying zero texts.

See `kom-review-uses-cache', `kom-review-priority' and
176
`kom-review-marks-texts-as-read' for information on settings that affect
177
all review-related functions."
178
179
180
181
  (interactive)
  (lyskom-tell-internat 'kom-tell-review)
  (lyskom-review-by-to 0))

David Byers's avatar
David Byers committed
182
183
184
185
186
187
188
189
190
191
192
193
(def-kom-command kom-review-all-roots ()
  "Review all texts that are not comments written by a particular
author to a particular conference. This can also be accomplished
by using `kom-review-roots-by-to' and specifying zero texts.

See `kom-review-uses-cache', `kom-review-priority' and
`kom-review-marks-texts-as-read' for information on settings that affect
all review-related functions."
  (interactive)
  (lyskom-tell-internat 'kom-tell-review)
  (lyskom-review-by-to 0 'lyskom-review-filter-roots))

David Byers's avatar
David Byers committed
194
(def-kom-command kom-unread-all ()
195
  "Mark all texts written by a particular author to a particular
David Byers's avatar
David Byers committed
196
197
198
199
200
conference as unread. This can also be accomplished by using
`kom-unread-by-to' and specifying zero texts."
  (interactive)
  (lyskom-unread-by-to 0))

David Byers's avatar
David Byers committed
201
202
203
204
205
206
207
(def-kom-command kom-unread-all-roots ()
  "Mark all texts that are not comments written by a particular
author to a particular conference as unread. This can also be
accomplished by using `kom-unread-roots-by-to' and specifying
zero texts."
  (interactive)
  (lyskom-unread-by-to 0 'lyskom-review-filter-roots))
Per Cederqvist's avatar
.    
Per Cederqvist committed
208

209
(def-kom-command kom-review-more (count)
210
  "Review more texts using the same critera as the last review
211
212
213
214
performed with `kom-review-by-to'. The review will be resumed where
the previous review finished.

See `kom-review-uses-cache', `kom-review-priority' and
215
`kom-review-marks-texts-as-read' for information on settings that affect
216
all review-related functions."
Ulrik Haugen's avatar
Ulrik Haugen committed
217
  (interactive "P")
David Byers's avatar
David Byers committed
218
219
  (if (not lyskom-have-review)
      (lyskom-format-insert 'no-review-done)
220
221
222
223
    (let* ((count (or count
		      (lyskom-read-number
		       (lyskom-get-string 'review-how-many-more)
		       (abs lyskom-last-review-num))))
David Byers's avatar
David Byers committed
224
225
226
227
228
229
230
231
232
233
234
           (info (progn (if (and (listp count)
                                 (integerp (car count))
                                 (null (cdr count)))
                            (setq count (car count)))
                        (cond ((zerop count) 
                               (setq count nil)
                               (lyskom-get-string 'review-rest))
                              ((> count 0)
                               (lyskom-format (lyskom-get-string 'review-more)
                                              count)))))
           (by lyskom-last-review-by)
David Byers's avatar
David Byers committed
235
236
           (to lyskom-last-review-to)
	   (filter lyskom-last-review-filter))
David Byers's avatar
David Byers committed
237
238
239
240
241
242
243
244

      (lyskom-format-insert 'review-more-info-by-to
                            info
                            (if (zerop by)
                                (lyskom-get-string 'anybody)
                              by)
                            (if (zerop to)
                                (lyskom-get-string 'all-confs)
David Byers's avatar
David Byers committed
245
246
247
                              to)
			    (when filter
			      (funcall filter 'description)))
David Byers's avatar
David Byers committed
248
249
    
      (condition-case arg
David Byers's avatar
David Byers committed
250
          (let ((list (lyskom-get-texts-by-to by to count t nil filter)))
David Byers's avatar
David Byers committed
251
252
253
254
255
            (setq lyskom-last-review-num 
                  (if (< lyskom-last-review-num 0)
                      (- count)
                    count))
            (if list
256
257
258
259
260
261
262
                (lyskom-review-enter-read-info
                 (lyskom-create-read-info
                  'REVIEW
                  nil
                  (lyskom-review-get-priority)
                  (lyskom-create-text-list list)
                  nil t) t)
David Byers's avatar
David Byers committed
263
264
265
266
267
              (lyskom-insert-string 'no-such-text)))
        (lyskom-review-error (if arg
                                 nil
                               (lyskom-insert-string 'no-such-text)))))))

David Byers's avatar
David Byers committed
268
(def-kom-command kom-unread-more (count)
269
  "Mark more texts unread using the same critera as the last 
David Byers's avatar
David Byers committed
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
mark unread performed with `kom-unread-by-to'."
  (interactive "P")
  (if (not lyskom-have-unread)
      (lyskom-format-insert 'no-unread-done)
    (let* ((count (or count
		      (lyskom-read-number
		       (lyskom-get-string 'unread-how-many-more)
		       (abs lyskom-last-unread-num))))
           (info (progn (if (and (listp count)
                                 (integerp (car count))
                                 (null (cdr count)))
                            (setq count (car count)))
                        (cond ((zerop count) 
                               (setq count nil)
                               (lyskom-get-string 'unread-rest))
                              ((> count 0)
                               (lyskom-format (lyskom-get-string 'unread-more)
                                              count)))))
           (by lyskom-last-unread-by)
David Byers's avatar
David Byers committed
289
290
           (to lyskom-last-unread-to)
	   (filter lyskom-last-review-filter))
David Byers's avatar
David Byers committed
291
292
293
294
295
296
297
298

      (lyskom-format-insert 'unread-more-info-by-to
                            info
                            (if (zerop by)
                                (lyskom-get-string 'anybody)
                              by)
                            (if (zerop to)
                                (lyskom-get-string 'all-confs)
David Byers's avatar
David Byers committed
299
300
301
                              to)
			    (when filter
			      (funcall filter 'description)))
David Byers's avatar
David Byers committed
302
303
    
      (condition-case arg
304
305
          (let* ((lyskom-last-review-num count)
		 (list (lyskom-get-texts-by-to by to count t t filter)))
David Byers's avatar
David Byers committed
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
            (setq lyskom-last-unread-num 
                  (if (< lyskom-last-unread-num 0)
                      (- count)
                    count))
            (if list
              (lyskom-traverse text-no list
                (unless (lyskom-mark-unread text-no)
                  (lyskom-format-insert 'cant-mark-text-unread
                                        text-no
                                        (lyskom-get-error-text lyskom-errno))))
              (lyskom-insert-string 'no-such-text)))
        (lyskom-review-error (if arg
                                 nil
                               (lyskom-insert-string 'no-such-text)))))))

321

David Byers's avatar
David Byers committed
322

323
(def-kom-command kom-review-first (&optional count)
324
  "Review the first N texts written by a particular author to some
325
326
327
328
329
330
331
conference. With no author specified, review texts by all authors.
With zero texts specified, review all text. With no conference
specified, review texts to all conferences. With a negative number of
texts, review the last N texts instead of the first (you can use
`kom-review-by-to' instead.

See `kom-review-uses-cache', `kom-review-priority' and
332
`kom-review-marks-texts-as-read' for information on settings that affect
333
all review-related functions."
334
  (interactive "P")
335
336
337
338
  (lyskom-review-by-to (- (or count
                           (lyskom-read-number
                            (lyskom-get-string 'review-how-many) 1)))))

David Byers's avatar
David Byers committed
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
(def-kom-command kom-review-first-roots (&optional count)

  "Review the first N texts that are not comments written by a
particular author to some conference. With no author specified,
review texts by all authors. With zero texts specified, review
all text. With no conference specified, review texts to all
conferences. With a negative number of texts, review the last N
texts instead of the first (you can use `kom-review-roots-by-to'
instead.

See `kom-review-uses-cache', `kom-review-priority' and
`kom-review-marks-texts-as-read' for information on settings that affect
all review-related functions."
  (interactive "P")
  (lyskom-review-by-to (- (or count
                           (lyskom-read-number
                            (lyskom-get-string 'review-how-many-roots) 1)))
		       'lyskom-review-filter-roots))

David Byers's avatar
David Byers committed
358
(def-kom-command kom-unread-first (&optional count)
359
  "Mark the first N texts written by a particular author to some
David Byers's avatar
David Byers committed
360
361
362
363
364
365
366
367
368
369
conference as unread. With no author specified, review texts by all 
authors. With zero texts specified, review all text. With no conference
specified, review texts to all conferences. With a negative number of
texts, review the last N texts instead of the first (you can use
`kom-unread-by-to' instead."
  (interactive "P")
  (lyskom-unread-by-to (- (or count
                           (lyskom-read-number
                            (lyskom-get-string 'unread-how-many) 1)))))

David Byers's avatar
David Byers committed
370
371
372
373
374
375
376
377
378
379
380
381
382
383
(def-kom-command kom-unread-first-roots (&optional count)
  "Mark the first N texts that are not comments written by a
particular author to some conference as unread. With no author
specified, review texts by all authors. With zero texts
specified, review all text. With no conference specified, review
texts to all conferences. With a negative number of texts, review
the last N texts instead of the first (you can use
`kom-unread-roots-by-to' instead."
  (interactive "P")
  (lyskom-unread-by-to (- (or count
                           (lyskom-read-number
                            (lyskom-get-string 'unread-how-many-roots) 1)))
		       'lyskom-review-filter-roots))

384

David Kågedal's avatar
David Kågedal committed
385
(def-kom-command kom-review-by-to (&optional count)
386
  "Review the last N texts written by a particular author to some
387
conference. With no author specified, review texts by all authors.
David Byers's avatar
David Byers committed
388
With zero texts specified, review all texts. With no conference
389
390
391
392
393
specified, review texts to all conferences. With a negative number of
texts, review the last N texts instead of the first (you can use
`kom-review-first' instead.

See `kom-review-uses-cache', `kom-review-priority' and
394
`kom-review-marks-texts-as-read' for information on settings that affect
395
all review-related functions."
396
397
398
399
400
  (interactive "P")
  (lyskom-review-by-to (or count
                           (lyskom-read-number
                            (lyskom-get-string 'review-how-many) 1))))

David Byers's avatar
David Byers committed
401
402
403
404
405
406
407
(def-kom-command kom-review-roots-by-to (&optional count)
  "Review the last N texts, excluding comments, written by a particular
author to some conference. With no author specified, review texts by all
authors. With zero texts specified, review all texts. With no conference
specified, review texts to all conferences. With a negative number of
texts, review the last N texts instead of the first (you can use
`kom-review-first-roots' instead.
408

David Byers's avatar
David Byers committed
409
410
411
412
413
414
415
416
417
418
See `kom-review-uses-cache', `kom-review-priority' and
`kom-review-marks-texts-as-read' for information on settings that affect
all review-related functions."
  (interactive "P")
  (lyskom-review-by-to (or count
                           (lyskom-read-number
                            (lyskom-get-string 'review-how-many-roots) 1))
		       'lyskom-review-filter-roots))

(defun lyskom-review-by-to (count &optional filter)
419
  "Common function for kom-review-by-to and kom-review-first"
David Byers's avatar
David Byers committed
420
  (setq filter (or filter lyskom-default-review-filter))
421
422
423
424
425
426
  (let* ((info (progn (if (and (listp count)
                               (integerp (car count))
                               (null (cdr count)))
                          (setq count (car count)))
                      (cond ((zerop count) 
                             (setq count nil)
427
                             (lyskom-get-string 'everything))
428
429
430
431
432
                            ((> count 0)
                             (lyskom-format 'latest-n count))
                            ((< count 0)
                             (lyskom-format 'first-n
                                            (- count))))))
David Byers's avatar
David Byers committed
433
434
435
436
437
438
         (by (lyskom-read-conf-no
	      `(review-by-whom ,info ,(and filter (funcall filter 'description)))
	      '(pers) t nil t))
         (to (lyskom-read-conf-no
	      `(review-to-conf ,info ,(and filter (funcall filter 'description)))
	      '(all) t nil t)))
David Kågedal's avatar
David Kågedal committed
439
440

    (if (not (zerop to))
441
        (cache-del-conf-stat to))
David Kågedal's avatar
David Kågedal committed
442
    (if (not (zerop by)) 
443
        (cache-del-pers-stat by))
444

David Byers's avatar
David Byers committed
445
446
447
448
449
450
451
    (lyskom-format-insert 'review-info-by-to
                          info
                          (if (zerop by)
                              (lyskom-get-string 'anybody)
                            by)
                          (if (zerop to)
                              (lyskom-get-string 'all-confs)
David Byers's avatar
David Byers committed
452
453
454
                            to)
			  (when filter
			    (funcall filter 'description)))
David Byers's avatar
David Byers committed
455
456
457
458
459
460

    (setq lyskom-last-review-by by)
    (setq lyskom-last-review-to to)
    (setq lyskom-last-review-num count)
    (setq lyskom-last-review-pmark nil)
    (setq lyskom-last-review-cmark nil)
David Byers's avatar
David Byers committed
461
    (setq lyskom-last-review-filter filter)
David Byers's avatar
David Byers committed
462
463
464
465
466
467
    (setq lyskom-last-review-saved-result-list nil)
    (setq lyskom-last-review-saved-by-list nil)
    (setq lyskom-last-review-saved-to-list nil)
    (setq lyskom-last-review-saved-result-size 0)
    (setq lyskom-last-review-saved-smallest nil)
    (setq lyskom-last-review-saved-largest nil)
David Byers's avatar
   
David Byers committed
468
    (setq lyskom-have-review 'lyskom-review-by-to)
David Kågedal's avatar
David Kågedal committed
469

470
    (condition-case arg
David Byers's avatar
David Byers committed
471
472
473
        (let ((list (lyskom-get-texts-by-to by to count 
					    nil nil 
					    filter)))
474
          (if list
475
476
477
478
479
480
481
              (lyskom-review-enter-read-info
               (lyskom-create-read-info
                'REVIEW
                nil
                (lyskom-review-get-priority)
                (lyskom-create-text-list list)
                nil t) t)
482
483
484
485
            (lyskom-insert-string 'no-such-text)))
      (lyskom-review-error (if arg
                               nil 
                             (lyskom-insert-string 'no-such-text))))))
486

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

David Byers's avatar
David Byers committed
488
(def-kom-command kom-unread-by-to (&optional count)
489
  "Mark the last N texts written by a particular author to some
David Byers's avatar
David Byers committed
490
491
492
493
conference as unread. With no author specified, review texts by all 
authors. With zero texts specified, review all text. With no conference
specified, review texts to all conferences. With a negative number of
texts, review the last N texts instead of the first (you can use
David Byers's avatar
David Byers committed
494
`kom-unread-first' instead)."
David Byers's avatar
David Byers committed
495
496
497
498
  (interactive "P")
  (lyskom-unread-by-to (or count
                           (lyskom-read-number
                            (lyskom-get-string 'unread-how-many) 1))))
David Byers's avatar
David Byers committed
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514

(def-kom-command kom-unread-roots-by-to (&optional count)
  "Mark the last N texts, excluding comments, written by a
particular author to some conference as unread. With no author
specified, review texts by all authors. With zero texts
specified, review all texts. With no conference specified, review
texts to all conferences. With a negative number of texts, review
the last N texts instead of the first (you can use
`kom-unread-first-roots' instead)."
  (interactive "P")
  (lyskom-unread-by-to (or count
                           (lyskom-read-number
                            (lyskom-get-string 'unread-how-many-roots) 1))
		       'lyskom-review-filter-roots))
  

David Byers's avatar
David Byers committed
515
516
  

David Byers's avatar
David Byers committed
517
(defun lyskom-unread-by-to (count &optional filter)
David Byers's avatar
David Byers committed
518
  "Common function for kom-review-by-to and kom-review-first"
David Byers's avatar
David Byers committed
519
  (setq filter (or filter lyskom-default-review-filter))
David Byers's avatar
David Byers committed
520
521
522
523
524
525
526
527
528
529
530
531
  (let* ((info (progn (if (and (listp count)
                               (integerp (car count))
                               (null (cdr count)))
                          (setq count (car count)))
                      (cond ((zerop count) 
                             (setq count nil)
                             (lyskom-get-string 'everything))
                            ((> count 0)
                             (lyskom-format 'latest-n count))
                            ((< count 0)
                             (lyskom-format 'first-n
                                            (- count))))))
David Byers's avatar
David Byers committed
532
533
534
535
536
537
         (by (lyskom-read-conf-no 
	      `(unread-by-whom ,info ,(and filter (funcall filter 'description)))
	      '(pers) t nil t))
         (to (lyskom-read-conf-no 
	      `(unread-to-conf ,info ,(and filter (funcall filter 'description)))
	      '(all) t nil t)))
David Byers's avatar
David Byers committed
538
539
540
541
542
543
544
545
546
547
548
549
550

    (if (not (zerop to))
        (cache-del-conf-stat to))
    (if (not (zerop by)) 
        (cache-del-pers-stat by))

    (lyskom-format-insert 'unread-info-by-to
                          info
                          (if (zerop by)
                              (lyskom-get-string 'anybody)
                            by)
                          (if (zerop to)
                              (lyskom-get-string 'all-confs)
David Byers's avatar
David Byers committed
551
552
553
                            to)
			  (when filter
			    (funcall filter 'description)))
David Byers's avatar
David Byers committed
554
555
556
557
558
559

    (setq lyskom-last-unread-by by)
    (setq lyskom-last-unread-to to)
    (setq lyskom-last-unread-num count)
    (setq lyskom-last-unread-pmark nil)
    (setq lyskom-last-unread-cmark nil)
David Byers's avatar
David Byers committed
560
    (setq lyskom-last-unread-filter filter)
David Byers's avatar
David Byers committed
561
562
563
564
565
566
567
568
569
    (setq lyskom-last-unread-saved-result-list nil)
    (setq lyskom-last-unread-saved-by-list nil)
    (setq lyskom-last-unread-saved-to-list nil)
    (setq lyskom-last-unread-saved-result-size 0)
    (setq lyskom-last-unread-saved-smallest nil)
    (setq lyskom-last-unread-saved-largest nil)
    (setq lyskom-have-unread t)

    (condition-case arg
David Byers's avatar
David Byers committed
570
571
572
        (let ((list (lyskom-get-texts-by-to by to count 
					    nil t
					    filter)))
David Byers's avatar
David Byers committed
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
          (if list
              (lyskom-traverse text-no list
                (unless (lyskom-mark-unread text-no)
                  (lyskom-format-insert 'cant-mark-text-unread
                                        text-no
                                        (lyskom-get-error-text lyskom-errno))))
            (lyskom-insert-string 'no-such-text)))
      (lyskom-review-error (if arg
                               nil 
                             (lyskom-insert-string 'no-such-text))))))






589
590
591
592
593
594
595
596
597
598
;;; ================================================================
;;; lyskom-get-texts-by-to
;;; Author: David Byers
;;;
;;; Call lyskom-get-texts-by, lyskom-get-texts-to or 
;;; lyskom-get-texts-by-and-to to get NUM texts by person 
;;; BY to conference TO.
;;;


David Byers's avatar
David Byers committed
599
(defun lyskom-get-texts-by-to (by to num &optional again do-unread filter)
David Byers's avatar
David Byers committed
600
  "Get NUM texts written by person number BY in conference number TO
David Byers's avatar
David Byers committed
601
602
603
604
605
606
607
608

If optional argument AGAIN is non-nil, then repeat the last review.

If optional argument DO-UNREAD is non-nil, this call is for
marking texts unread, not reviewing them. If optional argument
FILTER is non-nil, then only accept those texts for which
FILTER (called with a text-no) returns non-nil.

609
Args: BY TO NUM AGAIN DO-UNREAD"
610
  (cond ((and (zerop by) 
David Byers's avatar
David Byers committed
611
612
613
614
              (zerop to)) (lyskom-get-texts-globally num again 
						     do-unread filter))
        ((zerop to) (lyskom-get-texts-by by num again nil filter))
        ((zerop by) (lyskom-get-texts-to to num again nil filter))
David Byers's avatar
David Byers committed
615
616
617
618
619
620
621
622
623
624
625
        ((and (eq by lyskom-pers-no)
              (not (eq to by))
              (let ((conf (blocking-do 'get-conf-stat to)))
                (and (conf-type->letterbox (conf-stat->conf-type conf))
                     (null (map->text-nos 
                            (blocking-do 'get-map
                                         (conf-stat->conf-no conf)
                                         (conf-stat->first-local-no conf)
                                         1))))))
         (lyskom-get-texts-by-generic 
          by num 
David Byers's avatar
David Byers committed
626
627
628
629
630
631
632
633
634
635
636
637
	  (lambda (x to filter)
	    (let ((found nil))
	      (and (or (null filter)
		       (funcall filter x))
		   (lyskom-traverse misc (text-stat->misc-info-list x)
		     (setq found 
			   (or found
			       (and (memq (misc-info->type misc)
					  lyskom-recpt-types-list)
				    (eq (misc-info->recipient-no misc) to))))))
	      found))
          (list to filter)
David Byers's avatar
David Byers committed
638
          again))
David Byers's avatar
David Byers committed
639
         (t (lyskom-get-texts-by-and-to by to num again nil nil filter))))
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675


;;; ============================================================
;;; lyskom-check-review-access
;;; Author: David Byers
;;;
;;; Check that we can access the conference map. If we can't some
;;; review functions are just not much fun
;;;

(defun lyskom-check-review-access (conf pers)
  "Check that we can review texts to CONF by PERS.
CONF is a conf-stat or t if we know we can access that conference.
PERS is a pers-stat or t if we know we can access that person.
This function signals an error if review is impossible"
  (cond ((null conf) 
         (lyskom-format-insert 'review-conf-gone)
         (signal 'lyskom-cant-review-error t))
        ((null pers)
         (lyskom-format-insert 'review-pers-gone)
         (signal 'lyskom-cant-review-error t))
        ((lyskom-conf-stat-p conf)
         (cond ((= 0 (conf-stat->no-of-texts conf))
                (lyskom-format-insert 'review-cant-read-empty)
                (signal 'lyskom-cant-review-error t))
               ((null (map->text-nos 
                       (blocking-do 'get-map
                                    (conf-stat->conf-no conf)
                                    (conf-stat->first-local-no conf)
                                    1)))
                (if (conf-type->letterbox
                     (conf-stat->conf-type conf))
                    (lyskom-format-insert 'review-cant-read-letterbox)
                  (lyskom-format-insert 'review-cant-read-conf))
                (signal 'lyskom-cant-review-error t))))))

676
677


678
679
680
681
682
;;; ============================================================
;;; lyskom-get-texts-globally
;;; Author: Per Cederquist, David Byers
;;;

David Byers's avatar
David Byers committed
683
(defun lyskom-get-texts-globally (num &optional again do-unread filter)
David Byers's avatar
David Byers committed
684
685
686
687
688
689
690
  "Get the last NUM texts created in LysKOM. If AGAIN is non-nil, keep
going from where we were before."
  (cond ((and again (null num))
         (setq num lyskom-last-review-num))
        ((and again (< lyskom-last-review-num 0)) 
         (setq num (- num)))
        ((null num) 
691
692
         (lyskom-format-insert
          (if do-unread 'cant-unread-everything 'cant-review-everything))
David Byers's avatar
David Byers committed
693
694
         (signal 'lyskom-cant-review-error t)))

695
  (let ((result nil)
David Byers's avatar
David Byers committed
696
697
698
        (textno (cond (again lyskom-last-review-cmark)
                      ((< num 0) 1)
                      (t (lyskom-maxint))))
699
700
        (op (if (< num 0)
                'find-next-text-no
David Byers's avatar
David Byers committed
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
              'find-previous-text-no))
	(batch-size (abs num)))

    ;; Get the texts in batches of how many we have left to get
    ;; With the filter, this gets inefficient as we start getting
    ;; close to the number of texts we want. 

    (while (and (not (eq textno 0)) (not (null textno))
		(< (length result) (abs num)))

      ;; Inner loop to get a batch of texts

      (let (batch)
	(while (and (not (eq textno 0))
		    (not (null textno))
		    (< (length batch) batch-size))
	  (setq textno (blocking-do op textno))
	  (when textno (setq batch (cons textno batch))))
	  
	;; Now filter the results.

	(setq batch (lyskom-review-filter-results batch filter))

	;; We now have the batch (sometimes in reverse order), so we
	;; put it onto the front of the result list. It would probably
	;; be better to retain a reasonable batch size and save any
	;; results not used, but the benefit is not obvious, and the
	;; work required is...

	(setq result (nconc batch result))
	(setq batch-size (- (abs num) (length result)))))

David Byers's avatar
David Byers committed
733
    (setq lyskom-last-review-cmark textno)
734
735
736
737
    (if (< num 0)
        (nreverse result)
      result)))

738

739
740
741
742
743
744
745
746
747
748
749
;;; ================================================================
;;; lyskom-get-letters-to
;;; Author: David Byers
;;; 
;;; Get letters by self that have a specified letterbox as
;;; recipient. Do this by linearly searching selfs letterbox
;;; map and look as every single doggone text-stat. What a drag.
;;;
;;; +++ FIXME: This is just get-texts-by right now. Need to filter stuff.
;;;

David Byers's avatar
David Byers committed
750
751
(defun lyskom-get-letters-to (persno recipient num &optional again
				     pstart filter)
David Byers's avatar
David Byers committed
752
753
754
  "Get NUM texts written by PERSNO. Args: persno num

Cannot be called from a callback."
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
  (let ((persstat (blocking-do 'get-pers-stat persno)))
    (lyskom-check-review-access t persstat)

    (cond ((and again (null num)) (setq num lyskom-last-review-num))
          ((and again (< lyskom-last-review-num 0)) (setq num (- num))))

    (let* ((plow (or pstart (pers-stat->first-created-text persstat)))
           (phigh (1- (+ plow (pers-stat->no-of-created-texts persstat))))
           (result (if again
                       lyskom-last-review-saved-result-list
                     nil))
           (increment (if num (abs num)))
           (mark (cond (again lyskom-last-review-pmark)
                        ((and num (< num 0)) plow)
                        (t phigh)))
           (found nil)
David Byers's avatar
David Byers committed
771
           (start nil))
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
    

      (if (null num)
          (setq num (1+ phigh)
                mark phigh
                increment (1+ phigh)))

      (while (and (<= mark phigh)
                  (>= mark plow)
                  (> (abs num) (length result)))

        (setq increment (min lyskom-fetch-map-nos increment))
        (setq start (if (< num 0)
                        mark
                      (- mark (1- increment))))
        (if (< start 0)
            (progn
              (setq increment (- increment start))
              (setq start 0)))
      
David Byers's avatar
David Byers committed
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
        (setq found (lyskom-remove-zeroes
		     (listify-vector
		      (map->text-nos
		       (blocking-do 'get-created-texts
				    persno
				    start
				    increment)))))

        (let ((collector (make-collector)))
	  (lyskom-traverse x found
	    (initiate-get-text-stat 
	     'main 
	     (lambda (x collector pers-no pred)
	       (if (and x (or (null pred) (funcall pred x))
			(lyskom-is-recipient x pers-no))
		   (collector-push (text-stat->text-no x) collector)))
	     x collector recipient filter))

	  (lyskom-wait-queue 'main)
	  (setq found (nreverse (collector->value collector))))
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826

        (if (> num 0)
            (setq result (nconc found result)
                  mark (- mark increment))
          (setq result (nconc result found)
                mark (+ mark increment)))
        (if (null found)
            (setq increment (min lyskom-fetch-map-nos (* increment 2)))
          (setq increment (- (abs num) (length result)))))

      (setq lyskom-last-review-pmark mark)

      (if (> num 0)
          (progn
            (setq lyskom-last-review-saved-result-list 
827
                  (lyskom-nfirst (- (length result) num) result))
828
            (nthcdr (max 0 (- (length result) num)) result))
829
830
831
        (progn
          (setq lyskom-last-review-saved-result-list
                (nthcdr (- num) result))
832
          (lyskom-nfirst (- num)  result))))))
833
834
835
836
837
838






839
840
;;; ================================================================
;;; lyskom-get-texts-by-and-to
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
;;; Author: David Byers
;;;
;;; Note: We can't assume that the conference's map of texts is
;;; sorted. If we could, it would be possible to simplify this
;;; function considerably without making it slower. 
;;;
;;; Problem: Construct part of the intersection between the user's
;;; created texts (the by-list) and the texts in a conference (the
;;; to-list) without bogging down the client, server or network and
;;; do it quickly!
;;;
;;; Idea: Construct the intersection incrementally without doing more
;;; work comparing things than we would if we had the full maps to
;;; start with.
;;;
;;; Solution: Get one segment of the by-list (call the nth segment
;;; by_n) and to-list (call the nth segment to_n) at a time until we
;;; are done or until both are exhausted. 
;;;
;;; In each iteration do the following: Calculate the intersection
;;; between to_n with each of the previous by_i leaving r_n:
;;;         r_n = \prod_{i=1}^{n-1} by_i \cap to_n
;;; where \prod denotes list concatenation. Next calculate the
;;; intersection of by_n with each to_i 0<i<n in turn, concatenating
;;; the result to the corresponding r_i:
;;;         r_i \larrow r_i * (by_n \cap to_i) ; 0<i<n
;;; At this point, the concatenation of all r_n, \prod r_n, is the
;;; result of the intersection between the segments of the by-list and
Joel Rosdahl's avatar
Joel Rosdahl committed
869
;;; to-list we have retrieved so far.
870
871
872
873
874
875
876
877
878
879
880
;;;
;;; If the total size of the result equals or exceeds the size we
;;; requested, finish the loop and return the results.
;;;
;;;
;;; Althogh the solution may seem a bit complicated, it's really not
;;; that bad once you think about how it's done. The good thing about
;;; it is that it does as little work as possible comparing elements.
;;; The bad part is that it constructs a little too many new cons
;;; cells, although reversing most of the lists does help.
;;;
881
;;; The following optimisations have been implemented:
882
;;;
883
884
885
886
887
888
889
890
891
892
893
894
895
;;; - Exploit the fact that the user's map is sorted by aborting the
;;; search if we have the full conference map and the lowest number we
;;; have from the user's map is lower than the lowest number in the
;;; conference map. Highest numbers apply when we are searching from
;;; the front.

;;; +++ FIXME: For users that have written very little in high-traffic
;;; conferences, and where the request cannot be fulfilled (if num is
;;; too high) this function ends up scanning the entire conference
;;; map. At some point it is probably faster to get all the text-stats
;;; in the user's map (when we've retrieved the map we know how many
;;; there are) and look at the recipients rather than calculate the
;;; intersection. 
896
;;;
897

David Byers's avatar
David Byers committed
898
(defun lyskom-get-texts-by-and-to (persno confno num 
David Byers's avatar
David Byers committed
899
                                          &optional again pstart cstart filter)
900
  "Get NUM texts written by person PERSNO with conference CONFNO as a
David Byers's avatar
David Byers committed
901
902
recipient. If optional AGAIN is non-nil, continue from where we were.
Args: persno confno num &optional again pstart cstart"
903
904
  (blocking-do-multiple ((persstat (get-pers-stat persno))
                         (confstat (get-conf-stat confno)))
905
906
907
908
909
910
911
912
913
    (cond

     ;;
     ;; Special case: reviewing to a letterbox or conference we're not
     ;; a member of and have no access to.
     ;;

     ((and (eq lyskom-pers-no persno)
           confstat
914
915
           (or (conf-type->letterbox (conf-stat->conf-type confstat))
               (and (conf-type->rd_prot (conf-stat->conf-type confstat))
916
917
                    (null (map->text-nos 
                           (blocking-do 'get-map
David Byers's avatar
David Byers committed
918
919
                                        (conf-stat->conf-no confstat)
                                        (conf-stat->first-local-no confstat)
920
921
                                        1)))))
           (not (eq persno confno)))
David Byers's avatar
David Byers committed
922
      (lyskom-get-letters-to persno confno num again pstart filter))
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
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009

     ;;
     ;; General case
     ;;

     (t
      (lyskom-check-review-access confstat persstat)
      (cond ((and again (null num)) (setq num lyskom-last-review-num))
            ((and again (< lyskom-last-review-num 0) (setq num (- num)))))
      (let* ((result-list (if again
                              lyskom-last-review-saved-result-list
                            nil))
             (by-list (if again
                          lyskom-last-review-saved-by-list
                        nil))
             (to-list (if again 
                          lyskom-last-review-saved-to-list 
                        nil))
             (result-size (if again
                              lyskom-last-review-saved-result-size
                            0))
             (by nil)
             (to nil)
             (increment lyskom-fetch-map-nos)
             (plow (or pstart (pers-stat->first-created-text persstat)))
             (phigh (1- (+ plow (pers-stat->no-of-created-texts persstat))))
             (pmark (cond (again lyskom-last-review-pmark)
                          ((and num (< num 0)) plow)
                          (t phigh)))
             (clow (or cstart (conf-stat->first-local-no confstat)))
             (chigh (1- (+ clow (conf-stat->no-of-texts confstat))))
             (cmark (cond (again lyskom-last-review-cmark)
                          ((and num (< num 0)) clow)
                          (t chigh)))
             (smallest (if again lyskom-last-review-saved-smallest nil))
             (largest (if again lyskom-last-review-saved-largest nil))
             (abort-loop nil))

        (if (null num)
            (setq num (1+ phigh)))

        (while (and (or (and (<= pmark phigh)
                             (>= pmark plow))
                        (and (<= cmark chigh)
                             (>= cmark clow)))
                    (> (abs num) result-size)
                    (not abort-loop))

          (setq by (and (<= pmark phigh)
                        (>= pmark plow)
                        (lyskom-remove-zeroes
                         (listify-vector
                          (map->text-nos
                           (blocking-do 'get-created-texts
                                        (pers-stat->pers-no persstat)
                                        (if (< num 0)
                                            pmark
                                          (max 0 (- pmark (1- increment))))
                                        increment)))))
                to (and (<= cmark chigh)
                        (>= cmark clow)
                        (lyskom-remove-zeroes
                         (listify-vector
                          (map->text-nos
                           (blocking-do 'get-map
                                        (conf-stat->conf-no confstat)
                                        (if (< num 0)
                                            cmark
                                          (max 0 (- cmark (1- increment))))
                                        increment))))))

          (if (> num 0)
              (if (and smallest by
                       (> smallest (car by)))
                  (setq abort-loop t))
            (if (and largest by
                     (< largest (car (nthcdr (1- (length by)) by))))
                (setq abort-loop t)))

          ;;
          ;;    Add intersection between new TO and old BYs
          ;;    to the results list.
          ;;

          (setq result-list
                (cons (apply 'nconc
                             (mapcar 
David Byers's avatar
David Byers committed
1010
1011
1012
1013
			      (lambda (x)
				(lyskom-review-filter-results
				 (lyskom-intersection to x)
				 filter))
1014
1015
1016
1017
1018
1019
1020
1021
1022
                              by-list))
                      result-list))

          ;;
          ;;    Add new BY and TO to the by-list and to-list
          ;;

          (setq by-list (cons by by-list)
                to-list (cons to to-list))
1023
      
1024

1025
1026
1027
1028
1029
          ;;
          ;;    Add intersections between new BY and all TOs
          ;;

          (setq result-list
David Byers's avatar
David Byers committed
1030
1031
1032
1033
1034
                (lyskom-mapcar2 (lambda (x y)
				  (lyskom-review-filter-results
				   (lyskom-intersection y
							(nconc x by))
				   filter))
1035
1036
                                result-list
                                to-list))
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061

          (setq result-size (apply '+ (mapcar 'length result-list)))

          ;;
          ;;    Adjust the marks
          ;;

          (if (> num 0)
              (setq pmark (- pmark increment)
                    cmark (- cmark increment))
            (setq pmark (+ pmark increment)
                  cmark (+ cmark increment)))


          ;;
          ;;  If we have exhausted the conference, calculate smallest and
          ;;  largest
          ;;

          (if (and (null smallest)
                   (null largest)
                   (or (> cmark chigh)
                       (< cmark clow)))
              (setq smallest 
                    (apply 'min
David Byers's avatar
David Byers committed
1062
1063
1064
1065
                           (mapcar (lambda (x)
				     (if x
					 (apply 'min x)
				       (lyskom-maxint)))
1066
1067
1068
                                   to-list))
                    largest
                    (apply 'max
David Byers's avatar
David Byers committed
1069
1070
1071
1072
                           (mapcar (lambda (x)
				     (if x
					 (apply 'max x)
				       -1))
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
                                   to-list))))


          ;;
          ;;    This is the end of the while loop
          ;;

          )

        (setq lyskom-last-review-pmark pmark)
        (setq lyskom-last-review-cmark cmark)
        (setq lyskom-last-review-saved-by-list by-list)
        (setq lyskom-last-review-saved-to-list to-list)
        (setq lyskom-last-review-saved-smallest smallest)
        (setq lyskom-last-review-saved-largest largest)

1089
        ;;
1090
        ;;  Extract results
1091
        ;;
1092

1093
        (setq result-list
1094
1095
1096
              (apply 'nconc (if (< num 0)
                                (nreverse result-list)
                              result-list)))
1097

1098
        ;;
1099
        ;;  Save discarded results and return retained results
1100
        ;;
1101

1102
        (if (> num 0)
1103
1104
            (progn
              (setq lyskom-last-review-saved-result-list
1105
                    (lyskom-nfirst (- (length result-list) num) result-list))
1106
1107
1108
1109
1110
              (setq lyskom-last-review-saved-result-size
                    (length  lyskom-last-review-saved-result-list))
              (setq lyskom-last-review-saved-result-list
                    (cons lyskom-last-review-saved-result-list
                          (make-list (- (length by-list) 1) nil)))
1111
              (nthcdr (max 0 (- (length result-list) num)) result-list))
1112

David Byers's avatar
David Byers committed
1113
1114
1115
1116
1117
1118
1119
1120
          (progn
            (setq lyskom-last-review-saved-result-list 
                  (nthcdr (- num) result-list))
            (setq lyskom-last-review-saved-result-size
                  (length lyskom-last-review-saved-result-list))
            (setq lyskom-last-review-saved-result-list
                  (cons lyskom-last-review-saved-result-list
                        (make-list (- (length by-list) 1) nil)))
1121
            (lyskom-nfirst (- num) result-list))))))))
David Byers's avatar
David Byers committed
1122

1123

1124
1125

;;; ===============================================================
1126
;;; lyskom-get-texts-by, lyskom-get-texts-to
1127
1128
;;; Author: David Byers
;;;
1129
1130
1131
1132
1133
1134
1135
;;; These functions get data in chunks, starting with the number of
;;; texts requested. If they come up empty (which is common when
;;; scanning from the beginning of a map), the increment is
;;; exponentially increased up to a maximum of 150. 
;;;
;;; lyskom-get-texts-by is also careful to filter out those texts that
;;; are not readable, hence the added complexity in that function.
1136
1137
;;;

David Byers's avatar
David Byers committed
1138
(defun lyskom-get-texts-by (persno num &optional again pstart filter)
1139
  "Get NUM texts written by PERSNO. Args: persno num"
David Byers's avatar
David Byers committed
1140
  (let* ((persstat (blocking-do 'get-pers-stat persno)))
1141
    (lyskom-check-review-access t persstat)
David Byers's avatar
David Byers committed
1142
    (lyskom-get-texts-by-generic persno num filter nil again pstart)))
David Byers's avatar
David Byers committed
1143
1144
1145

(defun lyskom-get-texts-by-generic (persno num pred args 
                                           &optional again pstart)
David Byers's avatar
David Byers committed
1146
1147
1148
  "Get NUM texts written by PERSNO. Args: persno num

Cannot be called from a callback."
David Byers's avatar
David Byers committed
1149
1150
  (let* ((persstat (blocking-do 'get-pers-stat persno))
         (user-area (pers-stat->user-area persstat)))
1151

David Byers's avatar
David Byers committed
1152
1153
1154
1155
    (cond ((and again (null num)) (setq num lyskom-last-review-num))
          ((and again (< lyskom-last-review-num 0)) (setq num (- num))))

    (let* ((plow (or pstart (pers-stat->first-created-text persstat)))
1156
           (phigh (1- (+ plow (pers-stat->no-of-created-texts persstat))))
David Byers's avatar
David Byers committed
1157
1158
1159
           (result (if again
                       lyskom-last-review-saved-result-list
                     nil))
1160
           (increment (if num (abs num)))
David Byers's avatar
David Byers committed
1161
1162
1163
           (mark (cond (again lyskom-last-review-pmark)
                        ((and num (< num 0)) plow)
                        (t phigh)))
1164
           (collector nil)
1165
           (found nil)
David Byers's avatar
David Byers committed
1166
           (start nil))
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
    

      (if (null num)
          (setq num (1+ phigh)
                mark phigh
                increment (1+ phigh)))

      (while (and (<= mark phigh)
                  (>= mark plow)
                  (> (abs num) (length result)))
1177
1178
1179
1180
1181
1182
1183
1184
1185

        (setq increment (min lyskom-fetch-map-nos increment))
        (setq start (if (< num 0)
                        mark
                      (- mark (1- increment))))
        (if (< start 0)
            (progn
              (setq increment (- increment start))
              (setq start 0)))
1186
      
David Byers's avatar
David Byers committed
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
        (setq found (delq user-area
			  (lyskom-remove-zeroes
			   (listify-vector
			    (map->text-nos
			     (blocking-do 'get-created-texts
					  persno
					  start
					  increment))))))

	(when pred
	  (let ((collector (make-collector)))
	    (lyskom-traverse x found
	      (initiate-get-text-stat 'main 
				      (lambda (x collector pred args)
					(when (and x (apply pred x args))
					  (collector-push 
					   (text-stat->text-no x)
					   collector)))
				      x collector pred args))

	    (lyskom-wait-queue 'main)
	    (setq found (nreverse (collector->value collector)))))
1209

1210
1211
        (if (> num 0)
            (setq result (nconc found result)
1212
                  mark (- mark increment))
1213
1214
1215
          (setq result (nconc result found)
                mark (+ mark increment)))
        (if (null found)
1216
1217
            (setq increment (min lyskom-fetch-map-nos (* increment 2)))
          (setq increment (- (abs num) (length result)))))
1218

David Byers's avatar
David Byers committed
1219
1220
      (setq lyskom-last-review-pmark mark)

1221
      (if (> num 0)
David Byers's avatar
David Byers committed
1222
1223
          (progn
            (setq lyskom-last-review-saved-result-list 
1224
                  (lyskom-nfirst (- (length result) num) result))
1225
            (nthcdr (max 0 (- (length result) num)) result))
David Byers's avatar
David Byers committed
1226
1227
1228
        (progn
          (setq lyskom-last-review-saved-result-list
                (nthcdr (- num) result))
1229
          (lyskom-nfirst (- num)  result))))))
1230

David Byers's avatar
David Byers committed
1231
1232
1233
1234
1235
1236
1237
(defun lyskom-get-texts-to (confno num &optional again cstart filter)
  "From CONFNO get NUM texts.

If optional AGAIN is non-nil, repeat last review. If optional CSTART
is non-nil, then start from that local number. If optional FILTER
is non-nil, then only retrieve those texts for which FILTER (called 
with the text-stat) returns non-nil."
1238
1239
1240
1241
  (let ((confstat (blocking-do 'get-conf-stat confno)))

    (lyskom-check-review-access confstat t)

David Byers's avatar
David Byers committed
1242
1243
1244
1245
    (cond ((and again (null num)) (setq num lyskom-last-review-num))
          ((and again (< lyskom-last-review-num 0)) (setq num (- num))))

    (let* ((clow (or cstart (conf-stat->first-local-no confstat)))
1246
           (chigh (1- (+ clow (conf-stat->no-of-texts confstat))))
David Byers's avatar
David Byers committed
1247
1248
1249
           (result (if again 
                       lyskom-last-review-saved-result-list
                     nil))
1250
           (start nil)
1251
           (increment (and num (abs num)))
David Byers's avatar
David Byers committed
1252
1253
1254
           (mark (cond (again lyskom-last-review-cmark)
                       ((and num (< num 0)) clow)
                       (t chigh))))
1255
1256
1257
1258
1259
1260
1261
1262
1263

      (if (null num)
          (setq num (1+ chigh)
                increment (1+ chigh)
                mark chigh))

      (while (and (<= mark chigh)
                  (>= mark clow)
                  (> (abs num) (length result)))
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273

        (setq increment (min lyskom-fetch-map-nos increment))
        (setq start (if (< num 0)
                        mark
                      (- mark (1- increment))))
        (if (< start 0)
            (progn
              (setq increment (- increment start))
              (setq start 0)))

1274
1275
1276
1277
1278
        (let ((found (lyskom-remove-zeroes
                      (listify-vector
                       (map->text-nos
                        (blocking-do 'get-map
                                     confno
1279
                                     start
1280
                                     increment))))))
David Byers's avatar
David Byers committed
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
	  (when filter
	    (let ((collector (make-collector)))
	      (lyskom-traverse x found
		(initiate-get-text-stat 'main
					(lambda (x collector pred)
					  (when (and x (funcall pred x))
					    (collector-push
					     (text-stat->text-no x)
					     collector)))
					x collector filter))
	      (lyskom-wait-queue 'main)
	      (setq found (nreverse (collector->value collector)))))
					

1295
1296
1297
1298
1299
1300
1301
1302
1303
          (if (> num 0)
              (setq result (nconc found result)
                    mark (- mark increment)
                    increment (- (abs num) (length result)))
            (setq result (nconc result found)
                  mark (+ mark increment)))
          (if (null found)
              (setq increment (min lyskom-fetch-map-nos (* increment 2)))
            (setq increment (- (abs num) (length result))))))
1304

David Byers's avatar
David Byers committed
1305
1306
      (setq lyskom-last-review-cmark mark)

1307
      (if (> num 0)
David Byers's avatar
David Byers committed
1308
1309
          (progn
            (setq lyskom-last-review-saved-result-list 
1310
                  (lyskom-nfirst (- (length result) num) result))
1311
            (nthcdr (max 0 (- (length result) num)) result))
David Byers's avatar
David Byers committed
1312
1313
1314
        (progn
          (setq lyskom-last-review-saved-result-list
                (nthcdr (- num) result))
1315
          (lyskom-nfirst (- num)  result))))))
Per Cederqvist's avatar
.    
Per Cederqvist committed
1316
1317


David Byers's avatar
David Byers committed
1318
1319


David Byers's avatar
David Byers committed
1320
1321
1322
1323
1324
;;; ============================================================
;;;                 terse baklnges
;;;

(def-kom-command kom-review-backward ()
1325
1326
1327
1328
1329
  "Toggles the reviewing order. If you are currently reviewing texts
oldest to newest, review newest to oldest instead. When reviewing
newest to oldest, change to oldest to newest.

See `kom-review-uses-cache', `kom-review-priority' and
1330
`kom-review-marks-texts-as-read' for information on settings that affect
1331
all review-related functions."
Per Cederqvist's avatar
.    
Per Cederqvist committed
1332
1333
1334
  (interactive)
  (cond
   ((and (not (read-list-isempty lyskom-reading-list))
1335
	 (memq (read-info->type (read-list->first lyskom-reading-list))
1336
		 '(REVIEW REVIEW-MARK)))
Per Cederqvist's avatar
.    
Per Cederqvist committed
1337
1338
    (let* ((info (read-list->first lyskom-reading-list))
	   (list (read-info->text-list info))
1339
	   (texts (text-list->texts list))
Per Cederqvist's avatar
.    
Per Cederqvist committed
1340
	   (forward (read-info->forward info)))
David Byers's avatar
David Byers committed
1341
      (set-text-list->texts list (nreverse texts))
Per Cederqvist's avatar
.    
Per Cederqvist committed
1342
      (set-read-info->forward info (not forward))
1343
1344
1345
1346
      (lyskom-format-insert 'you-review 
			    (lyskom-get-string (if (not forward)
						   'forward
						 'backward)))))
Per Cederqvist's avatar
.    
Per Cederqvist committed
1347
   (t
David Byers's avatar
David Byers committed
1348
    (lyskom-insert-string 'illegal-command))))
Per Cederqvist's avatar
.    
Per Cederqvist committed
1349
1350
1351
1352
1353
1354
1355
1356


;;; ================================================================
;;;                   ]terse tr{det - review tree

;;; Author: Linus Tolke


David Kågedal's avatar
David Kågedal committed
1357
(def-kom-command kom-review-tree (&optional text-no)
1358
1359
1360
1361
1362
1363
1364
1365
1366
  "Recursively review all comments to the selected text.
This command will descend recursively in the comment tree, as when
reading texts normally. Unlike when reading normally, filters are
not applied and circular structures are not dealt with gracefully.

This command accepts text number prefix arguments \(see
`lyskom-read-text-no-prefix-arg').

See `kom-review-uses-cache', `kom-review-priority' and
1367
`kom-review-marks-texts-as-read' for information on settings that affect
1368
all review-related functions."
1369
  (interactive (list (lyskom-read-text-no-prefix-arg 'review-tree-q)))
David Kågedal's avatar
David Kågedal committed
1370
1371
  (lyskom-tell-internat 'kom-tell-review)
  (if text-no
1372
1373
1374
1375
1376
1377
1378
1379
1380
      (progn
        (unless kom-review-uses-cache
          (cache-del-text-stat text-no))
        
        (let ((ts (blocking-do 'get-text-stat text-no)))
          (lyskom-follow-comments ts
                                  nil 'review
                                  (lyskom-review-get-priority)
                                  t)))
David Kågedal's avatar
David Kågedal committed
1381
1382
1383
    (lyskom-insert-string 'read-text-first)))


David Byers's avatar
David Byers committed
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
(def-kom-command kom-unread-tree (text-no)
    "Recursively mark all comments to the selected text as unread.

This command accepts text number prefix arguments \(see
`lyskom-read-text-no-prefix-arg')."
  (interactive (list (lyskom-read-text-no-prefix-arg 'unread-tree-q)))
  (lyskom-unread-tree text-no nil))

(defun lyskom-unread-tree (text-no visited-list)
  "Perform the function of kom-unread-tree."
  (let* ((text-stat (blocking-do 'get-text-stat text-no))
         (worklist (and text-stat
                        (lyskom-text-comments text-stat))))
    (if (null (car worklist))
        (lyskom-format-insert 'no-such-text-no text-no)
      (while worklist
        (let ((cur (car worklist)))
          (setq worklist (cdr worklist))
          (unless (memq cur visited-list)
            (setq visited-list (cons cur visited-list)
                  cur (blocking-do 'get-text-stat cur))
            (when cur
              (when (delq nil (mapcar 'lyskom-get-membership
                                      (lyskom-text-recipients cur)))
                (lyskom-format-insert 'marking-text-unread
                                      (text-stat->text-no cur))
                (lyskom-report-command-answer
                 (lyskom-mark-unread (text-stat->text-no cur))))
              (lyskom-traverse text-no (lyskom-text-comments cur)
                (unless (or (memq text-no visited-list)
                            (memq text-no worklist)
                  (setq worklist (cons text-no worklist)))))))))))
  visited-list)



1420
(def-kom-command kom-find-root (text-no)
1421
1422
1423
1424
1425
1426
1427
1428
  "Finds the root text of the tree containing the selected text.
When there is more than one root, all will be included in a review
operation.

This command accepts text number prefix arguments \(see
`lyskom-read-text-no-prefix-arg').

See `kom-review-uses-cache', `kom-review-priority' and
1429
`kom-review-marks-texts-as-read' for information on settings that affect
1430
all review-related functions."
1431
  (interactive (list (lyskom-read-text-no-prefix-arg 'find-root-q)))
David Kågedal's avatar
David Kågedal committed
1432
1433
  (lyskom-tell-internat 'kom-tell-review)
  (cond
1434
   (text-no
1435
1436
    (unless kom-review-uses-cache
      (cache-del-text-stat text-no))
1437
    (let* ((ts (blocking-do 'get-text-stat text-no))
<