xref: /illumos-gate/usr/src/cmd/mail/gethead.c (revision e77c795bcbe51aebd7579fe13cbf2a6d56eca47f)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27 /*	  All Rights Reserved  	*/
28 
29 #include "mail.h"
30 
31 #define	MAXHDRSIZE	100	/* Maximum length of header line */
32 #define	MAXUNAME	20	/* Maximum length of user name */
33 
34 /*
35  *	display headers, indicating current and status
36  *
37  *	current is the displacement into the mailfile of the
38  *	current letter
39  *
40  *	all indicates how many headers should be shown.
41  *		0	->	show window +/-6 around current
42  *		1	->	show all messages
43  *		2	->	show deleted messages
44  *
45  *	Only 100 characters of the From (first) header line will
46  *	be read in.  This line is assumed to be in the following
47  *	format:
48  *		From <sender address> <date>
49  *	where
50  *		<sender address> is either a UUCP-style (sysa!sysb!user)
51  *		or domain-style address (user@host).
52  *
53  *	If the sender address contains a UUCP-style address, then
54  *	the user name displayed is made up of the characters following
55  *	the final '!' in the sender address, otherwise the sender
56  *	address is considered to be the user name.
57  *
58  *	The maximum number of characters of a user name displayed
59  *	is 19.
60  *
61  */
62 int
63 gethead(int current, int all)
64 {
65 
66 	int	displayed = 0;
67 	FILE	*file;
68 	char	*hold;
69 	char	holdval[MAXHDRSIZE];
70 	char	*wline;
71 	char	wlineval[MAXHDRSIZE];
72 	int	ln;
73 	char	mark;
74 	int	rc, size, start, stop, ix;
75 	char	userval[MAXUNAME];
76 	char	*uucpptr;
77 	int	uucpstart;
78 	int	unamechars = MAXUNAME - 1;
79 	int	sender_size;
80 
81 	hold = holdval;
82 	wline = wlineval;
83 
84 	printf("%d letters found in %s, %d scheduled for deletion, "
85 	    "%d newly arrived\n", nlet, mailfile, changed, nlet - onlet);
86 
87 	if (all == 2 && !changed)
88 		return (0);
89 
90 	file = doopen(lettmp, "r", E_TMP);
91 	if (!flgr) {
92 		stop = current - 6;
93 		if (stop < -1) stop = -1;
94 		start = current + 5;
95 		if (start > nlet - 1) start = nlet - 1;
96 		if (all) {
97 			start = nlet -1;
98 			stop = -1;
99 		}
100 	} else {
101 		stop = current + 6;
102 		if (stop > nlet) stop = nlet;
103 		start = current - 5;
104 		if (start < 0) start = 0;
105 		if (all) {
106 			start = 0;
107 			stop = nlet;
108 		}
109 	}
110 	for (ln = start; ln != stop; ln = flgr ? ln + 1 : ln - 1) {
111 		size = let[ln+1].adr - let[ln].adr;
112 		if ((rc = fseek(file, let[ln].adr, 0)) != 0) {
113 			errmsg(E_FILE, "Cannot seek header");
114 			fclose(file);
115 			return (1);
116 		}
117 		if (fgets(wline, MAXHDRSIZE, file) == NULL) {
118 			errmsg(E_FILE, "Cannot read header");
119 			fclose(file);
120 			return (1);
121 		}
122 		if ((rc = strncmp(wline, header[H_FROM].tag, 5)) != SAME) {
123 			errmsg(E_FILE, "Invalid header encountered");
124 			fclose(file);
125 			return (1);
126 		}
127 
128 		/* skip past trailing white space after header tag */
129 		for (rc = 5; wline[rc] == ' ' || wline[rc] == '\t'; ++rc)
130 			;
131 		(void) strlcpy(hold, wline + rc, MAXHDRSIZE);
132 		fgets(wline, MAXHDRSIZE, file);
133 
134 		while (((rc = strncmp(wline,
135 		    header[H_FROM1].tag, 6)) == SAME) &&
136 		    (substr(wline, "remote from ") != -1)) {
137 			(void) strlcpy(hold, wline + 6, MAXHDRSIZE);
138 			fgets(wline, MAXHDRSIZE, file);
139 		}
140 
141 
142 		/*
143 		 * If UUCP-style sender address, then read past
144 		 * last "!" to get the start of the user name.
145 		 */
146 		sender_size = strcspn(hold, " \t");
147 		uucpstart = 0;
148 		if ((uucpptr = strrchr(hold, '!')) != NULL) {
149 			uucpstart = uucpptr - hold + 1;
150 			if (uucpstart > sender_size) {
151 				uucpstart = 0;
152 			}
153 		}
154 
155 		/* Get the user name out of the sender address. */
156 		for (ix = 0, rc = uucpstart; ix < unamechars &&
157 		    hold[rc] != ' ' && hold[rc] != '\t' &&
158 		    rc < sender_size; ++rc) {
159 			userval[ix++] = hold[rc];
160 		}
161 		if ((ix > 0) && (userval[ix - 1] == '\n')) {
162 			userval[ix - 1] = '\0';
163 		} else {
164 			userval[ix] = '\0';
165 		}
166 
167 		/*
168 		 * Skip past the rest of the sender address, and
169 		 * delimiting white space.
170 		 */
171 		for (; hold[rc] != '\0' && hold[rc] != ' ' &&
172 		    hold[rc] != '\t'; ++rc)
173 			;
174 		for (; hold[rc] == ' ' || hold[rc] == '\t'; ++rc)
175 			;
176 
177 		/* Get the date information. */
178 		(void) strlcpy(wline, hold + rc, MAXHDRSIZE);
179 		for (rc = 0; wline[rc] != '\0' && wline[rc] != '\n'; ++rc)
180 			;
181 		wline[rc] = '\0';
182 
183 		if (!flgh && current == ln) mark = '>';
184 		else mark = ' ';
185 
186 		if (all == 2) {
187 			if (displayed >= changed) {
188 				fclose(file);
189 				return (0);
190 			}
191 			if (let[ln].change == ' ') continue;
192 		}
193 
194 		printf("%c %3d  %c  %-5d  %-10s  %s\n", mark, ln + 1,
195 		    let[ln].change, size, userval, wline);
196 		displayed++;
197 	}
198 	fclose(file);
199 	return (0);
200 }
201 
202 void
203 tmperr(void)
204 {
205 	fclose(tmpf);
206 	errmsg(E_TMP, "");
207 }
208 
209 /*
210  *	Write a string out to tmp file, with error checking.
211  *	Return 1 on success, else 0
212  */
213 int
214 wtmpf(char *str, int length)
215 {
216 	if (fwrite(str, 1, length, tmpf) != length) {
217 		tmperr();
218 		return (0);
219 	}
220 	return (1);
221 }
222 
223 /*
224  *	Read a line from stdin, assign it to line and
225  *	return number of bytes in length
226  */
227 int
228 getaline(char *ptr2line, int max, FILE *f)
229 {
230 	int	i, ch;
231 	for (i = 0; i < max-1 && (ch = getc(f)) != EOF; )
232 		if ((ptr2line[i++] = ch) == '\n') break;
233 	ptr2line[i] = '\0';
234 	return (i);
235 }
236 
237 /*
238  *	Make temporary file for letter
239  */
240 void
241 mktmp(void)
242 {
243 	static char tmpl[] = "/var/tmp/mailXXXXXX";
244 	int fd = mkstemp(lettmp = tmpl);
245 
246 	if (fd < 0 || (tmpf = fdopen(fd, "w+")) == NULL) {
247 		fprintf(stderr,
248 		    "%s: Can't open '%s', type: w+\n", program, lettmp);
249 		done(0);
250 	}
251 }
252 
253 /*
254  * Get a number from user's reply,
255  * return its value or zero if none present, -1 on error
256  */
257 int
258 getnumbr(char *s)
259 {
260 	int	k = 0;
261 
262 	while (*s == ' ' || *s == '\t') s++;
263 
264 	if (*s != '\0') {
265 		if ((k = atoi(s)) != 0)
266 			if (!validmsg(k))
267 				return (-1);
268 
269 		for (; *s >= '0' && *s <= '9'; ) s++;
270 		if (*s != '\0' && *s != '\n') {
271 			printf("Illegal numeric\n");
272 			return (-1);
273 		}
274 		return (k);
275 	}
276 	return (0);
277 }
278 
279 /*
280  *	If valid msgnum return 1,
281  *		else print message and return 0
282  */
283 int
284 validmsg(int i)
285 {
286 	if ((i < 0) || (i > nlet)) {
287 		printf("No such message\n");
288 		return (0);
289 	}
290 	return (1);
291 }
292 
293 /*
294  *	Set letter to passed status, and adjust changed as necessary
295  */
296 void
297 setletr(int letter, int status)
298 {
299 	if (status == ' ') {
300 		if (let[letter].change != ' ')
301 			if (changed) changed--;
302 	} else {
303 		if (let[letter].change == ' ') changed++;
304 	}
305 	let[letter].change = status;
306 }
307