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