~ubuntu-branches/ubuntu/lucid/mew-beta/lucid

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
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
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
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
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
;;; mew-exec.el

;; Author:  Kazu Yamamoto <Kazu@Mew.org>
;; Created: Mar  2, 1997

;;; Code:

(require 'mew)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; exec-func
;;;

(defun mew-mark-kill-refile (src msg)
  (let ((refinfo (mew-refile-get msg))
	myself)
    (setq myself (or (null refinfo) (member src refinfo)))
    (if myself (mew-summary-refile-remove-body))
    (not myself)))

(defun mew-mark-exec-refile (src msgs)
  "Refile MSGs from the SRC folder."
  (let (dsts tmp msg-dsts dsts-msgses)
    (dolist (msg msgs)
      (setq msg-dsts (mew-refile-get msg))
      (setq dsts (cdr msg-dsts))
      (if dsts ;; sanity check
	  (if (setq tmp (assoc dsts dsts-msgses))
	      (nconc tmp (list msg))	
	    (setq dsts-msgses (cons (list dsts msg) dsts-msgses))))
      (mew-refile-reset msg))
    ;; refile at once
    (dolist (dsts-msgs dsts-msgses)
      (mew-summary-mv-msgs src dsts-msgs))))

(defun mew-mark-exec-unlink (src dels)
  "Unlink DELS from the SRC folder.
DELS represents the messages to be deleted."
  (when dels
    (mew-summary-unlink-msgs src dels)))

(defun mew-mark-exec-delete (src dels)
  "Delete messages from the SRC folder according to 'mew-trash-folder'
and 'mew-trash-folder-list'.
DELS represents the messages to be deleted."
  (when dels
    ;; see also mew-summary-exec-remote-get-execinfo.
    (cond
     ((null mew-trash-folder)
      (mew-summary-unlink-msgs src dels))
     (mew-trash-folder-list
      (if (or (member src mew-trash-folder-list)
	      (string= src mew-trash-folder))
	  (mew-summary-unlink-msgs src dels)
	(mew-summary-totrash-msgs src dels)))
     (t
      (if (string= src mew-trash-folder)
	  (mew-summary-unlink-msgs src dels)
	(mew-summary-totrash-msgs src dels))))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; sanity-func
;;;

(defun mew-mark-sanity-refile (msgs)
  "Check the destination folder for MSGS."
  (let (uniq-dsts udst err-dsts dir)
    (dolist (msg msgs)
      (dolist (dst (cdr (mew-refile-get msg)))
	(mew-addq uniq-dsts dst)))
    (mew-addq uniq-dsts mew-trash-folder)
    (dolist (uniq-dst uniq-dsts)
      (setq udst (mew-case-folder mew-inherit-exec-case uniq-dst))
      (setq dir (mew-expand-folder udst))
      (if (file-exists-p dir)
	  (if (file-directory-p dir)
	      (unless (file-writable-p dir)
		(set-file-modes dir mew-folder-mode))
	    (setq err-dsts (cons udst err-dsts))) ;; NG
	(mew-make-directory dir)))
    err-dsts))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Unlinking, moving, to-trash
;;;

(defun mew-folder-suffix (folder)
  (if (or (mew-folder-queuep folder) (mew-folder-postqp folder))
      mew-queue-info-suffix
    (if (mew-folder-draftp folder)
	mew-draft-info-suffix)))

(defun mew-summary-unlink-msgs (src dels)
  (let ((suffix (mew-folder-suffix src))
	file infofile)
    (dolist (del dels)
      (setq file (mew-expand-msg src del))
      ;; if file does not exist, the marked line will be deleted anyway.
      (mew-delete-file file)
      (when suffix
	(setq infofile (concat file suffix))
	(mew-delete-file infofile)))))

(defun mew-i2s (num cache)
  (if cache
      (concat "0" (number-to-string num)) ;; "0" is the mark for invalid messages
    (number-to-string num)))

(defun mew-summary-mv-msgs (src dsts-msgs)
  (let* ((dsts (car dsts-msgs)) ;; (+foo +bar)
	 (msgs (cdr dsts-msgs)) ;; (1 2 3)
	 (srcx (mew-case:folder-folder src))
	 (myselfp (member srcx dsts))
	 (cache mew-inherit-offline)
	 (suffix (mew-folder-suffix srcx))
	 msgs- srcfile dstfile dst num strnum infofile)
    (if myselfp
	;; msg stays in the src folder with the same number
	(progn
	  (setq dsts (delete srcx dsts))
	  (dolist (msg msgs)
	    (if (file-regular-p (mew-expand-msg src msg))
		(setq msgs- (cons msg msgs-))))
	  (setq msgs- (nreverse msgs-))
	  (setq msgs msgs-))
      (setq dst (mew-case-folder mew-inherit-exec-case (car dsts)))
      (setq dsts (cdr dsts))
      (setq num (string-to-number (mew-folder-new-message dst 'num-only cache)))
      (dolist (msg msgs)
	(setq srcfile (mew-expand-msg src msg))
	(when (and (file-exists-p srcfile) (file-writable-p srcfile))
	  (setq strnum (mew-i2s num cache))
	  (setq msgs- (cons strnum msgs-))
	  (setq dstfile (mew-expand-new-msg dst strnum))
	  (setq num (1+ num))
	  (rename-file srcfile dstfile 'override)
	  (mew-set-file-times dstfile)
	  (when suffix
	    (setq infofile (concat srcfile suffix))
	    (mew-delete-file infofile))))
      (mew-touch-folder dst)
      (setq msgs- (nreverse msgs-))
      (setq src dst)) ;; myselfp
    (dolist (ent dsts)
      (setq dst (mew-case-folder mew-inherit-exec-case ent))
      (setq num (string-to-number (mew-folder-new-message dst 'num-only cache)))
      (dolist (msg msgs-)
	(setq srcfile (mew-expand-msg src msg))
	(setq strnum (mew-i2s num cache))
	(setq dstfile (mew-expand-new-msg dst strnum))
	(setq num (1+ num))
	(mew-link srcfile dstfile))
      (mew-touch-folder dst))))

(defun mew-summary-totrash-msgs (src dels)
  (let* ((trash (mew-case-folder mew-inherit-exec-case mew-trash-folder))
	 (trashdir (mew-expand-folder trash))
	 (cache mew-inherit-offline)
	 (suffix (mew-folder-suffix src))
	 num srcfile dstfile infofile)
    (unless (file-directory-p trashdir) (make-directory trashdir))
    (setq num (string-to-number (mew-folder-new-message trash 'num-only cache)))
    ;; must be here after ensuring that +trash exists.
    (dolist (del dels)
      (setq srcfile (mew-expand-msg src del)) ;; xxx
      (setq dstfile (mew-expand-new-msg trash (mew-i2s num cache)))
      (setq num (1+ num))
      (when (file-regular-p srcfile)
	;; if not, the marked line will be deleted anyway.
	(rename-file srcfile dstfile 'override)
	(mew-set-file-times dstfile))
      (when suffix
	(setq infofile (concat srcfile suffix))
	(mew-delete-file infofile)))
    (mew-touch-folder trash)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Commands for mark processing
;;;

(defun mew-summary-exec (&optional arg)
  "\\<mew-summary-mode-map> Process marked messages. When called with
'\\[universal-argument]', process marked messages in the specified
region. To cancel the '*' mark, use '\\[mew-summary-undo]' or
'\\[mew-summary-undo-all]'."
  (interactive "P")
  (let (beg end region)
    (if (mew-mark-active-p) (setq arg t))
    (cond
     (arg
      (setq region (mew-summary-get-region))
      (setq beg (car region))
      (setq end (cdr region)))
     (t
      (setq beg (point-min))
      (setq end (point-max))))
    (mew-summary-exec-region beg end)))

(defun mew-summary-exec-one (&optional arg)
  "Process the current marked message.
When called with '\\[universal-argument]', process
all marked messages before the current message."
  (interactive "P")
  (mew-summary-goto-message)
  (mew-decode-syntax-delete)
  (save-window-excursion
    (let (beg end)
      (save-excursion
	(beginning-of-line)
	(setq beg (if arg (point-min) (point)))
	(end-of-line)
	(setq end (1+ (point))))
      (if (> end (point-max))
	  (message "No message")
	(mew-summary-exec-region beg end)))))

(defun mew-summary-exec-delete ()
  "Process messages marked with 'D'."
  (interactive)
  (let* ((ent (assoc mew-mark-delete mew-mark-spec))
	 (mew-mark-spec (list ent)))
    (mew-summary-exec-region (point-min) (point-max))))

(defun mew-summary-exec-unlink ()
  "Process messages marked with 'X'."
  (interactive)
  (let* ((ent (assoc mew-mark-unlink mew-mark-spec))
	 (mew-mark-spec (list ent)))
    (mew-summary-exec-region (point-min) (point-max))))

(defun mew-summary-exec-refile (&optional arg)
  "Process messages marked with 'o'.
If called with '\\[universal-argument]', only messages whose
destination is the same as that of the current message are processed."
  (interactive "P")
  (let* ((ent (assoc mew-mark-refile mew-mark-spec))
	 (mew-mark-spec (list ent)))
    (if (not arg)
	(mew-summary-exec-region (point-min) (point-max))
      (let* ((msg (mew-summary-message-number))
	     (dst (cdr (mew-refile-get msg)))
	     func)
	(if (not dst)
	    (message "No message to be refiled here")
	  (setq func (lambda (num) (equal dst (cdr (mew-refile-get num)))))
	  (mew-summary-exec-region (point-min) (point-max) func))))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Exec region
;;;

(defun mew-summary-move-and-display (msg &optional redisplay)
  (when (mew-summary-search-msg msg)
    (mew-summary-display redisplay)))

(defun mew-summary-go-back-summary (key)
  (let ((msg (mew-summary-message-number))
	(fld (mew-summary-physical-folder)))
    (if (not (and fld (get-buffer fld)))
	(message "No physical folder")
      (mew-summary-visit-folder fld nil 'no-ls)
      (if msg
	  (mew-summary-move-and-display msg)
	(goto-char (point-max)))
      (message "Now in %s. Type '%s' again" fld key))))

(defun mew-summary-exec-region (beg end &optional func)
  (let ((folder (mew-sinfo-get-folder)))
    (cond
     ((mew-folder-nntpp folder)
      (message "This command cannot be used in this folder"))
     ((mew-folder-remotep folder)
      (message "Refiling and deleting...")
      (force-mode-line-update)
      (mew-summary-exec-remote beg end func))
     ((mew-virtual-p)
      (mew-summary-go-back-summary
       (mew-substitute-for-summary "\\[mew-summary-exec]")))
     (t
      (message "Refiling and deleting...")
      (force-mode-line-update)
      (mew-summary-exec-local beg end func)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Refile log
;;;

(defun mew-exec-refile-log (buf)
  (when (get-buffer buf)
    (with-current-buffer buf
      (mew-frwlet mew-cs-dummy mew-cs-m17n
	(write-region (point-min) (point-max)
		      (expand-file-name mew-refile-log-file mew-conf-path)
		      'append 'no-msg)))
    (mew-remove-buffer buf)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Processing marks for local
;;;

(defun mew-mark-kill-line ()
  (let (start)
    (beginning-of-line)
    (setq start (point))
    (forward-line)
    (mew-elet (delete-region start (point)))))

(defun mew-summary-exec-local (beg end &optional func-decide)
  (when (mew-summary-exclusive-p)
    (save-excursion
      (condition-case nil
	  (let* ((marks (mew-mark-get-all-marks))
		 (src (mew-summary-folder-name 'ext))
		 (lbuf (mew-refile-log-buffer src))
		 (m (copy-marker end))
		 (cnt 0)
		 (case-fold-search nil)
		 msg msgs err-folders func-exec func-sanity killp regex)
	    (dolist (mark marks)
	      (setq func-exec (mew-markdb-func-exec mark))
	      (when func-exec
		(setq killp (mew-markdb-killp mark))
		(setq regex (mew-mark-regex mark))
		(setq msgs nil)
		(goto-char beg)
		(while (re-search-forward regex m t)
		  (setq msg (mew-summary-message-number))
		  (when (or (not func-decide) (funcall func-decide msg))
		    (setq msgs (cons msg msgs))
		    (cond
		     ((fboundp killp)
		      (if (funcall killp src msg)
			  (mew-mark-kill-line)
			(mew-mark-remove)))
		     ((eq killp t)
		      (mew-mark-kill-line)))))
		(setq msgs (nreverse msgs))
		(when msgs
		  (when (= cnt 0)
		    ;; opening...
		    (mew-summary-lock t "Executing")
		    (mew-summary-reset))
		  (setq cnt (1+ cnt))
		  ;; refiling and deleting...
		  (setq func-sanity (mew-markdb-func-sanity mark))
		  (when (and func-sanity
			     (setq err-folders (funcall func-sanity msgs)))
		    (mew-summary-unlock)
		    (mew-warn
		     "Nothing proceeded. Folder(s) MUST be a file!: %s"
		     (mew-join "," err-folders)))
		  (funcall func-exec src msgs))))
	    (if (= cnt 0)
		(message "No marks")
	      ;; ending...
	      (mew-cache-clean-up)
	      (mew-summary-folder-cache-save)
	      (set-buffer-modified-p nil)
	      (mew-summary-unlock)
	      (when (and (eobp) (not (pos-visible-in-window-p)))
		(forward-line -1)
		;; This ensures that some messages are displayed in Summary.
		(recenter))
	      (run-hooks 'mew-summary-exec-hook)
	      (mew-exec-refile-log lbuf)
	      (message "Refiling and deleting...done")))
	(quit
	 (set-buffer-modified-p nil)
	 (mew-summary-unlock))))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Processing marks for remote
;;;

(defun mew-mark-invisible-line ()
  (let (start)
    (beginning-of-line)
    (setq start (point))
    (forward-line)
    (mew-elet
     (put-text-property start (point) 'invisible t)
     ;; For Emacs only. To make invisible text act as we want
     (put-text-property start (point) 'front-sticky t))))

(mew-defstruct execinfo remove kill refile move rttl dttl)
(mew-defstruct refileinfo uid size delete folders)

(defun mew-summary-exec-remote-get-execinfo (beg end modify &optional func-decide)
  ;; for POP or IMAP
  ;; If modify, marked lines get invisible. They are removed
  ;; IMAP's sentinel.
  ;; Otherwise, marked lines retain and they are to be processed
  ;; by mew-summary-exec-local().
  (let* ((case (mew-sinfo-get-case))
	 (folder (mew-sinfo-get-folder))
	 (m (copy-marker end))
	 (case-fold-search nil)
	 (rttl 0) (dttl 0)
	 trash trash-list lomov
	 siz msg uid ref flds del regex trss rmvs kils refs movs
	 refinfo refile-back)
    (when (mew-folder-imapp folder)
      ;; see also mew-mark-exec-delete.
      (setq trash (mew-imap-trash-folder case))
      (setq trash-list (mew-imap-trash-folder-list case))
      (setq lomov t)
      (cond
       ((null trash)
	)
       (trash-list
	(if (or (member folder trash-list)
		(string= folder trash))
	    (setq trash nil)))
       (t
	(if (string= folder trash)
	    (setq trash nil)))))
    (save-excursion
      (mew-decode-syntax-delete)
      ;;
      ;; refile
      ;;
      (when (mew-markdb-by-mark mew-mark-refile)
	(setq regex (mew-mark-regex mew-mark-refile))
	(goto-char beg)
	(while (re-search-forward regex m t)
	  (re-search-forward mew-regex-sumsyn-long)
	  (setq msg (mew-sumsyn-message-number))
	  (setq uid (mew-sumsyn-message-uid))
	  (setq siz (mew-sumsyn-message-size))
	  (when (or (not func-decide) (funcall func-decide msg))	
	    (setq refinfo (mew-refile-get msg))
	    (setq refile-back (cons refinfo refile-back))
	    (setq flds (cdr refinfo))
	    ;;
	    (setq del nil)
	    (if (member folder flds)
		(setq flds (delete folder flds)) ;; destructive
	      (setq del t)
	      (when modify
		(if lomov
		    (setq movs (cons msg movs))
		  (setq kils (cons msg kils)))))
	    (when flds
	      (setq ref (mew-make-refileinfo :uid uid
					     :size siz
					     :delete del
					     :folders flds))
	      (setq refs (cons ref refs)))
	    (if modify
		(if del
		    (mew-mark-invisible-line)
		  (mew-summary-refile-remove-body)
		  (mew-mark-remove)))))
	(setq refs (nreverse refs))
	(setq rttl (length refs))
	(setq movs (nreverse movs))
	(if modify (mew-sinfo-set-refile-back refile-back))
	(when lomov
	  (let ((mew-inherit-exec-case case))
	    (mew-mark-sanity-refile movs))))
      ;;
      ;; delete
      ;;
      (when (mew-markdb-by-mark mew-mark-delete)
	(setq regex (mew-mark-regex mew-mark-delete))
	(goto-char beg)
	(while (re-search-forward regex m t)
	  (re-search-forward mew-regex-sumsyn-long)
	  (setq msg (mew-sumsyn-message-number))
	  (setq uid (mew-sumsyn-message-uid))
	  (setq siz (mew-sumsyn-message-size))
	  (if trash
	      (setq trss (cons (mew-make-refileinfo :uid uid
						    :size siz
						    :delete t
						    :folders (list trash))
			       trss))
	    (setq rmvs (cons uid rmvs)))
	  (when modify
	    (setq kils (cons msg kils))
	    (mew-mark-invisible-line))
	  (setq dttl (1+ dttl))))
      ;;
      ;; unlink
      ;;
      (when (mew-markdb-by-mark mew-mark-unlink)
	(setq regex (mew-mark-regex mew-mark-unlink))
	(goto-char beg)
	(while (re-search-forward regex m t)
	  (re-search-forward mew-regex-sumsyn-long)
	  (setq msg (mew-sumsyn-message-number))
	  (setq uid (mew-sumsyn-message-uid))
	  (setq siz (mew-sumsyn-message-size))
	  (setq rmvs (cons uid rmvs))
	  (when modify
	    (setq kils (cons msg kils))
	    (mew-mark-invisible-line))
	  (setq dttl (1+ dttl))))
      ;;
      (setq rmvs (nreverse rmvs))
      (setq trss (nreverse trss))
      (if trss (setq refs (nconc trss refs)))
      ;;
      (set-buffer-modified-p nil)
      (cond
       ((and (null rmvs) (null refs)) nil)
       (modify
	(force-mode-line-update) ;; xxx
	(mew-make-execinfo :remove rmvs
			   :kill   kils
			   :refile refs
			   :move   movs
			   :rttl   rttl
			   :dttl   dttl))
       (t
	(mew-make-execinfo :remove rmvs
			   :refile refs
			   :rttl   0
			   :dttl   0))))))

(defun mew-summary-exec-remote (beg end &optional func-decide)
  (if (mew-folder-nntpp (mew-sinfo-get-folder))
      (message "This command cannot be used in this folder")
    (when (mew-summary-exclusive-p)
      (let* ((case (mew-sinfo-get-case))
	     (folder (mew-sinfo-get-folder))
	     (bnm (mew-summary-folder-name 'ext))
	     (lbuf (mew-refile-log-buffer bnm))
	     (execinfo (mew-summary-exec-remote-get-execinfo beg end 'modify func-decide)))
	(if (not execinfo)
	    (message "No messages to be processed")
	  (mew-summary-reset)
	  (while (eq (get-text-property (point) 'invisible) t)
	    (forward-line))
	  (cond
	   ((mew-folder-popp folder)
	    (mew-pop-retrieve case 'exec bnm execinfo))
	   ((mew-folder-imapp folder)
	    (mew-imap-retrieve case 'exec bnm execinfo)))
	  (mew-exec-refile-log lbuf))))))

(defun mew-mark-kill-invisible ()
  (save-excursion
    (goto-char (point-min))
    (while (not (eobp))
      (if (get-text-property (point) 'invisible)
	  (mew-mark-kill-line)
	(forward-line)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Processing marks for offline
;;;

(defun mew-summary-exec-offline (&optional arg)
  "\\<mew-summary-mode-map>Process marked messages in an IMAP folder *offline*. Messages to be refiled in
a remote folder are moved to the corresponding folder but they are
marked invalid. Invalid message are marked with '#'.
Invalid messages will be overridden when the remote folder is scanned online.
A job to delete or refile messages, which is created by this command,
is queued in a queue folder (%queue for IMAP). To flush jobs in
the queue, type '\\[mew-summary-send-message]' in the queue online."
  (interactive "P")
  (cond
   ((mew-virtual-p)
    (mew-summary-go-back-summary
     (mew-substitute-for-summary "\\[mew-summary-exec-offline]")))
   ((not (mew-folder-imapp (mew-sinfo-get-folder)))
    (message "This command cannot be used in this folder"))
   (t
    (if (mew-mark-active-p) (setq arg t))
    (let (beg end region)
      (cond
       (arg
	(setq region (mew-summary-get-region))
	(setq beg (car region))
	(setq end (cdr region)))
       (t
	(setq beg (point-min))
	(setq end (point-max))))
      (message "Refiling and deleting...")
      (force-mode-line-update)
      (mew-summary-exec-offline-region beg end)))))

(mew-defstruct jobinfo mailbox execinfo mark-hist)

(defun mew-summary-exec-offline-region (beg end)
  "Process the current marked message offline."
  (interactive)
  (let* ((execinfo (mew-summary-exec-remote-get-execinfo beg end nil))
	 (rmvs (mew-execinfo-get-remove execinfo))
	 (refs (mew-execinfo-get-refile execinfo))
	 job)
    (if (not execinfo)
	(message "No messages to be processed")
      (let* ((fld (mew-sinfo-get-folder))
	     (case (mew-sinfo-get-case))
	     (imapq (mew-case-folder case (mew-imap-queue-folder case)))
	     (imapq-dir (mew-expand-folder imapq))
	     file file-info)
	(unless (file-directory-p imapq-dir) (mew-make-directory imapq-dir))
	(setq file (mew-folder-new-message imapq))
	(setq file-info (concat file mew-imapq-info-suffix))
	(setq job (mew-make-jobinfo :mailbox fld
				    :execinfo execinfo
				    :mark-hist (mew-sinfo-get-mark-hist)))
	(mew-lisp-save file-info job 'nobackup 'unlimit)
	(with-temp-buffer
	  (mew-header-insert mew-subj: (format "IMAP jobs for %s" fld))
	  (mew-header-insert mew-date: (mew-time-ctz-to-rfc (current-time)))
	  (mew-header-insert mew-from: "Mew IMAP manager")
	  (insert "\n")
	  (insert "Messages to be refiled:\n")
	  (dolist (ref refs)
	    (insert (format (if (mew-refileinfo-get-delete ref)
				"\t%s will be copied to %s\n"
			      "\t%s will be moved to %s\n")
			    (mew-refileinfo-get-uid ref)
			    (mew-join "," (mew-refileinfo-get-folders ref)))))
	  (insert "\n")
	  (when rmvs
	    (insert "Messages to be deleted:\n")
	    (insert "\t" (mew-join "," rmvs) "\n"))
	  (mew-frwlet mew-cs-dummy nil
	    (write-region (point-min) (point-max) file nil 'no-msg)))
	(mew-touch-folder imapq)
	;; refile log is not necessary since mew-summary-exec-local does it.
	(let ((mew-inherit-exec-case case)
	      (mew-inherit-offline t)
	      (mew-trash-folder (mew-imap-trash-folder case)))
	  (mew-summary-exec-local beg end))))))

(defun mew-summary-exec-offline-one (&optional arg)
  "Process the message on the cursor offline."
  (interactive "P")
  (if (not (mew-folder-imapp (mew-sinfo-get-folder)))
      (message "This command cannot be used in this folder")
    (mew-summary-goto-message)
    (mew-decode-syntax-delete)
    (save-window-excursion
      (let (beg end)
        (save-excursion
          (beginning-of-line)
          (setq beg (if arg (point-min) (point)))
          (end-of-line)
          (setq end (1+ (point))))
        (if (> end (point-max))
            (message "No message")
	  (force-mode-line-update) ;; xxx
          (mew-summary-exec-offline-region beg end))))))

(provide 'mew-exec)

;;; Copyright Notice:

;; Copyright (C) 1997-2010 Mew developing team.
;; All rights reserved.

;; Redistribution and use in source and binary forms, with or without
;; modification, are permitted provided that the following conditions
;; are met:
;;
;; 1. Redistributions of source code must retain the above copyright
;;    notice, this list of conditions and the following disclaimer.
;; 2. Redistributions in binary form must reproduce the above copyright
;;    notice, this list of conditions and the following disclaimer in the
;;    documentation and/or other materials provided with the distribution.
;; 3. Neither the name of the team nor the names of its contributors
;;    may be used to endorse or promote products derived from this software
;;    without specific prior written permission.
;;
;; THIS SOFTWARE IS PROVIDED BY THE TEAM AND CONTRIBUTORS ``AS IS'' AND
;; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
;; PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE TEAM OR CONTRIBUTORS BE
;; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
;; BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
;; OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
;; IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

;;; mew-exec.el ends here