root/usr/src/cmd/mail/printmail.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/*        All Rights Reserved   */


/*
 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include "mail.h"
/*
 *      Print mail entries
 */
void
printmail()
{
        static char pn[] = "printmail";
        int     flg, curlet, showlet, k, print, aret, stret, rc;
        int     nsmbox = 0;     /* 1 ==> mailbox is in non-standard place */
        int     sav_j = -1;
        char    *p, *getarg();
        struct  stat stbuf;
        struct  stat *stbufp;
        int ttyf = isatty(1) ? TTY : ORDINARY;
        char    readbuf[LSIZE]; /* holds user's response in interactive mode */
        char    *resp;
        gid_t   savedegid;

        stbufp = &stbuf;

        /*
         *      create working directory mbox name
         */
        if ((hmbox = malloc(strlen(home) + strlen(mbox) + 1)) == NULL) {
                errmsg(E_MBOX, "");
                return;
        }
        cat(hmbox, home, mbox);

        /*
         *      If we are not using an alternate mailfile, then get
         *      the $MAIL value and build the filename for the mailfile.
         *      If $MAIL is set, but is NOT the 'standard' place, then
         *      use it but set flgf to circumvent :saved processing.
         */
        if (!flgf) {
                if ((p = malloc(strlen(maildir) + strlen(my_name) + 1))
                                                                == NULL) {
                        errmsg(E_MEM, "");
                        return;
                }
                cat(p, maildir, my_name);
                if (((mailfile = getenv("MAIL")) == NULL) ||
                    (strlen(mailfile) == 0)) {
                        /* $MAIL not set, use standard path to mailfile */
                        mailfile = p;
                } else {
                        if (strcmp(mailfile, p) != 0) {
                            flgf = 1;
                            nsmbox = 1;
                            Dout(pn, 0, "$MAIL ('%s') != standard path\n",
                                mailfile);
                            Dout("", 0, "\tSetting flgf to 1.\n");
                        }
                        free(p);
                }
        }

        /*
         *      Get ACCESS and MODIFICATION times of mailfile BEFORE we
         *      use it. This allows us to put them back when we are
         *      done. If we didn't, the shell would think NEW mail had
         *      arrived since the file times would have changed.
         */
        stret = CERROR;
        if (access(mailfile, A_EXIST) == A_OK) {
                if ((stret = stat(mailfile, stbufp)) != A_OK) {
                        errmsg(E_FILE, "Cannot stat mailfile");
                        return;
                }
                mf_gid = stbufp->st_gid;
                mf_uid = stbufp->st_uid;
                utimep->actime = stbufp->st_atime;
                utimep->modtime = stbufp->st_mtime;
                file_size = stbufp->st_size;
        }

        /* Open the file as the real gid */
        savedegid = getegid();
        (void) setegid(getgid());
        malf = fopen(mailfile, "r");
        (void) setegid(savedegid);
        /*
         *      stat succeeded, but we cannot access the mailfile
         */
        if (stret == CSUCCESS && malf == NULL) {
                char buf[MAXFILENAME+50];
                (void) snprintf(buf, sizeof (buf),
                    "Invalid permissions on %s", mailfile);
                errmsg(E_PERM, buf);
                return;
        } else
        /*
         *      using an alternate mailfile, but we failed on access
         */
        if (!nsmbox && flgf && (malf == NULL)) {
                errmsg(E_FILE, "Cannot open mailfile");
                return;
        }
        /*
         *      we failed to access OR the file is empty
         */
        else if ((malf == NULL) || (stbuf.st_size == 0)) {
                if (!flge && !flgE) {
                        printf("No mail.\n");
                }
                error = E_FLGE;
                Dout(pn, 0, "error set to %d\n", error);
                return;
        }
        if (flge)
                return;

        if (flgE) {
                if (utimep->modtime < utimep->actime) {
                        error = E_FLGE_OM;
                        Dout(pn, 0, "error set to %d\n", error);
                }
                return;
        }
        /*
         *      Secure the mailfile to guarantee integrity
         */
        lock(my_name);

        /*
         *      copy mail to temp file and mark each letter in the
         *      let array --- mailfile is still locked !!!
         */
        mktmp();
        copymt(malf, tmpf);
        onlet = nlet;
        fclose(malf);
        fclose(tmpf);
        unlock();       /* All done, OK to unlock now */
        tmpf = doopen(lettmp, "r+", E_TMP);
        changed = 0;
        print = 1;
        curlet = 0;
        while (curlet < nlet) {
                /*
                 *      reverse order ?
                 */
                showlet = flgr ? curlet : nlet - curlet - 1;

                if (setjmp(sjbuf) == 0 && print != 0) {
                                /* -h says to print the headers first */
                                if (flgh) {
                                        gethead(showlet, 0);
                                        flgh = 0;       /* Only once */
                                        /* set letter # to invalid # */
                                        curlet--;
                                        showlet =
                                            flgr ? curlet : nlet - curlet - 1;
                                } else {
                                        if (showlet != sav_j) {
                                                /* Looking at new message. */
                                                /* Reset flag to override */
                                                /* non-display of binary */
                                                /* contents */
                                                sav_j = showlet;
                                                pflg = 0;
                                                Pflg = flgP;
                                        }
                                        copylet(showlet, stdout, ttyf);
                                }
                }

                /*
                 *      print only
                 */
                if (flgp) {
                        curlet++;
                        continue;
                }
                /*
                 *      Interactive
                 */
                interactive = 1;
                setjmp(sjbuf);
                stat(mailfile, stbufp);
                if (stbufp->st_size != file_size) {
                        /*
                         *      New mail has arrived, load it
                         */
                        k = nlet;
                        lock(my_name);
                        malf = doopen(mailfile, "r", E_FILE);
                        fclose(tmpf);
                        tmpf = doopen(lettmp, "a", E_TMP);
                        fseek(malf, let[nlet].adr, 0);
                        copymt(malf, tmpf);
                        file_size = stbufp->st_size;
                        fclose(malf);
                        fclose(tmpf);
                        unlock();
                        tmpf = doopen(lettmp, "r+", E_TMP);
                        if (++k < nlet)
                                printf("New mail loaded into letters %d - %d\n",
                                    k, nlet);
                        else
                                printf("New mail loaded into letter %d\n",
                                    nlet);
                }

                /* read the command */
                printf("? ");
                fflush(stdout);
                fflush(stderr);
                if (fgets(readbuf, sizeof (readbuf), stdin) == NULL) break;
                resp = readbuf;
                while (*resp == ' ' || *resp == '\t') resp++;
                print = 1;
                Dout(pn, 0, "resp = '%s'\n", resp);
                if ((rc = atoi(resp)) != 0) {
                        if (!validmsg(rc)) print = 0;
                        else curlet = flgr ? rc - 1 : nlet - rc;
                } else switch (resp[0]) {
                        default:
                                printf("Usage:\n");
                        /*
                         *      help
                         */
                        case '?':
                                print = 0;
                                for (rc = 0; help[rc]; rc++)
                                        printf("%s", help[rc]);
                                break;
                        /*
                         *      print message number of current message
                         */
                        case '#':
                                print = 0;
                                if ((showlet == nlet) || (showlet < 0)) {
                                        printf("No message selected yet.\n");
                                } else {
                                        printf("Current message number is %d\n",
                                            showlet+1);
                                }
                                break;
                        /*
                         *      headers
                         */
                        case 'h':
                                print = 0;
                                if (resp[2] != 'd' &&
                                    resp[2] != 'a' &&
                                    (rc = getnumbr(resp+1)) > 0) {
                                        showlet = rc - 1;
                                        curlet = flgr ? rc - 1 : nlet - rc- 1;
                                }
                                if (rc == -1 && resp[2] != 'a' &&
                                    resp[2] != 'd')
                                        break;
                                if (resp[2] == 'a') rc = 1;
                                else if (resp[2] == 'd') rc = 2;
                                        else rc = 0;

/*
 *                              if (!validmsg(showlet)) break;
 */
                                gethead(showlet, rc);
                                break;
                        /*
                         *      skip entry
                         */
                        case '+':
                        case 'n':
                        case '\n':
                                curlet++;
                                break;
                        case 'P':
                                Pflg++;
                                break;
                        case 'p':
                                pflg++;
                                break;
                        case 'x':
                                changed = 0;
                        case 'q':
                                goto donep;
                        /*
                         *      Previous entry
                         */
                        case '^':
                        case '-':
                                if (--curlet < 0) curlet = 0;
                                break;
                        /*
                         *      Save in file without header
                         */
                        case 'y':
                        case 'w':
                        /*
                         *      Save mail with header
                         */
                        case 's':
                                print = 0;
                                if (!validmsg(curlet)) break;
                                if (resp[1] == '\n' || resp[1] == '\0') {
                                        cat(resp+1, hmbox, "");
                                } else if (resp[1] != ' ') {
                                        printf("Invalid command\n");
                                        break;
                                }
                                umask(umsave);
                                flg = 0;
                                if (getarg(lfil, resp + 1) == NULL) {
                                        cat(resp + 1, hmbox, "");
                                }
                                malf = (FILE *)NULL;
                                p = resp + 1;
                                while ((p = getarg(lfil, p)) != NULL) {
                                        if (flg) {
                                            fprintf(stderr,
                                                "%s: File '%s' skipped\n",
                                                program, lfil);
                                            continue;
                                        }
                                        malf = NULL;
                                        if ((aret = legal(lfil))) {
                                                malf = fopen(lfil, "a");
                                        }
                                        if ((malf == NULL) || (aret == 0)) {
                                            fprintf(stderr,
                                                "%s: Cannot append to %s\n",
                                                program, lfil);
                                            flg++;
                                        } else if (aret == 2) {
                                                chown(lfil, my_euid, my_gid);
                                        }
                                        if (!flg &&
                                            copylet(showlet, malf, resp[0] ==
                                            's'? ORDINARY: ZAP) == FALSE) {
                                                fprintf(stderr,
                                            "%s: Cannot save mail to '%s'\n",
                                                    program, lfil);
                                                flg++;
                                        } else
                                                Dout(pn, 0, "!saved\n");
                                        if (malf != (FILE *)NULL) {
                                                fclose(malf);
                                        }
                                }
                                umask(7);
                                if (!flg) {
                                        setletr(showlet, resp[0]);
                                        print = 1;
                                        curlet++;
                                }
                                break;
                        /*
                         *      Reply to a letter
                         */
                        case 'r':
                                print = 0;
                                if (!validmsg(curlet)) break;
                                replying = 1;
                                for (k = 1; resp[k] == ' ' || resp[k] == '\t';
                                    ++k);
                                resp[strlen(resp)-1] = '\0';
                                (void) strlcpy(m_sendto, resp+k,
                                    sizeof (m_sendto));
                                goback(showlet);
                                replying = 0;
                                setletr(showlet, resp[0]);
                                break;
                        /*
                         *      Undelete
                         */
                        case 'u':
                                print = 0;
                                if ((k = getnumbr(resp+1)) <= 0) k = showlet;
                                else k--;
                                if (!validmsg(k)) break;
                                setletr(k, ' ');
                                break;
                        /*
                         *      Mail letter to someone else
                         */
                        case 'm':
                                {
                                reciplist list;
                                print = 0;
                                if (!validmsg(curlet)) break;
                                new_reciplist(&list);
                                flg = 0;
                                k = 0;
                                if (substr(resp, " -") != -1 ||
                                        substr(resp, "\t-") != -1) {
                                        printf("Only users may be specified\n");
                                        break;
                                }
                                p = resp + 1;
                                while ((p = getarg(lfil, p)) != NULL) {
                                        char *env;
                                        if (lfil[0] == '$') {
                                                if (!(env = getenv(&lfil[1]))) {
                                                        fprintf(stderr,
                                "%s: %s has no value or is not exported.\n",
                                                            program, lfil);
                                                        flg++;
                                                } else
                                                        add_recip(&list, env,
                                                            FALSE);
                                                k++;
                                        } else if (lfil[0] != '\0') {
                                                add_recip(&list, lfil, FALSE);
                                                k++;
                                        }
                                }
                                (void) strlcpy(Rpath, my_name, sizeof (Rpath));
                                sending = TRUE;
                                flg += sendlist(&list, showlet, 0);
                                sending = FALSE;
                                if (k) {
                                        if (!flg) {
                                                setletr(showlet, 'm');
                                                print = 1;
                                                curlet++;
                                        }
                                } else
                                        printf("Invalid command\n");
                                del_reciplist(&list);
                                break;
                                }
                        /*
                         *      Read new letters
                         */
                        case 'a':
                                if (onlet == nlet) {
                                        printf("No new mail\n");
                                        print = 0;
                                        break;
                                }
                                curlet = 0;
                                print = 1;
                                break;
                        /*
                         *      Escape to shell
                         */
                        case '!':
                                systm(resp + 1);
                                printf("!\n");
                                print = 0;
                                break;
                        /*
                         *      Delete an entry
                         */
                        case 'd':
                                print = 0;
                                k = 0;
                                if (strncmp("dq", resp, 2) != SAME &&
                                        strncmp("dp", resp, 2) != SAME)
                                        if ((k = getnumbr(resp+1)) == -1) break;
                                if (k == 0) {
                                        k = showlet;
                                        if (!validmsg(curlet)) break;
                                        print = 1;
                                        curlet++;
                                } else  k--;

                                setletr(k, 'd');
                                if (resp[1] == 'p') print = 1;
                                else if (resp[1] == 'q') goto donep;
                                break;
                }
        }
        /*
         *      Copy updated mailfile back
         */
donep:
        if (changed) {
                copyback();
                stamp();
        }
}