Tue Apr 11 10:34:52 2023 UTC ()
Make vacation(1) check 'Auto-Submitted:' (RFC 3834) in addition to
'Precedence:' (RFC 2076), and set 'Precedence:' in addition to
'Auto-Submitted:'.

Update the man page accordingly.


(hauke)
diff -r1.32 -r1.33 src/usr.bin/vacation/vacation.1
diff -r1.37 -r1.38 src/usr.bin/vacation/vacation.c

cvs diff -r1.32 -r1.33 src/usr.bin/vacation/vacation.1 (switch to unified diff)

--- src/usr.bin/vacation/vacation.1 2019/05/06 06:56:07 1.32
+++ src/usr.bin/vacation/vacation.1 2023/04/11 10:34:52 1.33
@@ -1,256 +1,267 @@ @@ -1,256 +1,267 @@
1.\" $NetBSD: vacation.1,v 1.32 2019/05/06 06:56:07 wiz Exp $ 1.\" $NetBSD: vacation.1,v 1.33 2023/04/11 10:34:52 hauke Exp $
2.\" 2.\"
3.\" Copyright (c) 1985, 1987, 1990, 1991, 1993 3.\" Copyright (c) 1985, 1987, 1990, 1991, 1993
4.\" The Regents of the University of California. All rights reserved. 4.\" The Regents of the University of California. All rights reserved.
5.\" 5.\"
6.\" Redistribution and use in source and binary forms, with or without 6.\" Redistribution and use in source and binary forms, with or without
7.\" modification, are permitted provided that the following conditions 7.\" modification, are permitted provided that the following conditions
8.\" are met: 8.\" are met:
9.\" 1. Redistributions of source code must retain the above copyright 9.\" 1. Redistributions of source code must retain the above copyright
10.\" notice, this list of conditions and the following disclaimer. 10.\" notice, this list of conditions and the following disclaimer.
11.\" 2. Redistributions in binary form must reproduce the above copyright 11.\" 2. Redistributions in binary form must reproduce the above copyright
12.\" notice, this list of conditions and the following disclaimer in the 12.\" notice, this list of conditions and the following disclaimer in the
13.\" documentation and/or other materials provided with the distribution. 13.\" documentation and/or other materials provided with the distribution.
14.\" 3. Neither the name of the University nor the names of its contributors 14.\" 3. Neither the name of the University nor the names of its contributors
15.\" may be used to endorse or promote products derived from this software 15.\" may be used to endorse or promote products derived from this software
16.\" without specific prior written permission. 16.\" without specific prior written permission.
17.\" 17.\"
18.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28.\" SUCH DAMAGE. 28.\" SUCH DAMAGE.
29.\" 29.\"
30.\" @(#)vacation.1 8.2 (Berkeley) 4/28/95 30.\" @(#)vacation.1 8.2 (Berkeley) 4/28/95
31.\" 31.\"
32.Dd May 6, 2019 32.Dd May 6, 2019
33.Dt VACATION 1 33.Dt VACATION 1
34.Os 34.Os
35.Sh NAME 35.Sh NAME
36.Nm vacation 36.Nm vacation
37.Nd return 37.Nd return
38.Dq I am not here 38.Dq I am not here
39indication 39indication
40.Sh SYNOPSIS 40.Sh SYNOPSIS
41.Nm 41.Nm
42.Fl dIi 42.Fl dIi
43.Op Fl f Ar databasefile 43.Op Fl f Ar databasefile
44.Op Fl m Ar messagefile 44.Op Fl m Ar messagefile
45.Op Fl r Ar interval 45.Op Fl r Ar interval
46.Op Fl t Ar interval 46.Op Fl t Ar interval
47.Nm 47.Nm
48.Fl dj 48.Fl dj
49.Op Fl a Ar alias 49.Op Fl a Ar alias
50.Op Fl F Ar F|R|S 50.Op Fl F Ar F|R|S
51.Op Fl f Ar databasefile 51.Op Fl f Ar databasefile
52.Op Fl m Ar messagefile 52.Op Fl m Ar messagefile
53.Op Fl s Ar sender 53.Op Fl s Ar sender
54.Op Fl T Ar A|D 54.Op Fl T Ar A|D
55.Ar login 55.Ar login
56.Sh DESCRIPTION 56.Sh DESCRIPTION
57.Nm 57.Nm
58returns a message to the sender of a message telling them that you 58returns a message to the sender of a message telling them that you
59are currently not reading your mail. 59are currently not reading your mail.
60The intended use is in a 60The intended use is in a
61.Pa .forward 61.Pa .forward
62file. 62file.
63For example, your 63For example, your
64.Pa .forward 64.Pa .forward
65file might have: 65file might have:
66.Bd -literal -offset indent 66.Bd -literal -offset indent
67\eeric, "|/usr/bin/vacation -a allman eric" 67\eeric, "|/usr/bin/vacation -a allman eric"
68.Ed 68.Ed
69which would send messages to you (assuming your login name was eric) and 69which would send messages to you (assuming your login name was eric) and
70reply to any messages for 70reply to any messages for
71.Dq eric 71.Dq eric
72or 72or
73.Dq allman . 73.Dq allman .
74.Pp 74.Pp
75Available options: 75Available options:
76.Bl -tag -width Ds 76.Bl -tag -width Ds
77.It Fl a Ar alias 77.It Fl a Ar alias
78Handle messages for 78Handle messages for
79.Ar alias 79.Ar alias
80in the same manner as those received for the user's 80in the same manner as those received for the user's
81login name. 81login name.
82.It Fl d 82.It Fl d
83Turn debugging on; don't send an actual message, but print it on stdout. 83Turn debugging on; don't send an actual message, but print it on stdout.
84.It Fl f Ar database_file 84.It Fl f Ar database_file
85Use the specified 85Use the specified
86.Ar database_file 86.Ar database_file
87prefix and append 87prefix and append
88.Dv \.db 88.Dv \.db
89to it instead of 89to it instead of
90.Dv $HOME/.vacation.db . 90.Dv $HOME/.vacation.db .
91.It Fl F Ar F|R|S 91.It Fl F Ar F|R|S
92Make 92Make
93.Nm 93.Nm
94additionally look in From: (F), Return-Path: (R), or Sender: (S) headers 94additionally look in From: (F), Return-Path: (R), or Sender: (S) headers
95to determine the From: field. 95to determine the From: field.
96.It Fl i 96.It Fl i
97.It Fl I 97.It Fl I
98Initialize the vacation database files. 98Initialize the vacation database files.
99It should be used before you modify your 99It should be used before you modify your
100.Pa .forward 100.Pa .forward
101file. 101file.
102.It Fl j 102.It Fl j
103Do not check if the recipient is present in the 103Do not check if the recipient is present in the
104.Dv To: 104.Dv To:
105or 105or
106.Dv Cc: 106.Dv Cc:
107lines. 107lines.
108Usage of this option is strongly discouraged because it will result in 108Usage of this option is strongly discouraged because it will result in
109.Nm 109.Nm
110replying to mailing lists or other inappropriate places (e.g., messages that 110replying to mailing lists or other inappropriate places (e.g., messages that
111you have been 111you have been
112.Dv Bcc 112.Dv Bcc
113to). 113to).
114.It Fl m Ar message_file 114.It Fl m Ar message_file
115Use 115Use
116.Ar message_file 116.Ar message_file
117instead of 117instead of
118.Dv $HOME/.vacation.msg . 118.Dv $HOME/.vacation.msg .
119.It Fl s Ar sender 119.It Fl s Ar sender
120Reply to 120Reply to
121.Ar sender 121.Ar sender
122instead of the value read from the message. 122instead of the value read from the message.
123.It Fl r Ar interval 123.It Fl r Ar interval
124.It Fl t Ar interval 124.It Fl t Ar interval
125Set the reply interval to 125Set the reply interval to
126.Ar interval 126.Ar interval
127days. 127days.
128If the 128If the
129.Ar interval 129.Ar interval
130number is followed by 130number is followed by
131.Dv w , 131.Dv w ,
132.Dv d , 132.Dv d ,
133.Dv h , 133.Dv h ,
134.Dv m , 134.Dv m ,
135or 135or
136.Dv s 136.Dv s
137then the number is interpreted as weeks, days, hours, minutes, or seconds 137then the number is interpreted as weeks, days, hours, minutes, or seconds
138respectively. 138respectively.
139The default 139The default
140.Ar interval 140.Ar interval
141is one week. 141is one week.
142An 142An
143.Ar interval 143.Ar interval
144of 144of
145.Dq 0 145.Dq 0
146means that 146means that
147a reply is sent to each message, and an interval of 147a reply is sent to each message, and an interval of
148.Dq Li infinite 148.Dq Li infinite
149(actually, any non-numeric character) will never send more than 149(actually, any non-numeric character) will never send more than
150one reply. 150one reply.
151It should be noted that intervals of 151It should be noted that intervals of
152.Dq Li \&0 152.Dq Li \&0
153are quite 153are quite
154dangerous, as it allows mailers to get into 154dangerous, as it allows mailers to get into
155.Dq I am on vacation 155.Dq I am on vacation
156loops. 156loops.
157.It Fl T Ar A|D 157.It Fl T Ar A|D
158Make 158Make
159.Nm 159.Nm
160additionally look in Apparently-To: (A) or Delivered-To: (D) headers 160additionally look in Apparently-To: (A) or Delivered-To: (D) headers
161to determine the To: field. 161to determine the To: field.
162.El 162.El
163.Pp 163.Pp
164No message will be sent unless 164No message will be sent unless
165.Ar login 165.Ar login
166(or an 166(or an
167.Ar alias 167.Ar alias
168supplied using the 168supplied using the
169.Fl a 169.Fl a
170option) is part of either the 170option) is part of either the
171.Dq To: 171.Dq To:
172or 172or
173.Dq Cc: 173.Dq Cc:
174headers of the mail. 174headers of the mail.
 175.Pp
175No messages from 176No messages from
176.Dq ???-REQUEST , 177.Dq ???-REQUEST ,
177.Dq Postmaster , 178.Dq Postmaster ,
178.Dq Tn UUCP , 179.Dq Tn UUCP ,
179.Dq MAILER , 180.Dq MAILER ,
180or 181or
181.Dq MAILER-DAEMON 182.Dq MAILER-DAEMON
182will be replied to (where these strings are 183will be replied to (where these strings are
183case insensitive) nor is a notification sent if a 184case insensitive).
 185.Pp
 186No notification is sent if a
184.Dq Precedence: bulk 187.Dq Precedence: bulk
185.Dq Precedence: list 188.Dq Precedence: list
186or 
187.Dq Precedence: junk 189.Dq Precedence: junk
188line is included in the mail headers. 190line or an
 191.Dq Auto-Submitted:
 192line with any qualifier except
 193.Dq no
 194are included in the mail headers.
 195.Nm
 196will include these headers in its response to avoid auto-responder loops.
 197.Pp
189The people who have sent you messages are maintained as a 198The people who have sent you messages are maintained as a
190.Xr db 3 199.Xr db 3
191database in the file 200database in the file
192.Pa .vacation.db 201.Pa .vacation.db
193in your home directory. 202in your home directory.
194.Pp 203.Pp
195.Nm 204.Nm
196expects a file 205expects a file
197.Pa .vacation.msg , 206.Pa .vacation.msg ,
198in your home directory, containing a message to be sent back to each 207in your home directory containing a message to be sent back to each
199sender. 208sender.
200It should be an entire message (including headers). 209It should be an entire message (including headers).
201If the message contains the string 210If the message contains the string
202.Dv $SUBJECT 211.Dv $SUBJECT
203then it will will be replaced with the subject of the original message. 212then it will will be replaced with the subject of the original message.
204For example, it might contain: 213For example, it might contain:
205.Pp 214.Pp
206.Bd -literal -offset indent -compact 215.Bd -literal -offset indent -compact
207From: eric@CS.Berkeley.EDU (Eric Allman) 216From: eric@CS.Berkeley.EDU (Eric Allman)
208Subject: I am on vacation 217Subject: I am on vacation
209Delivered-By-The-Graces-Of: The Vacation program 218Delivered-By-The-Graces-Of: The Vacation program
210Precedence: bulk 
211 219
212I am on vacation until July 22. 220I am on vacation until July 22.
213Your mail regarding "$SUBJECT" will be read when I return. 221Your mail regarding "$SUBJECT" will be read when I return.
214If you have something urgent, please contact Keith Bostic 222If you have something urgent, please contact Keith Bostic
215<bostic@CS.Berkeley.EDU>. 223<bostic@CS.Berkeley.EDU>.
216--eric 224--eric
217.Ed 225.Ed
218.Pp 226.Pp
219.Nm 227.Nm
220reads the first line from the standard input for a 228reads the first line from the standard input for a
221.Ux 229.Ux
222.Dq From 230.Dq From
223line to determine the sender. 231line to determine the sender.
224.Xr sendmail 1 232.Xr sendmail 1
225includes this 233includes this
226.Dq From 234.Dq From
227line automatically. 235line automatically.
228.Pp 236.Pp
229Fatal errors, such as calling 237Fatal errors, such as calling
230.Nm 238.Nm
231with incorrect arguments, or with non-existent 239with incorrect arguments, or with non-existent
232.Ar login Ns Ar s , 240.Ar login Ns Ar s ,
233are logged in the system log file, using 241are logged in the system log file, using
234.Xr syslog 3 . 242.Xr syslog 3 .
235.Sh FILES 243.Sh FILES
236.Bl -tag -width "vacation.dirxxx" -compact 244.Bl -tag -width "vacation.dirxxx" -compact
237.It Pa ~/.vacation.db 245.It Pa ~/.vacation.db
238database file 246database file
239.It Pa ~/.vacation.msg 247.It Pa ~/.vacation.msg
240message to send 248message to send
241.El 249.El
242.Sh SEE ALSO 250.Sh SEE ALSO
243.Xr sendmail 1 , 251.Xr sendmail 1 ,
244.Xr syslog 3 252.Xr syslog 3
 253.Pp
 254RFC 2076 ,
 255RFC 3834
245.Sh HISTORY 256.Sh HISTORY
246The 257The
247.Nm 258.Nm
248command appeared in 259command appeared in
249.Bx 4.3 . 260.Bx 4.3 .
250.Sh BUGS 261.Sh BUGS
251Adding 262Adding
252.Fl T Ar A 263.Fl T Ar A
253or 264or
254.Fl T Ar D 265.Fl T Ar D
255should only be done for misconfigured or non-compliant MTAs. 266should only be done for misconfigured or non-compliant MTAs.
256Doing so may auto-respond to messages that were not supposed to be replied to. 267Doing so may auto-respond to messages that were not supposed to be replied to.

cvs diff -r1.37 -r1.38 src/usr.bin/vacation/vacation.c (switch to unified diff)

--- src/usr.bin/vacation/vacation.c 2019/05/05 23:08:37 1.37
+++ src/usr.bin/vacation/vacation.c 2023/04/11 10:34:52 1.38
@@ -1,654 +1,669 @@ @@ -1,654 +1,669 @@
1/* $NetBSD: vacation.c,v 1.37 2019/05/05 23:08:37 pgoyette Exp $ */ 1/* $NetBSD: vacation.c,v 1.38 2023/04/11 10:34:52 hauke Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1983, 1987, 1993 4 * Copyright (c) 1983, 1987, 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors 15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software 16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission. 17 * without specific prior written permission.
18 * 18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE. 29 * SUCH DAMAGE.
30 */ 30 */
31 31
32#include <sys/cdefs.h> 32#include <sys/cdefs.h>
33 33
34#ifndef lint 34#ifndef lint
35__COPYRIGHT("@(#) Copyright (c) 1983, 1987, 1993\ 35__COPYRIGHT("@(#) Copyright (c) 1983, 1987, 1993\
36 The Regents of the University of California. All rights reserved."); 36 The Regents of the University of California. All rights reserved.");
37#endif /* not lint */ 37#endif /* not lint */
38 38
39#ifndef lint 39#ifndef lint
40#if 0 40#if 0
41static char sccsid[] = "@(#)vacation.c 8.2 (Berkeley) 1/26/94"; 41static char sccsid[] = "@(#)vacation.c 8.2 (Berkeley) 1/26/94";
42#endif 42#endif
43__RCSID("$NetBSD: vacation.c,v 1.37 2019/05/05 23:08:37 pgoyette Exp $"); 43__RCSID("$NetBSD: vacation.c,v 1.38 2023/04/11 10:34:52 hauke Exp $");
44#endif /* not lint */ 44#endif /* not lint */
45 45
46/* 46/*
47** Vacation 47** Vacation
48** Copyright (c) 1983 Eric P. Allman 48** Copyright (c) 1983 Eric P. Allman
49** Berkeley, California 49** Berkeley, California
50*/ 50*/
51 51
52#include <sys/param.h> 52#include <sys/param.h>
53#include <sys/stat.h> 53#include <sys/stat.h>
54 54
55#include <ctype.h> 55#include <ctype.h>
56#include <db.h> 56#include <db.h>
57#include <err.h> 57#include <err.h>
58#include <errno.h> 58#include <errno.h>
59#include <fcntl.h> 59#include <fcntl.h>
60#include <paths.h> 60#include <paths.h>
61#include <pwd.h> 61#include <pwd.h>
62#include <stdio.h> 62#include <stdio.h>
63#include <stdlib.h> 63#include <stdlib.h>
64#include <string.h> 64#include <string.h>
65#include <syslog.h> 65#include <syslog.h>
66#include <time.h> 66#include <time.h>
67#include <tzfile.h> 67#include <tzfile.h>
68#include <unistd.h> 68#include <unistd.h>
69 69
70/* 70/*
71 * VACATION -- return a message to the sender when on vacation. 71 * VACATION -- return a message to the sender when on vacation.
72 * 72 *
73 * This program is invoked as a message receiver. It returns a 73 * This program is invoked as a message receiver. It returns a
74 * message specified by the user to whomever sent the mail, taking 74 * message specified by the user to whomever sent the mail, taking
75 * care not to return a message too often to prevent "I am on 75 * care not to return a message too often to prevent "I am on
76 * vacation" loops. 76 * vacation" loops.
77 */ 77 */
78 78
79#define MAXLINE 1024 /* max line from mail header */ 79#define MAXLINE 1024 /* max line from mail header */
80 80
81static const char *dbprefix = ".vacation"; /* dbm's database sans .db */ 81static const char *dbprefix = ".vacation"; /* dbm's database sans .db */
82static const char *msgfile = ".vacation.msg"; /* vacation message */ 82static const char *msgfile = ".vacation.msg"; /* vacation message */
83 83
84typedef struct alias { 84typedef struct alias {
85 struct alias *next; 85 struct alias *next;
86 const char *name; 86 const char *name;
87} alias_t; 87} alias_t;
88static alias_t *names; 88static alias_t *names;
89 89
90static DB *db; 90static DB *db;
91static char from[MAXLINE]; 91static char from[MAXLINE];
92static char subject[MAXLINE]; 92static char subject[MAXLINE];
93 93
94static int iflag = 0; /* Initialize the database */ 94static int iflag = 0; /* Initialize the database */
95 95
96static int tflag = 0; 96static int tflag = 0;
97#define APPARENTLY_TO 1 97#define APPARENTLY_TO 1
98#define DELIVERED_TO 2 98#define DELIVERED_TO 2
99 99
100static int fflag = 0; 100static int fflag = 0;
101#define FROM_FROM 1 101#define FROM_FROM 1
102#define RETURN_PATH_FROM 2 102#define RETURN_PATH_FROM 2
103#define SENDER_FROM 4 103#define SENDER_FROM 4
104 104
105static int toanybody = 0; /* Don't check if we appear in the to or cc */ 105static int toanybody = 0; /* Don't check if we appear in the to or cc */
106 106
107static int debug = 0; 107static int debug = 0;
108 108
109static void opendb(void); 109static void opendb(void);
110static int junkmail(const char *); 110static int junkmail(const char *);
111static int nsearch(const char *, const char *); 111static int nsearch(const char *, const char *);
112static int readheaders(void); 112static int readheaders(void);
113static int recent(void); 113static int recent(void);
114static void getfrom(char *); 114static void getfrom(char *);
115static void sendmessage(const char *); 115static void sendmessage(const char *);
116static void setinterval(time_t); 116static void setinterval(time_t);
117static void setreply(void); 117static void setreply(void);
118static void usage(void) __dead; 118static void usage(void) __dead;
119 119
120int 120int
121main(int argc, char **argv) 121main(int argc, char **argv)
122{ 122{
123 struct passwd *pw; 123 struct passwd *pw;
124 alias_t *cur; 124 alias_t *cur;
125 long interval; 125 long interval;
126 int ch, rv; 126 int ch, rv;
127 char *p; 127 char *p;
128 128
129 setprogname(argv[0]); 129 setprogname(argv[0]);
130 opterr = 0; 130 opterr = 0;
131 interval = -1; 131 interval = -1;
132 openlog(getprogname(), 0, LOG_USER); 132 openlog(getprogname(), 0, LOG_USER);
133 while ((ch = getopt(argc, argv, "a:df:F:Iijm:r:s:t:T:")) != -1) 133 while ((ch = getopt(argc, argv, "a:df:F:Iijm:r:s:t:T:")) != -1)
134 switch((char)ch) { 134 switch((char)ch) {
135 case 'a': /* alias */ 135 case 'a': /* alias */
136 if (!(cur = (alias_t *)malloc((size_t)sizeof(alias_t)))) 136 if (!(cur = (alias_t *)malloc((size_t)sizeof(alias_t))))
137 break; 137 break;
138 cur->name = optarg; 138 cur->name = optarg;
139 cur->next = names; 139 cur->next = names;
140 names = cur; 140 names = cur;
141 break; 141 break;
142 case 'd': 142 case 'd':
143 debug++; 143 debug++;
144 break; 144 break;
145 case 'F': 145 case 'F':
146 for (p = optarg; *p; p++) 146 for (p = optarg; *p; p++)
147 switch (*p) { 147 switch (*p) {
148 case 'F': 148 case 'F':
149 fflag |= FROM_FROM; 149 fflag |= FROM_FROM;
150 break; 150 break;
151 case 'R': 151 case 'R':
152 fflag |= RETURN_PATH_FROM; 152 fflag |= RETURN_PATH_FROM;
153 break; 153 break;
154 case 'S': 154 case 'S':
155 fflag |= SENDER_FROM; 155 fflag |= SENDER_FROM;
156 break; 156 break;
157 default: 157 default:
158 errx(1, "Unknown -f option `%c'", *p); 158 errx(1, "Unknown -f option `%c'", *p);
159 } 159 }
160 break; 160 break;
161 case 'f': 161 case 'f':
162 dbprefix = optarg; 162 dbprefix = optarg;
163 break; 163 break;
164 case 'I': /* backward compatible */ 164 case 'I': /* backward compatible */
165 case 'i': /* init the database */ 165 case 'i': /* init the database */
166 iflag = 1; 166 iflag = 1;
167 break; 167 break;
168 case 'j': 168 case 'j':
169 toanybody = 1; 169 toanybody = 1;
170 break; 170 break;
171 case 'm': 171 case 'm':
172 msgfile = optarg; 172 msgfile = optarg;
173 break; 173 break;
174 case 'r': 174 case 'r':
175 case 't': /* Solaris compatibility */ 175 case 't': /* Solaris compatibility */
176 if (!isdigit((unsigned char)*optarg)) { 176 if (!isdigit((unsigned char)*optarg)) {
177 interval = LONG_MAX; 177 interval = LONG_MAX;
178 break; 178 break;
179 } 179 }
180 if (*optarg == '\0') 180 if (*optarg == '\0')
181 goto bad; 181 goto bad;
182 interval = strtol(optarg, &p, 0); 182 interval = strtol(optarg, &p, 0);
183 if (errno == ERANGE && 183 if (errno == ERANGE &&
184 (interval == LONG_MAX || interval == LONG_MIN)) 184 (interval == LONG_MAX || interval == LONG_MIN))
185 err(1, "Bad interval `%s'", optarg); 185 err(1, "Bad interval `%s'", optarg);
186 switch (*p) { 186 switch (*p) {
187 case 's': 187 case 's':
188 break; 188 break;
189 case 'm': 189 case 'm':
190 interval *= SECSPERMIN; 190 interval *= SECSPERMIN;
191 break; 191 break;
192 case 'h': 192 case 'h':
193 interval *= SECSPERHOUR; 193 interval *= SECSPERHOUR;
194 break; 194 break;
195 case 'd': 195 case 'd':
196 case '\0': 196 case '\0':
197 interval *= SECSPERDAY; 197 interval *= SECSPERDAY;
198 break; 198 break;
199 case 'w': 199 case 'w':
200 interval *= DAYSPERWEEK * SECSPERDAY; 200 interval *= DAYSPERWEEK * SECSPERDAY;
201 break; 201 break;
202 default: 202 default:
203 bad: 203 bad:
204 errx(1, "Invalid interval `%s'", optarg); 204 errx(1, "Invalid interval `%s'", optarg);
205 } 205 }
206 if (interval < 0 || (*p && p[1])) 206 if (interval < 0 || (*p && p[1]))
207 goto bad; 207 goto bad;
208 break; 208 break;
209 case 's': 209 case 's':
210 (void)strlcpy(from, optarg, sizeof(from)); 210 (void)strlcpy(from, optarg, sizeof(from));
211 break; 211 break;
212 case 'T': 212 case 'T':
213 for (p = optarg; *p; p++) 213 for (p = optarg; *p; p++)
214 switch (*p) { 214 switch (*p) {
215 case 'A': 215 case 'A':
216 tflag |= APPARENTLY_TO; 216 tflag |= APPARENTLY_TO;
217 break; 217 break;
218 case 'D': 218 case 'D':
219 tflag |= DELIVERED_TO; 219 tflag |= DELIVERED_TO;
220 break; 220 break;
221 default: 221 default:
222 errx(1, "Unknown -T option `%c'", *p); 222 errx(1, "Unknown -T option `%c'", *p);
223 } 223 }
224 break; 224 break;
225 case '?': 225 case '?':
226 default: 226 default:
227 usage(); 227 usage();
228 } 228 }
229 argc -= optind; 229 argc -= optind;
230 argv += optind; 230 argv += optind;
231 231
232 if (argc != 1) { 232 if (argc != 1) {
233 if (!iflag) 233 if (!iflag)
234 usage(); 234 usage();
235 if (!(pw = getpwuid(getuid()))) { 235 if (!(pw = getpwuid(getuid()))) {
236 syslog(LOG_ERR, "%s: no such user uid %u.", 236 syslog(LOG_ERR, "%s: no such user uid %u.",
237 getprogname(), getuid()); 237 getprogname(), getuid());
238 exit(1); 238 exit(1);
239 } 239 }
240 } 240 }
241 else if (!(pw = getpwnam(*argv))) { 241 else if (!(pw = getpwnam(*argv))) {
242 syslog(LOG_ERR, "%s: no such user %s.", 242 syslog(LOG_ERR, "%s: no such user %s.",
243 getprogname(), *argv); 243 getprogname(), *argv);
244 exit(1); 244 exit(1);
245 } 245 }
246 if (chdir(pw->pw_dir) == -1 &&  246 if (chdir(pw->pw_dir) == -1 &&
247 (dbprefix[0] != '/' || msgfile[0] != '/')) { 247 (dbprefix[0] != '/' || msgfile[0] != '/')) {
248 syslog(LOG_ERR, "%s: no such directory %s.", 248 syslog(LOG_ERR, "%s: no such directory %s.",
249 getprogname(), pw->pw_dir); 249 getprogname(), pw->pw_dir);
250 exit(1); 250 exit(1);
251 } 251 }
252 252
253 opendb(); 253 opendb();
254 254
255 if (interval != -1) 255 if (interval != -1)
256 setinterval((time_t)interval); 256 setinterval((time_t)interval);
257 257
258 if (iflag) { 258 if (iflag) {
259 (void)(db->close)(db); 259 (void)(db->close)(db);
260 exit(0); 260 exit(0);
261 } 261 }
262 262
263 if (!(cur = malloc((size_t)sizeof(alias_t)))) { 263 if (!(cur = malloc((size_t)sizeof(alias_t)))) {
264 syslog(LOG_ERR, "%s: %m", getprogname()); 264 syslog(LOG_ERR, "%s: %m", getprogname());
265 (void)(db->close)(db); 265 (void)(db->close)(db);
266 exit(1); 266 exit(1);
267 } 267 }
268 cur->name = pw->pw_name; 268 cur->name = pw->pw_name;
269 cur->next = names; 269 cur->next = names;
270 names = cur; 270 names = cur;
271 271
272 if ((rv = readheaders()) != -1) { 272 if ((rv = readheaders()) != -1) {
273 (void)(db->close)(db); 273 (void)(db->close)(db);
274 exit(rv); 274 exit(rv);
275 } 275 }
276  276
277 if (!recent()) { 277 if (!recent()) {
278 setreply(); 278 setreply();
279 (void)(db->close)(db); 279 (void)(db->close)(db);
280 sendmessage(pw->pw_name); 280 sendmessage(pw->pw_name);
281 } 281 }
282 else 282 else
283 (void)(db->close)(db); 283 (void)(db->close)(db);
284 exit(0); 284 exit(0);
285 /* NOTREACHED */ 285 /* NOTREACHED */
286} 286}
287 287
288static void 288static void
289opendb(void) 289opendb(void)
290{ 290{
291 char path[MAXPATHLEN]; 291 char path[MAXPATHLEN];
292 292
293 (void)snprintf(path, sizeof(path), "%s.db", dbprefix); 293 (void)snprintf(path, sizeof(path), "%s.db", dbprefix);
294 db = dbopen(path, O_CREAT|O_RDWR | (iflag ? O_TRUNC : 0), 294 db = dbopen(path, O_CREAT|O_RDWR | (iflag ? O_TRUNC : 0),
295 S_IRUSR|S_IWUSR, DB_HASH, NULL); 295 S_IRUSR|S_IWUSR, DB_HASH, NULL);
296 296
297 if (!db) { 297 if (!db) {
298 syslog(LOG_ERR, "%s: %s: %m", getprogname(), path); 298 syslog(LOG_ERR, "%s: %s: %m", getprogname(), path);
299 exit(1); 299 exit(1);
300 } 300 }
301} 301}
302 302
303/* 303/*
304 * readheaders -- 304 * readheaders --
305 * read mail headers 305 * read mail headers
306 */ 306 */
307static int 307static int
308readheaders(void) 308readheaders(void)
309{ 309{
310 alias_t *cur; 310 alias_t *cur;
311 char *p; 311 char *p;
312 int tome, cont; 312 int tome, cont;
313 char buf[MAXLINE]; 313 char buf[MAXLINE];
314 314
315 cont = tome = 0; 315 cont = tome = 0;
316#define COMPARE(a, b) strncmp(a, b, sizeof(b) - 1) 316#define COMPARE(a, b) strncmp(a, b, sizeof(b) - 1)
317#define CASECOMPARE(a, b) strncasecmp(a, b, sizeof(b) - 1) 317#define CASECOMPARE(a, b) strncasecmp(a, b, sizeof(b) - 1)
318 while (fgets(buf, sizeof(buf), stdin) && *buf != '\n') 318 while (fgets(buf, sizeof(buf), stdin) && *buf != '\n')
319 switch(*buf) { 319 switch(*buf) {
320 case 'F': /* "From " or "From:" */ 320 case 'F': /* "From " or "From:" */
321 cont = 0; 321 cont = 0;
322 if (COMPARE(buf, "From ") == 0) 322 if (COMPARE(buf, "From ") == 0)
323 getfrom(buf + sizeof("From ") - 1); 323 getfrom(buf + sizeof("From ") - 1);
324 if ((fflag & FROM_FROM) != 0 && 324 if ((fflag & FROM_FROM) != 0 &&
325 COMPARE(buf, "From:") == 0) 325 COMPARE(buf, "From:") == 0)
326 getfrom(buf + sizeof("From:") - 1); 326 getfrom(buf + sizeof("From:") - 1);
327 break; 327 break;
328 case 'P': /* "Precedence:" */ 328 case 'P': /* "Precedence:" rfc 2076 ch 3.9 */
329 cont = 0; 329 cont = 0;
330 if (CASECOMPARE(buf, "Precedence") != 0 || 330 if (CASECOMPARE(buf, "Precedence") != 0 ||
331 (buf[10] != ':' && buf[10] != ' ' && 331 (buf[10] != ':' && buf[10] != ' ' &&
332 buf[10] != '\t')) 332 buf[10] != '\t'))
333 break; 333 break;
334 if ((p = strchr(buf, ':')) == NULL) 334 if ((p = strchr(buf, ':')) == NULL)
335 break; 335 break;
336 while (*++p && isspace((unsigned char)*p)) 336 while (*++p && isspace((unsigned char)*p))
337 continue; 337 continue;
338 if (!*p) 338 if (!*p)
339 break; 339 break;
340 if (CASECOMPARE(p, "junk") == 0 || 340 if (CASECOMPARE(p, "junk") == 0 ||
341 CASECOMPARE(p, "bulk") == 0|| 341 CASECOMPARE(p, "bulk") == 0||
342 CASECOMPARE(p, "list") == 0) 342 CASECOMPARE(p, "list") == 0)
343 exit(0); 343 exit(0);
344 break; 344 break;
345 case 'C': /* "Cc:" */ 345 case 'C': /* "Cc:" */
346 if (COMPARE(buf, "Cc:")) 346 if (COMPARE(buf, "Cc:"))
347 break; 347 break;
348 cont = 1; 348 cont = 1;
349 goto findme; 349 goto findme;
350 case 'T': /* "To:" */ 350 case 'T': /* "To:" */
351 if (COMPARE(buf, "To:")) 351 if (COMPARE(buf, "To:"))
352 break; 352 break;
353 cont = 1; 353 cont = 1;
354 goto findme; 354 goto findme;
355 case 'A': /* "Apparently-To:" */ 355 case 'A':
356 if ((tflag & APPARENTLY_TO) == 0 || 356 /* "Apparently-To:" */
357 COMPARE(buf, "Apparently-To:") != 0) 357 if ((tflag & APPARENTLY_TO) != 0 &&
 358 COMPARE(buf, "Apparently-To:") == 0) {
 359 cont = 1;
 360 goto findme;
 361 }
 362 /* "Auto-Submitted:" rfc 3834 ch 5 */
 363 cont = 0;
 364 if (CASECOMPARE(buf, "Auto-Submitted") != 0 ||
 365 (buf[14] != ':' && buf[14] != ' ' &&
 366 buf[14] != '\t'))
358 break; 367 break;
359 cont = 1; 368 if ((p = strchr(buf, ':')) == NULL)
360 goto findme; 369 break;
 370 while (*++p && isspace((unsigned char)*p))
 371 continue;
 372 if (CASECOMPARE(p, "no") != 0 )
 373 exit(0);
 374 break;
361 case 'D': /* "Delivered-To:" */ 375 case 'D': /* "Delivered-To:" */
362 if ((tflag & DELIVERED_TO) == 0 || 376 if ((tflag & DELIVERED_TO) == 0 ||
363 COMPARE(buf, "Delivered-To:") != 0) 377 COMPARE(buf, "Delivered-To:") != 0)
364 break; 378 break;
365 cont = 1; 379 cont = 1;
366 goto findme; 380 goto findme;
367 case 'R': /* "Return-Path:" */ 381 case 'R': /* "Return-Path:" */
368 cont = 0; 382 cont = 0;
369 if ((fflag & RETURN_PATH_FROM) != 0 && 383 if ((fflag & RETURN_PATH_FROM) != 0 &&
370 COMPARE(buf, "Return-Path:") == 0) 384 COMPARE(buf, "Return-Path:") == 0)
371 getfrom(buf + sizeof("Return-Path:") - 1); 385 getfrom(buf + sizeof("Return-Path:") - 1);
372 break; 386 break;
373 case 'S': /* "Sender:" */ 387 case 'S': /* "Sender:" */
374 cont = 0; 388 cont = 0;
375 if (COMPARE(buf, "Subject:") == 0) { 389 if (COMPARE(buf, "Subject:") == 0) {
376 /* trim leading blanks */ 390 /* trim leading blanks */
377 char *s = NULL; 391 char *s = NULL;
378 for (p = buf + sizeof("Subject:") - 1; *p; p++) 392 for (p = buf + sizeof("Subject:") - 1; *p; p++)
379 if (s == NULL && 393 if (s == NULL &&
380 !isspace((unsigned char)*p)) 394 !isspace((unsigned char)*p))
381 s = p; 395 s = p;
382 /* trim trailing blanks */ 396 /* trim trailing blanks */
383 if (s) { 397 if (s) {
384 for (--p; p != s; p--) 398 for (--p; p != s; p--)
385 if (!isspace((unsigned char)*p)) 399 if (!isspace((unsigned char)*p))
386 break; 400 break;
387 *++p = '\0'; 401 *++p = '\0';
388 } 402 }
389 if (s) { 403 if (s) {
390 (void)strlcpy(subject, s, sizeof(subject)); 404 (void)strlcpy(subject, s, sizeof(subject));
391 } else { 405 } else {
392 subject[0] = '\0'; 406 subject[0] = '\0';
393 } 407 }
394 } 408 }
395 if ((fflag & SENDER_FROM) != 0 && 409 if ((fflag & SENDER_FROM) != 0 &&
396 COMPARE(buf, "Sender:") == 0) 410 COMPARE(buf, "Sender:") == 0)
397 getfrom(buf + sizeof("Sender:") - 1); 411 getfrom(buf + sizeof("Sender:") - 1);
398 break; 412 break;
399 default: 413 default:
400 if (!isspace((unsigned char)*buf) || !cont || tome) { 414 if (!isspace((unsigned char)*buf) || !cont || tome) {
401 cont = 0; 415 cont = 0;
402 break; 416 break;
403 } 417 }
404findme: for (cur = names; !tome && cur; cur = cur->next) 418findme: for (cur = names; !tome && cur; cur = cur->next)
405 tome += nsearch(cur->name, buf); 419 tome += nsearch(cur->name, buf);
406 } 420 }
407 if (!toanybody && !tome) 421 if (!toanybody && !tome)
408 return 0; 422 return 0;
409 if (!*from) { 423 if (!*from) {
410 syslog(LOG_ERR, "%s: no initial \"From\" line.", 424 syslog(LOG_ERR, "%s: no initial \"From\" line.",
411 getprogname()); 425 getprogname());
412 return 1; 426 return 1;
413 } 427 }
414 return -1; 428 return -1;
415} 429}
416 430
417/* 431/*
418 * nsearch -- 432 * nsearch --
419 * do a nice, slow, search of a string for a substring. 433 * do a nice, slow, search of a string for a substring.
420 */ 434 */
421static int 435static int
422nsearch(const char *name, const char *str) 436nsearch(const char *name, const char *str)
423{ 437{
424 size_t len; 438 size_t len;
425 439
426 for (len = strlen(name); *str; ++str) 440 for (len = strlen(name); *str; ++str)
427 if (!strncasecmp(name, str, len)) 441 if (!strncasecmp(name, str, len))
428 return(1); 442 return(1);
429 return(0); 443 return(0);
430} 444}
431 445
432/* 446/*
433 * getfrom -- 447 * getfrom --
434 * return the first string in the buffer, stripping leading and trailing 448 * return the first string in the buffer, stripping leading and trailing
435 * blanks and <>. 449 * blanks and <>.
436 */ 450 */
437void 451void
438getfrom(char *buf) 452getfrom(char *buf)
439{ 453{
440 char *s, *p; 454 char *s, *p;
441 455
442 if ((s = strchr(buf, '<')) != NULL) 456 if ((s = strchr(buf, '<')) != NULL)
443 s++; 457 s++;
444 else 458 else
445 s = buf; 459 s = buf;
446 460
447 for (; *s && isspace((unsigned char)*s); s++) 461 for (; *s && isspace((unsigned char)*s); s++)
448 continue; 462 continue;
449 for (p = s; *p && !isspace((unsigned char)*p); p++) 463 for (p = s; *p && !isspace((unsigned char)*p); p++)
450 continue; 464 continue;
451 465
452 if (*--p == '>') 466 if (*--p == '>')
453 *p = '\0'; 467 *p = '\0';
454 else 468 else
455 *++p = '\0'; 469 *++p = '\0';
456 470
457 if (junkmail(s)) 471 if (junkmail(s))
458 exit(0); 472 exit(0);
459 473
460 if (!*from) 474 if (!*from)
461 (void)strlcpy(from, s, sizeof(from)); 475 (void)strlcpy(from, s, sizeof(from));
462} 476}
463 477
464/* 478/*
465 * junkmail -- 479 * junkmail --
466 * read the header and return if automagic/junk/bulk/list mail 480 * read the header and return if automagic/junk/bulk/list mail
467 */ 481 */
468static int 482static int
469junkmail(const char *addr) 483junkmail(const char *addr)
470{ 484{
471 static struct ignore { 485 static struct ignore {
472 const char *name; 486 const char *name;
473 size_t len; 487 size_t len;
474 } ignore[] = { 488 } ignore[] = {
475#define INIT(a) { a, sizeof(a) - 1 } 489#define INIT(a) { a, sizeof(a) - 1 }
476 INIT("-request"), 490 INIT("-request"),
477 INIT("postmaster"), 491 INIT("postmaster"),
478 INIT("uucp"), 492 INIT("uucp"),
479 INIT("mailer-daemon"), 493 INIT("mailer-daemon"),
480 INIT("mailer"), 494 INIT("mailer"),
481 INIT("-relay"), 495 INIT("-relay"),
482 {NULL, 0 } 496 {NULL, 0 }
483 }; 497 };
484 struct ignore *cur; 498 struct ignore *cur;
485 size_t len; 499 size_t len;
486 const char *p; 500 const char *p;
487 501
488 /* 502 /*
489 * This is mildly amusing, and I'm not positive it's right; trying 503 * This is mildly amusing, and I'm not positive it's right; trying
490 * to find the "real" name of the sender, assuming that addresses 504 * to find the "real" name of the sender, assuming that addresses
491 * will be some variant of: 505 * will be some variant of:
492 * 506 *
493 * From site!site!SENDER%site.domain%site.domain@site.domain 507 * From site!site!SENDER%site.domain%site.domain@site.domain
494 */ 508 */
495 if (!(p = strchr(addr, '%'))) 509 if (!(p = strchr(addr, '%')))
496 if (!(p = strchr(addr, '@'))) { 510 if (!(p = strchr(addr, '@'))) {
497 if ((p = strrchr(addr, '!')) != NULL) 511 if ((p = strrchr(addr, '!')) != NULL)
498 ++p; 512 ++p;
499 else 513 else
500 p = addr; 514 p = addr;
501 for (; *p; ++p) 515 for (; *p; ++p)
502 continue; 516 continue;
503 } 517 }
504 len = p - addr; 518 len = p - addr;
505 for (cur = ignore; cur->name; ++cur) 519 for (cur = ignore; cur->name; ++cur)
506 if (len >= cur->len && 520 if (len >= cur->len &&
507 !strncasecmp(cur->name, p - cur->len, cur->len)) 521 !strncasecmp(cur->name, p - cur->len, cur->len))
508 return(1); 522 return(1);
509 return(0); 523 return(0);
510} 524}
511 525
512#define VIT "__VACATION__INTERVAL__TIMER__" 526#define VIT "__VACATION__INTERVAL__TIMER__"
513 527
514/* 528/*
515 * recent -- 529 * recent --
516 * find out if user has gotten a vacation message recently. 530 * find out if user has gotten a vacation message recently.
517 * use memmove for machines with alignment restrictions 531 * use memmove for machines with alignment restrictions
518 */ 532 */
519static int 533static int
520recent(void) 534recent(void)
521{ 535{
522 DBT key, data; 536 DBT key, data;
523 time_t then, next; 537 time_t then, next;
524 538
525 /* get interval time */ 539 /* get interval time */
526 key.data = (void *)(intptr_t)VIT; 540 key.data = (void *)(intptr_t)VIT;
527 key.size = sizeof(VIT); 541 key.size = sizeof(VIT);
528 if ((db->get)(db, &key, &data, 0)) 542 if ((db->get)(db, &key, &data, 0))
529 next = SECSPERDAY * DAYSPERWEEK; 543 next = SECSPERDAY * DAYSPERWEEK;
530 else 544 else
531 (void)memmove(&next, data.data, sizeof(next)); 545 (void)memmove(&next, data.data, sizeof(next));
532 546
533 /* get record for this address */ 547 /* get record for this address */
534 key.data = from; 548 key.data = from;
535 key.size = strlen(from); 549 key.size = strlen(from);
536 if (!(db->get)(db, &key, &data, 0)) { 550 if (!(db->get)(db, &key, &data, 0)) {
537 (void)memmove(&then, data.data, sizeof(then)); 551 (void)memmove(&then, data.data, sizeof(then));
538 if (next == (time_t)LONG_MAX || /* XXX */ 552 if (next == (time_t)LONG_MAX || /* XXX */
539 then + next > time(NULL)) 553 then + next > time(NULL))
540 return(1); 554 return(1);
541 } 555 }
542 return(0); 556 return(0);
543} 557}
544 558
545/* 559/*
546 * setinterval -- 560 * setinterval --
547 * store the reply interval 561 * store the reply interval
548 */ 562 */
549static void 563static void
550setinterval(time_t interval) 564setinterval(time_t interval)
551{ 565{
552 DBT key, data; 566 DBT key, data;
553 567
554 key.data = (void *)(intptr_t)VIT; 568 key.data = (void *)(intptr_t)VIT;
555 key.size = sizeof(VIT); 569 key.size = sizeof(VIT);
556 data.data = &interval; 570 data.data = &interval;
557 data.size = sizeof(interval); 571 data.size = sizeof(interval);
558 (void)(db->put)(db, &key, &data, 0); 572 (void)(db->put)(db, &key, &data, 0);
559} 573}
560 574
561/* 575/*
562 * setreply -- 576 * setreply --
563 * store that this user knows about the vacation. 577 * store that this user knows about the vacation.
564 */ 578 */
565static void 579static void
566setreply(void) 580setreply(void)
567{ 581{
568 DBT key, data; 582 DBT key, data;
569 time_t now; 583 time_t now;
570 584
571 key.data = from; 585 key.data = from;
572 key.size = strlen(from); 586 key.size = strlen(from);
573 (void)time(&now); 587 (void)time(&now);
574 data.data = &now; 588 data.data = &now;
575 data.size = sizeof(now); 589 data.size = sizeof(now);
576 (void)(db->put)(db, &key, &data, 0); 590 (void)(db->put)(db, &key, &data, 0);
577} 591}
578 592
579/* 593/*
580 * sendmessage -- 594 * sendmessage --
581 * exec sendmail to send the vacation file to sender 595 * exec sendmail to send the vacation file to sender
582 */ 596 */
583static void 597static void
584sendmessage(const char *myname) 598sendmessage(const char *myname)
585{ 599{
586 FILE *mfp, *sfp; 600 FILE *mfp, *sfp;
587 int i; 601 int i;
588 int pvect[2]; 602 int pvect[2];
589 char buf[MAXLINE]; 603 char buf[MAXLINE];
590 604
591 mfp = fopen(msgfile, "r"); 605 mfp = fopen(msgfile, "r");
592 if (mfp == NULL) { 606 if (mfp == NULL) {
593 syslog(LOG_ERR, "%s: no `%s' file for `%s'.", getprogname(), 607 syslog(LOG_ERR, "%s: no `%s' file for `%s'.", getprogname(),
594 myname, msgfile); 608 myname, msgfile);
595 exit(1); 609 exit(1);
596 } 610 }
597 611
598 if (debug) { 612 if (debug) {
599 sfp = stdout; 613 sfp = stdout;
600 } else { 614 } else {
601 if (pipe(pvect) < 0) { 615 if (pipe(pvect) < 0) {
602 syslog(LOG_ERR, "%s: pipe: %m", getprogname()); 616 syslog(LOG_ERR, "%s: pipe: %m", getprogname());
603 exit(1); 617 exit(1);
604 } 618 }
605 i = vfork(); 619 i = vfork();
606 if (i < 0) { 620 if (i < 0) {
607 syslog(LOG_ERR, "%s: fork: %m", getprogname()); 621 syslog(LOG_ERR, "%s: fork: %m", getprogname());
608 exit(1); 622 exit(1);
609 } 623 }
610 if (i == 0) { 624 if (i == 0) {
611 (void)dup2(pvect[0], 0); 625 (void)dup2(pvect[0], 0);
612 (void)close(pvect[0]); 626 (void)close(pvect[0]);
613 (void)close(pvect[1]); 627 (void)close(pvect[1]);
614 (void)close(fileno(mfp)); 628 (void)close(fileno(mfp));
615 (void)execl(_PATH_SENDMAIL, "sendmail", "-f", myname, 629 (void)execl(_PATH_SENDMAIL, "sendmail", "-f", myname,
616 "--", from, NULL); 630 "--", from, NULL);
617 syslog(LOG_ERR, "%s: can't exec %s: %m", 631 syslog(LOG_ERR, "%s: can't exec %s: %m",
618 getprogname(), _PATH_SENDMAIL); 632 getprogname(), _PATH_SENDMAIL);
619 _exit(1); 633 _exit(1);
620 } 634 }
621 (void)close(pvect[0]); 635 (void)close(pvect[0]);
622 sfp = fdopen(pvect[1], "w"); 636 sfp = fdopen(pvect[1], "w");
623 if (sfp == NULL) { 637 if (sfp == NULL) {
624 syslog(LOG_ERR, "%s: can't fdopen %d: %m", 638 syslog(LOG_ERR, "%s: can't fdopen %d: %m",
625 getprogname(), pvect[1]); 639 getprogname(), pvect[1]);
626 _exit(1); 640 _exit(1);
627 } 641 }
628 }  642 }
629 (void)fprintf(sfp, "To: %s\n", from); 643 (void)fprintf(sfp, "To: %s\n", from);
630 (void)fputs("Auto-Submitted: auto-replied\n", sfp); 644 (void)fputs("Auto-Submitted: auto-replied\n", sfp);
 645 (void)fputs("Precedence: bulk\n", sfp);
631 while (fgets(buf, sizeof buf, mfp) != NULL) { 646 while (fgets(buf, sizeof buf, mfp) != NULL) {
632 char *p; 647 char *p;
633 if ((p = strstr(buf, "$SUBJECT")) != NULL) { 648 if ((p = strstr(buf, "$SUBJECT")) != NULL) {
634 *p = '\0'; 649 *p = '\0';
635 (void)fputs(buf, sfp); 650 (void)fputs(buf, sfp);
636 (void)fputs(subject, sfp); 651 (void)fputs(subject, sfp);
637 p += sizeof("$SUBJECT") - 1; 652 p += sizeof("$SUBJECT") - 1;
638 (void)fputs(p, sfp); 653 (void)fputs(p, sfp);
639 } else 654 } else
640 (void)fputs(buf, sfp); 655 (void)fputs(buf, sfp);
641 } 656 }
642 (void)fclose(mfp); 657 (void)fclose(mfp);
643 if (sfp != stdout) 658 if (sfp != stdout)
644 (void)fclose(sfp); 659 (void)fclose(sfp);
645} 660}
646 661
647static void 662static void
648usage(void) 663usage(void)
649{ 664{
650 665
651 syslog(LOG_ERR, "uid %u: Usage: %s [-dIij] [-a alias] [-f database_file] [-F F|R|S] [-m message_file] [-s sender] [-t interval] [-T A|D]" 666 syslog(LOG_ERR, "uid %u: Usage: %s [-dIij] [-a alias] [-f database_file] [-F F|R|S] [-m message_file] [-s sender] [-t interval] [-T A|D]"
652 " login", getuid(), getprogname()); 667 " login", getuid(), getprogname());
653 exit(1); 668 exit(1);
654} 669}