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