1 /*
2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  *
5  *	Copyright (c) 1983, 1984, 1986, 1986, 1987, 1988, 1989 AT&T
6  *	  All Rights Reserved
7  */
8 
9 /*
10  *  Vacation
11  *  Copyright (c) 1983  Eric P. Allman
12  *  Berkeley, California
13  *
14  *  Copyright (c) 1983 Regents of the University of California.
15  *  All rights reserved.  The Berkeley software License Agreement
16  *  specifies the terms and conditions for redistribution.
17  */
18 
19 #include <pwd.h>
20 #include <stdio.h>
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <sysexits.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <sm/bitops.h>
28 #include "conf.h"
29 
30 /*
31  *  MAILCOMPAT -- Deliver mail to a user's mailbox with the "From's" stuffed.
32  */
33 
34 typedef int bool;
35 
36 #define	FALSE	0
37 #define	TRUE	1
38 
39 bool	Debug = FALSE;
40 char	*myname;		/* person who is to have their mail filtered */
41 char	*homedir;		/* home directory of said person */
42 char	*AliasList[MAXLINE];	/* list of aliases to allow */
43 char    *fromp;
44 char    *fromuser;
45 int	AliasCount = 0;
46 
47 static char *newstr();
48 
49 int	ask(char *);
50 int	sendmessage(char *);
51 void	AutoInstall(void);
52 void	usrerr(const char *, ...);
53 
54 int
55 main(argc, argv)
56 	int argc;
57 	char **argv;
58 {
59 	register char *p;
60 	struct passwd *pw;
61 	extern char *getfrom();
62 
63 	/* process arguments */
64 	while (--argc > 0 && (p = *++argv) != NULL && *p == '-')
65 	{
66 		switch (*++p)
67 		{
68 		    case 'd':	/* debug */
69 			Debug = TRUE;
70 			break;
71 		    default:
72 			usrerr("Unknown flag -%s", p);
73 			exit(EX_USAGE);
74 		}
75 	}
76 
77 	/* verify recipient argument */
78 	if (argc != 1)
79 	{
80 		if (argc == 0)
81 			AutoInstall();
82 		else
83 			usrerr("Usage: mailcompat username (or) mailcompat -r");
84 		exit(EX_USAGE);
85 	}
86 
87 	myname = p;
88 	/* find user's home directory */
89 	pw = getpwnam(myname);
90 	if (pw == NULL)
91 	{
92 		usrerr("user: %s look up failed, name services outage ?", myname);
93 		exit(EX_TEMPFAIL);
94 	}
95 	homedir = newstr(pw->pw_dir);
96 
97 	/* read message from standard input (just from line) */
98 	fromuser = getfrom(&fromp);
99 	return (sendmessage(fromuser));
100 }
101 
102 /*
103 **  sendmessage -- read message from standard input do the from stuffing
104 **             and forward to /bin/mail, Being sure to delete any
105 **             content-length headers (/bin/mail recalculates them).
106 **
107 **
108 **	Parameters:
109 **		none.
110 **
111 **
112 **	Side Effects:
113 **		Reads first line from standard input.
114 */
115 
116 #define	L_HEADER	"Content-Length:"
117 #define	LL_HEADER	15
118 
119 int
120 sendmessage(from)
121 char *from;
122 {
123 	static char line[MAXLINE];
124 	static char command[MAXLINE];
125 	bool in_body = FALSE;
126 	FILE *mail_fp;
127 	static char user_name[L_cuserid];
128 
129 	if (from == NULL)
130 		from = cuserid(user_name);
131 
132 	snprintf(command, sizeof (command), "/bin/mail -f %s -d %s", from,
133 	    myname);
134 	mail_fp = popen(command, "w");
135 
136 	/* read the  line */
137 	while (fgets(line, sizeof line, stdin) != NULL)
138 	{
139 		if (line[0] == (char)'\n')  /* end of mail headers */
140 			in_body = TRUE;
141 		if (in_body && (strncmp(line, "From ", 5) == 0))
142 			fprintf(mail_fp, ">");
143 		if (in_body || (strncasecmp(line, L_HEADER, LL_HEADER) != 0))
144 			fputs(line, mail_fp);
145 	}
146 	return (pclose(mail_fp));
147 }
148 
149 char *
150 getfrom(shortp)
151 char **shortp;
152 {
153 	static char line[MAXLINE];
154 	register char *p, *start, *at, *bang;
155 	char saveat;
156 
157 	/* read the from line */
158 	if (fgets(line, sizeof line, stdin) == NULL ||
159 	    strncmp(line, "From ", 5) != NULL)
160 	{
161 		usrerr("No initial From line");
162 		exit(EX_USAGE);
163 	}
164 
165 	/* find the end of the sender address and terminate it */
166 	start = &line[5];
167 	p = strchr(start, ' ');
168 	if (p == NULL)
169 	{
170 		usrerr("Funny From line '%s'", line);
171 		exit(EX_USAGE);
172 	}
173 	*p = '\0';
174 
175 	/*
176 	 * Strip all but the rightmost UUCP host
177 	 * to prevent loops due to forwarding.
178 	 * Start searching leftward from the leftmost '@'.
179 	 *	a!b!c!d yields a short name of c!d
180 	 *	a!b!c!d@e yields a short name of c!d@e
181 	 *	e@a!b!c yields the same short name
182 	 */
183 #ifdef VDEBUG
184 printf("start='%s'\n", start);
185 #endif /* VDEBUG */
186 	*shortp = start;			/* assume whole addr */
187 	if ((at = strchr(start, '@')) == NULL)	/* leftmost '@' */
188 		at = p;				/* if none, use end of addr */
189 	saveat = *at;
190 	*at = '\0';
191 	if ((bang = strrchr(start, '!')) != NULL) {	/* rightmost '!' */
192 		char *bang2;
193 		*bang = '\0';
194 		if ((bang2 = strrchr(start, '!')) != NULL) /* 2nd rightmost '!' */
195 			*shortp = bang2 + 1;		/* move past ! */
196 		*bang = '!';
197 	}
198 	*at = saveat;
199 #ifdef VDEBUG
200 printf("place='%s'\n", *shortp);
201 #endif /* VDEBUG */
202 
203 	/* return the sender address */
204 	return newstr(start);
205 }
206 
207 /*
208 **  USRERR -- print user error
209 **
210 **	Parameters:
211 **		f -- format.
212 **
213 **	Returns:
214 **		none.
215 **
216 **	Side Effects:
217 **		none.
218 */
219 
220 void
221 usrerr(const char *f, ...)
222 {
223 	va_list alist;
224 
225 	va_start(alist, f);
226 	(void) fprintf(stderr, "mailcompat: ");
227 	(void) vfprintf(stderr, f, alist);
228 	(void) fprintf(stderr, "\n");
229 	va_end(alist);
230 }
231 
232 /*
233 **  NEWSTR -- copy a string
234 **
235 **	Parameters:
236 **		s -- the string to copy.
237 **
238 **	Returns:
239 **		A copy of the string.
240 **
241 **	Side Effects:
242 **		none.
243 */
244 
245 char *
246 newstr(s)
247 	char *s;
248 {
249 	char *p;
250 	size_t psize = strlen(s) + 1;
251 
252 	p = malloc(psize);
253 	if (p == NULL)
254 	{
255 		usrerr("newstr: cannot alloc memory");
256 		exit(EX_OSERR);
257 	}
258 	strlcpy(p, s, psize);
259 	return (p);
260 }
261 
262 /*
263  * When invoked with no arguments, we fall into an automatic installation
264  * mode, stepping the user through a default installation.
265  */
266 void
267 AutoInstall()
268 {
269 	char forward[MAXLINE];
270 	char line[MAXLINE];
271 	static char user_name[L_cuserid];
272 	FILE *f;
273 
274 	myname = cuserid(user_name);
275 	homedir = getenv("HOME");
276 	if (homedir == NULL) {
277 		usrerr("Home directory unknown");
278 		exit(EX_CONFIG);
279 	}
280 
281 	printf("This program can be used to store your mail in a format\n");
282 	printf("that you can read with SunOS 4.X based mail readers\n");
283 	(void) strlcpy(forward, homedir, sizeof (forward));
284 	(void) strlcat(forward, "/.forward", sizeof (forward));
285 	f = fopen(forward, "r");
286 	if (f) {
287 		printf("You have a .forward file in your home directory");
288 		printf("  containing:\n");
289 		while (fgets(line, MAXLINE, f))
290 			printf("    %s", line);
291 		fclose(f);
292 		if (!ask("Would you like to remove it and disable the mailcompat feature"))
293 			exit(0);
294 		if (unlink(forward))
295 			perror("Error removing .forward file:");
296 		else
297 			printf("Back to normal reception of mail.\n");
298 		exit(0);
299 	}
300 
301 	printf("To enable the mailcompat feature a \".forward\" ");
302 	printf("file is created.\n");
303 	if (!ask("Would you like to enable the mailcompat feature")) {
304 		printf("OK, mailcompat feature NOT enabled.\n");
305 		exit(0);
306 	}
307 	f = fopen(forward, "w");
308 	if (f == NULL) {
309 		perror("Error opening .forward file");
310 		exit(EX_USAGE);
311 	}
312 	fprintf(f, "\"|/usr/bin/mailcompat %s\"\n", myname);
313 	fclose(f);
314 	printf("Mailcompat feature ENABLED.");
315 	printf("Run mailcompat with no arguments to remove it\n");
316 }
317 
318 
319 /*
320  * Ask the user a question until we get a reasonable answer
321  */
322 int
323 ask(prompt)
324 	char *prompt;
325 {
326 	char line[MAXLINE];
327 
328 	for (;;) {
329 		printf("%s? ", prompt);
330 		fflush(stdout);
331 		fgets(line, sizeof (line), stdin);
332 		if (line[0] == 'y' || line[0] == 'Y')
333 			return (TRUE);
334 		if (line[0] == 'n' || line[0] == 'N')
335 			return (FALSE);
336 		printf("Please reply \"yes\" or \"no\" (\'y\' or \'n\')\n");
337 	}
338 	/* NOTREACHED */
339 }
340