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 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
23 /* All Rights Reserved */
24
25
26 /*
27 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
29 */
30
31 #pragma ident "%Z%%M% %I% %E% SMI"
32
33 #include "mail.h"
34 /*
35 * Print mail entries
36 */
37 void
printmail()38 printmail()
39 {
40 static char pn[] = "printmail";
41 int flg, curlet, showlet, k, print, aret, stret, rc;
42 int nsmbox = 0; /* 1 ==> mailbox is in non-standard place */
43 int sav_j = -1;
44 char *p, *getarg();
45 struct stat stbuf;
46 struct stat *stbufp;
47 int ttyf = isatty(1) ? TTY : ORDINARY;
48 char readbuf[LSIZE]; /* holds user's response in interactive mode */
49 char *resp;
50 gid_t savedegid;
51
52 stbufp = &stbuf;
53
54 /*
55 * create working directory mbox name
56 */
57 if ((hmbox = malloc(strlen(home) + strlen(mbox) + 1)) == NULL) {
58 errmsg(E_MBOX, "");
59 return;
60 }
61 cat(hmbox, home, mbox);
62
63 /*
64 * If we are not using an alternate mailfile, then get
65 * the $MAIL value and build the filename for the mailfile.
66 * If $MAIL is set, but is NOT the 'standard' place, then
67 * use it but set flgf to circumvent :saved processing.
68 */
69 if (!flgf) {
70 if ((p = malloc(strlen(maildir) + strlen(my_name) + 1))
71 == NULL) {
72 errmsg(E_MEM, "");
73 return;
74 }
75 cat(p, maildir, my_name);
76 if (((mailfile = getenv("MAIL")) == NULL) ||
77 (strlen(mailfile) == 0)) {
78 /* $MAIL not set, use standard path to mailfile */
79 mailfile = p;
80 } else {
81 if (strcmp(mailfile, p) != 0) {
82 flgf = 1;
83 nsmbox = 1;
84 Dout(pn, 0, "$MAIL ('%s') != standard path\n",
85 mailfile);
86 Dout("", 0, "\tSetting flgf to 1.\n");
87 }
88 free(p);
89 }
90 }
91
92 /*
93 * Get ACCESS and MODIFICATION times of mailfile BEFORE we
94 * use it. This allows us to put them back when we are
95 * done. If we didn't, the shell would think NEW mail had
96 * arrived since the file times would have changed.
97 */
98 stret = CERROR;
99 if (access(mailfile, A_EXIST) == A_OK) {
100 if ((stret = stat(mailfile, stbufp)) != A_OK) {
101 errmsg(E_FILE, "Cannot stat mailfile");
102 return;
103 }
104 mf_gid = stbufp->st_gid;
105 mf_uid = stbufp->st_uid;
106 utimep->actime = stbufp->st_atime;
107 utimep->modtime = stbufp->st_mtime;
108 file_size = stbufp->st_size;
109 }
110
111 /* Open the file as the real gid */
112 savedegid = getegid();
113 (void) setegid(getgid());
114 malf = fopen(mailfile, "r");
115 (void) setegid(savedegid);
116 /*
117 * stat succeeded, but we cannot access the mailfile
118 */
119 if (stret == CSUCCESS && malf == NULL) {
120 char buf[MAXFILENAME+50];
121 (void) snprintf(buf, sizeof (buf),
122 "Invalid permissions on %s", mailfile);
123 errmsg(E_PERM, buf);
124 return;
125 } else
126 /*
127 * using an alternate mailfile, but we failed on access
128 */
129 if (!nsmbox && flgf && (malf == NULL)) {
130 errmsg(E_FILE, "Cannot open mailfile");
131 return;
132 }
133 /*
134 * we failed to access OR the file is empty
135 */
136 else if ((malf == NULL) || (stbuf.st_size == 0)) {
137 if (!flge && !flgE) {
138 printf("No mail.\n");
139 }
140 error = E_FLGE;
141 Dout(pn, 0, "error set to %d\n", error);
142 return;
143 }
144 if (flge)
145 return;
146
147 if (flgE) {
148 if (utimep->modtime < utimep->actime) {
149 error = E_FLGE_OM;
150 Dout(pn, 0, "error set to %d\n", error);
151 }
152 return;
153 }
154 /*
155 * Secure the mailfile to guarantee integrity
156 */
157 lock(my_name);
158
159 /*
160 * copy mail to temp file and mark each letter in the
161 * let array --- mailfile is still locked !!!
162 */
163 mktmp();
164 copymt(malf, tmpf);
165 onlet = nlet;
166 fclose(malf);
167 fclose(tmpf);
168 unlock(); /* All done, OK to unlock now */
169 tmpf = doopen(lettmp, "r+", E_TMP);
170 changed = 0;
171 print = 1;
172 curlet = 0;
173 while (curlet < nlet) {
174 /*
175 * reverse order ?
176 */
177 showlet = flgr ? curlet : nlet - curlet - 1;
178
179 if (setjmp(sjbuf) == 0 && print != 0) {
180 /* -h says to print the headers first */
181 if (flgh) {
182 gethead(showlet, 0);
183 flgh = 0; /* Only once */
184 /* set letter # to invalid # */
185 curlet--;
186 showlet =
187 flgr ? curlet : nlet - curlet - 1;
188 } else {
189 if (showlet != sav_j) {
190 /* Looking at new message. */
191 /* Reset flag to override */
192 /* non-display of binary */
193 /* contents */
194 sav_j = showlet;
195 pflg = 0;
196 Pflg = flgP;
197 }
198 copylet(showlet, stdout, ttyf);
199 }
200 }
201
202 /*
203 * print only
204 */
205 if (flgp) {
206 curlet++;
207 continue;
208 }
209 /*
210 * Interactive
211 */
212 interactive = 1;
213 setjmp(sjbuf);
214 stat(mailfile, stbufp);
215 if (stbufp->st_size != file_size) {
216 /*
217 * New mail has arrived, load it
218 */
219 k = nlet;
220 lock(my_name);
221 malf = doopen(mailfile, "r", E_FILE);
222 fclose(tmpf);
223 tmpf = doopen(lettmp, "a", E_TMP);
224 fseek(malf, let[nlet].adr, 0);
225 copymt(malf, tmpf);
226 file_size = stbufp->st_size;
227 fclose(malf);
228 fclose(tmpf);
229 unlock();
230 tmpf = doopen(lettmp, "r+", E_TMP);
231 if (++k < nlet)
232 printf("New mail loaded into letters %d - %d\n",
233 k, nlet);
234 else
235 printf("New mail loaded into letter %d\n",
236 nlet);
237 }
238
239 /* read the command */
240 printf("? ");
241 fflush(stdout);
242 fflush(stderr);
243 if (fgets(readbuf, sizeof (readbuf), stdin) == NULL) break;
244 resp = readbuf;
245 while (*resp == ' ' || *resp == '\t') resp++;
246 print = 1;
247 Dout(pn, 0, "resp = '%s'\n", resp);
248 if ((rc = atoi(resp)) != 0) {
249 if (!validmsg(rc)) print = 0;
250 else curlet = flgr ? rc - 1 : nlet - rc;
251 } else switch (resp[0]) {
252 default:
253 printf("Usage:\n");
254 /*
255 * help
256 */
257 case '?':
258 print = 0;
259 for (rc = 0; help[rc]; rc++)
260 printf("%s", help[rc]);
261 break;
262 /*
263 * print message number of current message
264 */
265 case '#':
266 print = 0;
267 if ((showlet == nlet) || (showlet < 0)) {
268 printf("No message selected yet.\n");
269 } else {
270 printf("Current message number is %d\n",
271 showlet+1);
272 }
273 break;
274 /*
275 * headers
276 */
277 case 'h':
278 print = 0;
279 if (resp[2] != 'd' &&
280 resp[2] != 'a' &&
281 (rc = getnumbr(resp+1)) > 0) {
282 showlet = rc - 1;
283 curlet = flgr ? rc - 1 : nlet - rc- 1;
284 }
285 if (rc == -1 && resp[2] != 'a' &&
286 resp[2] != 'd')
287 break;
288 if (resp[2] == 'a') rc = 1;
289 else if (resp[2] == 'd') rc = 2;
290 else rc = 0;
291
292 /*
293 * if (!validmsg(showlet)) break;
294 */
295 gethead(showlet, rc);
296 break;
297 /*
298 * skip entry
299 */
300 case '+':
301 case 'n':
302 case '\n':
303 curlet++;
304 break;
305 case 'P':
306 Pflg++;
307 break;
308 case 'p':
309 pflg++;
310 break;
311 case 'x':
312 changed = 0;
313 case 'q':
314 goto donep;
315 /*
316 * Previous entry
317 */
318 case '^':
319 case '-':
320 if (--curlet < 0) curlet = 0;
321 break;
322 /*
323 * Save in file without header
324 */
325 case 'y':
326 case 'w':
327 /*
328 * Save mail with header
329 */
330 case 's':
331 print = 0;
332 if (!validmsg(curlet)) break;
333 if (resp[1] == '\n' || resp[1] == '\0') {
334 cat(resp+1, hmbox, "");
335 } else if (resp[1] != ' ') {
336 printf("Invalid command\n");
337 break;
338 }
339 umask(umsave);
340 flg = 0;
341 if (getarg(lfil, resp + 1) == NULL) {
342 cat(resp + 1, hmbox, "");
343 }
344 malf = (FILE *)NULL;
345 p = resp + 1;
346 while ((p = getarg(lfil, p)) != NULL) {
347 if (flg) {
348 fprintf(stderr,
349 "%s: File '%s' skipped\n",
350 program, lfil);
351 continue;
352 }
353 malf = NULL;
354 if ((aret = legal(lfil))) {
355 malf = fopen(lfil, "a");
356 }
357 if ((malf == NULL) || (aret == 0)) {
358 fprintf(stderr,
359 "%s: Cannot append to %s\n",
360 program, lfil);
361 flg++;
362 } else if (aret == 2) {
363 chown(lfil, my_euid, my_gid);
364 }
365 if (!flg &&
366 copylet(showlet, malf, resp[0] ==
367 's'? ORDINARY: ZAP) == FALSE) {
368 fprintf(stderr,
369 "%s: Cannot save mail to '%s'\n",
370 program, lfil);
371 flg++;
372 } else
373 Dout(pn, 0, "!saved\n");
374 if (malf != (FILE *)NULL) {
375 fclose(malf);
376 }
377 }
378 umask(7);
379 if (!flg) {
380 setletr(showlet, resp[0]);
381 print = 1;
382 curlet++;
383 }
384 break;
385 /*
386 * Reply to a letter
387 */
388 case 'r':
389 print = 0;
390 if (!validmsg(curlet)) break;
391 replying = 1;
392 for (k = 1; resp[k] == ' ' || resp[k] == '\t';
393 ++k);
394 resp[strlen(resp)-1] = '\0';
395 (void) strlcpy(m_sendto, resp+k,
396 sizeof (m_sendto));
397 goback(showlet);
398 replying = 0;
399 setletr(showlet, resp[0]);
400 break;
401 /*
402 * Undelete
403 */
404 case 'u':
405 print = 0;
406 if ((k = getnumbr(resp+1)) <= 0) k = showlet;
407 else k--;
408 if (!validmsg(k)) break;
409 setletr(k, ' ');
410 break;
411 /*
412 * Mail letter to someone else
413 */
414 case 'm':
415 {
416 reciplist list;
417 print = 0;
418 if (!validmsg(curlet)) break;
419 new_reciplist(&list);
420 flg = 0;
421 k = 0;
422 if (substr(resp, " -") != -1 ||
423 substr(resp, "\t-") != -1) {
424 printf("Only users may be specified\n");
425 break;
426 }
427 p = resp + 1;
428 while ((p = getarg(lfil, p)) != NULL) {
429 char *env;
430 if (lfil[0] == '$') {
431 if (!(env = getenv(&lfil[1]))) {
432 fprintf(stderr,
433 "%s: %s has no value or is not exported.\n",
434 program, lfil);
435 flg++;
436 } else
437 add_recip(&list, env,
438 FALSE);
439 k++;
440 } else if (lfil[0] != '\0') {
441 add_recip(&list, lfil, FALSE);
442 k++;
443 }
444 }
445 (void) strlcpy(Rpath, my_name, sizeof (Rpath));
446 sending = TRUE;
447 flg += sendlist(&list, showlet, 0);
448 sending = FALSE;
449 if (k) {
450 if (!flg) {
451 setletr(showlet, 'm');
452 print = 1;
453 curlet++;
454 }
455 } else
456 printf("Invalid command\n");
457 del_reciplist(&list);
458 break;
459 }
460 /*
461 * Read new letters
462 */
463 case 'a':
464 if (onlet == nlet) {
465 printf("No new mail\n");
466 print = 0;
467 break;
468 }
469 curlet = 0;
470 print = 1;
471 break;
472 /*
473 * Escape to shell
474 */
475 case '!':
476 systm(resp + 1);
477 printf("!\n");
478 print = 0;
479 break;
480 /*
481 * Delete an entry
482 */
483 case 'd':
484 print = 0;
485 k = 0;
486 if (strncmp("dq", resp, 2) != SAME &&
487 strncmp("dp", resp, 2) != SAME)
488 if ((k = getnumbr(resp+1)) == -1) break;
489 if (k == 0) {
490 k = showlet;
491 if (!validmsg(curlet)) break;
492 print = 1;
493 curlet++;
494 } else k--;
495
496 setletr(k, 'd');
497 if (resp[1] == 'p') print = 1;
498 else if (resp[1] == 'q') goto donep;
499 break;
500 }
501 }
502 /*
503 * Copy updated mailfile back
504 */
505 donep:
506 if (changed) {
507 copyback();
508 stamp();
509 }
510 }
511