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
|
;;;; GNU Mailutils -- a suite of utilities for electronic mail
;;;; Copyright (C) 1999-2001, 2006-2007, 2010-2012 Free Software
;;;; Foundation, Inc.
;;;;
;;;; GNU Mailutils is free software; you can redistribute it and/or modify
;;;; it under the terms of the GNU General Public License as published by
;;;; the Free Software Foundation; either version 3, or (at your option)
;;;; any later version.
;;;;
;;;; GNU Mailutils 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 GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
;;;; This module provides "vacation" extension
;;; vacation example:
;;; vacation :days 18
;;; :aliases ["gray@gnu.org", "gray@mirddin.farlep.net"]
;;; :addresses ["bug-mailutils@gnu.org","bug-inetutils@gnu.org"]
;;; :subject "I'm on vacation"
;;; :mime
;;; text:
;;; I am on vacation until July 22. I'll attend your message as soon
;;; as I'm back.
;;; .
;;;
;;; Additionally, the :sender flag may be used to debug the script.
;; Debugging flag
(define vacation-debug #f)
;; Each entry is (cons SENDER DATE), where SENDER is the sender email
;; address (lowercase) and DATE is the date where the first message
;; from this sender was received.
(define vacation-db '())
(define (vacation-downcase name)
(let ((len (string-length name)))
(do ((i 0 (1+ i)))
((= i len) name)
(string-set! name i (char-downcase (string-ref name i))))))
(define (vacation-db-name)
(let ((pwd (mu-getpwuid (getuid))))
(string-append (vector-ref pwd 5) "/.vacation.db")))
(define (vacation-db-load)
(catch #t
(lambda ()
(call-with-input-file (vacation-db-name)
(lambda (port)
(set! vacation-db (read port)))))
(lambda args args)))
(define (vacation-db-save)
(catch #t
(lambda ()
(let ((mask (umask #o077)))
(call-with-output-file (vacation-db-name)
(lambda (port)
(display ";; Vacation database file\n" port)
(display ";; Generated automatically. Please do not edit\n"
port)
(write vacation-db port)))
(umask mask)))
(lambda args args)))
(define (vacation-db-lookup sender days)
(vacation-db-load)
(let ((val (assoc (vacation-downcase sender) vacation-db)))
(cond
(val
(cond
((and days (> days 0))
(<= (- (car (gettimeofday)) (cdr val)) (* days 86400)))
(else
#t)))
(else
#f))))
(define (vacation-db-update msg)
(let* ((sender (vacation-downcase (mu-message-get-sender msg)))
(date (car (gettimeofday)))
(val (assoc sender vacation-db)))
(cond
(val
(set-cdr! val date))
(else
(set! vacation-db (append vacation-db (list
(cons sender date)))))))
(vacation-db-save))
(define vacation-noreply-senders
(list
".*-REQUEST@.*"
".*-RELAY@.*"
".*-OWNER@.*"
"OWNER-.*"
"postmaster@.*"
"UUCP@.*"
"MAILER@.*"
"MAILER-DAEMON@.*"))
(define (vacation-reply? msg aliases addresses days)
(let ((sender (mu-message-get-sender msg)))
(and
;; No message will be sent unless an alias is part of either
;; the "To:" or "Cc:" headers of the mail.
(call-with-current-continuation
(lambda (exit)
(for-each
(lambda (hdr)
(cond
(hdr
(let ((count (mu-address-get-count hdr)))
(do ((i 1 (1+ i)))
((> i count) #f)
(let ((email (mu-address-get-email hdr i)))
(for-each
(lambda (alias)
(if (string-ci=? alias email)
(exit #t)))
aliases)))))))
(list (mu-message-get-header msg "To")
(mu-message-get-header msg "Cc")))
#f))
;; Messages sent from one of the vacation-noreply-senders are not
;; responded to
(call-with-current-continuation
(lambda (exit)
(do ((explist (append vacation-noreply-senders addresses)
(cdr explist)))
((null? explist) #t)
(let ((rx (make-regexp (car explist) regexp/icase)))
(if (regexp-exec rx sender)
(exit #f))))))
;; Messages with Precedence: bulk or junk are not responded to
(let ((prec (mu-message-get-header msg "Precedence")))
(not (and prec (or (string-ci=? prec "bulk")
(string-ci=? prec "junk")))))
;; Senders already in the database get no response
(not (vacation-db-lookup sender days)))))
(define (vacation-send-reply subject text sender)
(let ((sender "root@localhost")
(mesg (mu-message-create)))
(let ((port (mu-message-get-port mesg "w")))
(display text port)
(close-output-port port))
(mu-message-set-header mesg "X-Sender"
(string-append "vacation.scm, " mu-package-string)
#t)
(mu-message-send mesg #f #f sender)))
(define (action-vacation text . opt)
(sieve-verbose-print "VACATION")
(set! vacation-debug (member #:debug opt))
(if vacation-debug
(begin
(display sieve-current-message)(display ": ")))
(cond
((vacation-reply? sieve-current-message
(append (list sieve-my-email)
(sieve-get-opt-arg opt #:aliases '()))
(sieve-get-opt-arg opt #:addresses '())
(sieve-get-opt-arg opt #:days #f))
(vacation-send-reply (sieve-get-opt-arg
opt #:subject
(string-append "Re: "
(mu-message-get-header
sieve-current-message
"Subject")))
text
(sieve-get-opt-arg
opt #:sender
(mu-message-get-sender sieve-current-message)))
(vacation-db-update sieve-current-message)
(if vacation-debug
(display "WILL REPLY\n")))
(vacation-debug
(display "WILL NOT REPLY\n"))))
;;; Register action
(if sieve-parser
(sieve-register-action "vacation"
action-vacation
(list 'string)
(list (cons "days" 'number)
(cons "addresses" 'string-list)
(cons "aliases" 'string-list)
(cons "subject" 'string)
(cons "sender" 'string)
(cons "mime" #f)
(cons "debug" #f))))
|