Commit 46dc1e3b 46dc1e3b5d49ea494e5d97df7cebc76d0bf9ae31 by Sergey Poznyakoff

New file. Implements "vacation" extension.

1 parent ac7de069
1 ;;;; GNU mailutils - a suite of utilities for electronic mail
2 ;;;; Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3 ;;;;
4 ;;;; This program is free software; you can redistribute it and/or modify
5 ;;;; it under the terms of the GNU General Public License as published by
6 ;;;; the Free Software Foundation; either version 2, or (at your option)
7 ;;;; any later version.
8 ;;;;
9 ;;;; This program is distributed in the hope that it will be useful,
10 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 ;;;; GNU General Public License for more details.
13 ;;;;
14 ;;;; You should have received a copy of the GNU General Public License
15 ;;;; along with this program; if not, write to the Free Software
16 ;;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 ;;;; This module provides "vacation" extension
19
20 ;;; vacation example:
21 ;;; vacation :days 18
22 ;;; :aliases ["gray@gnu.org", "gray@mirddin.farlep.net"]
23 ;;; :addresses ["bug-mailutils@gnu.org","bug-inetutils@gnu.org"]
24 ;;; :subject "I'm on vacation"
25 ;;; :mime
26 ;;; text:
27 ;;; I am on vacation until July 22. I'll attend your message as soon
28 ;;; as I'm back.
29 ;;; .
30 ;;;
31 ;;; Additionally, the :sender flag may be used to debug the script.
32
33 ;; Debugging flag
34 (define vacation-debug #f)
35
36 ;; Each entry is (cons SENDER DATE), where SENDER is the sender email
37 ;; address (lowercase) and DATE is the date where the first message
38 ;; from this sender was received.
39 (define vacation-db '())
40
41 (define (vacation-downcase name)
42 (let ((len (string-length name)))
43 (do ((i 0 (1+ i)))
44 ((= i len) name)
45 (string-set! name i (char-downcase (string-ref name i))))))
46
47 (define (vacation-db-name)
48 (let ((pwd (mu-getpwuid (getuid))))
49 (string-append (vector-ref pwd 5) "/.vacation.db")))
50
51 (define (vacation-db-load)
52 (catch #t
53 (lambda ()
54 (call-with-input-file (vacation-db-name)
55 (lambda (port)
56 (set! vacation-db (read port)))))
57 (lambda args args)))
58
59 (define (vacation-db-save)
60 (catch #t
61 (lambda ()
62 (let ((mask (umask #o077)))
63 (call-with-output-file (vacation-db-name)
64 (lambda (port)
65 (display ";; Vacation database file\n" port)
66 (display ";; Generated automatically. Please do not edit\n"
67 port)
68 (write vacation-db port)))
69 (umask mask)))
70 (lambda args args)))
71
72 (define (vacation-db-lookup sender days)
73 (vacation-db-load)
74 (let ((val (assoc (vacation-downcase sender) vacation-db)))
75 (cond
76 (val
77 (cond
78 ((and days (> days 0))
79 (<= (- (car (gettimeofday)) (cdr val)) (* days 86400)))
80 (else
81 #t)))
82 (else
83 #f))))
84
85 (define (vacation-db-update msg)
86 (let* ((sender (vacation-downcase (mu-message-get-sender msg)))
87 (date (car (gettimeofday)))
88 (val (assoc sender vacation-db)))
89 (cond
90 (val
91 (set-cdr! val date))
92 (else
93 (set! vacation-db (append vacation-db (list
94 (cons sender date)))))))
95 (vacation-db-save))
96
97 (define vacation-noreply-senders
98 (list
99 ".*-REQUEST@.*"
100 ".*-RELAY@.*"
101 ".*-OWNER@.*"
102 "OWNER-.*"
103 "postmaster@.*"
104 "UUCP@.*"
105 "MAILER@.*"
106 "MAILER-DAEMON@.*"))
107
108 (define (vacation-reply? msg aliases addresses days)
109 (let ((sender (mu-message-get-sender msg)))
110 (and
111 ;; No message will be sent unless an alias is part of either
112 ;; the "To:" or "Cc:" headers of the mail.
113 (call-with-current-continuation
114 (lambda (exit)
115 (for-each
116 (lambda (hdr)
117 (cond
118 (hdr
119 (let ((count (mu-address-get-count hdr)))
120 (do ((i 1 (1+ i)))
121 ((> i count) #f)
122 (let ((email (mu-address-get-email hdr i)))
123 (for-each
124 (lambda (alias)
125 (if (string-ci=? alias email)
126 (exit #t)))
127 aliases)))))))
128 (list (mu-message-get-header msg "To")
129 (mu-message-get-header msg "Cc")))
130 #f))
131
132 ;; Messages sent from one of the vacation-noreply-senders are not
133 ;; responded to
134 (call-with-current-continuation
135 (lambda (exit)
136 (do ((explist (append vacation-noreply-senders addresses)
137 (cdr explist)))
138 ((null? explist) #t)
139 (let ((rx (make-regexp (car explist) regexp/icase)))
140 (if (regexp-exec rx sender)
141 (exit #f))))))
142
143 ;; Messages with Precedence: bulk or junk are not responded to
144 (let ((prec (mu-message-get-header msg "Precedence")))
145 (not (and prec (or (string-ci=? prec "bulk")
146 (string-ci=? prec "junk")))))
147
148 ;; Senders already in the database get no response
149 (not (vacation-db-lookup sender days)))))
150
151 (define (vacation-send-reply subject text sender)
152 (let ((sender "root@localhost")
153 (mesg (mu-message-create)))
154 (let ((port (mu-message-get-port mesg "w")))
155 (display text port)
156 (close-output-port port))
157 (mu-message-set-header mesg "X-Sender"
158 (string-append "vacation.scm, " mu-package-string)
159 #t)
160 (mu-message-send mesg #f #f sender)))
161
162 (define (action-vacation text . opt)
163 (set! vacation-debug (member #:debug opt))
164 (if vacation-debug
165 (begin
166 (display sieve-current-message)(display ": ")))
167 (cond
168 ((vacation-reply? sieve-current-message
169 (append (list sieve-my-email)
170 (sieve-get-opt-arg opt #:aliases '()))
171 (sieve-get-opt-arg opt #:addresses '())
172 (sieve-get-opt-arg opt #:days #f))
173 (vacation-send-reply (sieve-get-opt-arg
174 opt #:subject
175 (string-append "Re: "
176 (mu-message-get-header
177 sieve-current-message
178 "Subject")))
179 text
180 (sieve-get-opt-arg
181 opt #:sender
182 (mu-message-get-sender sieve-current-message)))
183 (vacation-db-update sieve-current-message)
184 (if vacation-debug
185 (display "WILL REPLY\n")))
186 (vacation-debug
187 (display "WILL NOT REPLY\n"))))
188
189 ;;; Register action
190 (if sieve-parser
191 (sieve-register-action "vacation"
192 action-vacation
193 (list 'string)
194 (list (cons "days" 'number)
195 (cons "addresses" 'string-list)
196 (cons "aliases" 'string-list)
197 (cons "subject" 'string)
198 (cons "sender" 'string)
199 (cons "mime" #f)
200 (cons "debug" #f))))
201