Logo Search packages:      
Sourcecode: heirloom-mailx version File versions  Download package

main.c

/*
 * Heirloom mailx - a mail user agent derived from Berkeley Mail.
 *
 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
 */
/*
 * Copyright (c) 1980, 1993
 *    The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by the University of
 *    California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef lint
#ifdef      DOSCCS
static char copyright[]
= "@(#) Copyright (c) 1980, 1993 The Regents of the University of California.  All rights reserved.\n";
static char sccsid[] = "@(#)main.c  2.51 (gritter) 10/1/07";
#endif      /* DOSCCS */
#endif /* not lint */

/*
 * Most strcpy/sprintf functions have been changed to strncpy/snprintf to
 * correct several buffer overruns (at least one ot them was exploitable).
 * Sat Jun 20 04:58:09 CEST 1998 Alvaro Martinez Echevarria <alvaro@lander.es>
 * ---
 * Note: We set egid to realgid ... and only if we need the egid we will
 *       switch back temporary.  Nevertheless, I do not like seg faults.
 *       Werner Fink, <werner@suse.de>
 */


#include "config.h"
#ifdef      HAVE_NL_LANGINFO
#include <langinfo.h>
#endif      /* HAVE_NL_LANGINFO */
#define _MAIL_GLOBS_
#include "rcv.h"
#include "extern.h"
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef      HAVE_SETLOCALE
#include <locale.h>
#endif      /* HAVE_SETLOCALE */

/*
 * Mail -- a mail program
 *
 * Startup -- interface with user.
 */

static sigjmp_buf hdrjmp;
char  *progname;
sighandler_type   dflpipe = SIG_DFL;

static void hdrstop(int signo);
static void setscreensize(int dummy);

int 
main(int argc, char *argv[])
{
      const char optstr[] = "A:BHEFINVT:RS:a:b:c:dDefh:inqr:s:tu:v~";
      int i, existonly = 0, headersonly = 0, sendflag = 0;
      struct name *to, *cc, *bcc, *smopts;
      struct attachment *attach;
      char *subject, *cp, *ef, *qf = NULL, *fromaddr = NULL, *Aflag = NULL;
      char nosrc = 0;
      int Eflag = 0, Fflag = 0, Nflag = 0, tflag = 0;
      sighandler_type prevint;

      (void)&Nflag;
      /*
       * Absolutely the first thing we do is save our egid
       * and set it to the rgid, so that we can safely run
       * setgid.  We use the sgid (saved set-gid) to allow ourselves
       * to revert to the egid if we want (temporarily) to become
       * priveliged.
       */
      effectivegid = getegid();
      realgid = getgid();
      if (setgid(realgid) < 0) {
            perror("setgid");
            exit(1);
      }

      starting = 1;
      progname = strrchr(argv[0], '/');
      if (progname != NULL)
            progname++;
      else
            progname = argv[0];
      /*
       * Set up a reasonable environment.
       * Figure out whether we are being run interactively,
       * start the SIGCHLD catcher, and so forth.
       */
      safe_signal(SIGCHLD, sigchild);
      is_a_tty[0] = isatty(0);
      is_a_tty[1] = isatty(1);
      if (is_a_tty[0]) {
            assign("interactive", "");
            if (is_a_tty[1])
                  safe_signal(SIGPIPE, dflpipe = SIG_IGN);
      }
      assign("header", "");
      assign("save", "");
#ifdef      HAVE_SETLOCALE
      setlocale(LC_CTYPE, "");
      setlocale(LC_COLLATE, "");
      setlocale(LC_MESSAGES, "");
      mb_cur_max = MB_CUR_MAX;
#if defined (HAVE_NL_LANGINFO) && defined (CODESET)
      if (value("ttycharset") == NULL && (cp = nl_langinfo(CODESET)) != NULL)
            assign("ttycharset", cp);
#endif      /* HAVE_NL_LANGINFO && CODESET */
#if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
      if (mb_cur_max > 1) {
            wchar_t     wc;
            if (mbtowc(&wc, "\303\266", 2) == 2 && wc == 0xF6 &&
                        mbtowc(&wc, "\342\202\254", 3) == 3 &&
                        wc == 0x20AC)
                  utf8 = 1;
      }
#endif      /* HAVE_MBTOWC && HAVE_WCTYPE_H */
#else /* !HAVE_SETLOCALE */
      mb_cur_max = 1;
#endif      /* !HAVE_SETLOCALE */
#ifdef      HAVE_CATGETS
#ifdef      NL_CAT_LOCALE
      i = NL_CAT_LOCALE;
#else
      i = 0;
#endif
      catd = catopen(CATNAME, i);
#endif      /* HAVE_CATGETS */
#ifdef      HAVE_ICONV
      iconvd = (iconv_t) -1;
#endif
      image = -1;
      /*
       * Now, determine how we are being used.
       * We successively pick off - flags.
       * If there is anything left, it is the base of the list
       * of users to mail to.  Argp will be set to point to the
       * first of these users.
       */
      ef = NULL;
      to = NULL;
      cc = NULL;
      bcc = NULL;
      attach = NULL;
      smopts = NULL;
      subject = NULL;
      while ((i = getopt(argc, argv, optstr)) != EOF) {
            switch (i) {
            case 'V':
                  puts(version);
                  exit(0);
                  /*NOTREACHED*/
            case 'B':
                  setvbuf(stdin, NULL, _IOLBF, 0);
                  setvbuf(stdout, NULL, _IOLBF, 0);
                  break;
            case 'H':
                  headersonly = 1;
                  break;
            case 'E':
                  Eflag = 1;
                  break;
            case 'F':
                  Fflag = 1;
                  sendflag++;
                  break;
            case 'S': {
                        char *args[] = { NULL, NULL };
                        args[0] = optarg;
                        set(args);
                  }
                  break;
            case 'T':
                  /*
                   * Next argument is temp file to write which
                   * articles have been read/deleted for netnews.
                   */
                  Tflag = optarg;
                  if ((i = creat(Tflag, 0600)) < 0) {
                        perror(Tflag);
                        exit(1);
                  }
                  close(i);
                  /*FALLTHRU*/
            case 'I':
                  /*
                   * Show Newsgroups: field in header summary
                   */
                  Iflag = 1;
                  break;
            case 'u':
                  /*
                   * Next argument is person to pretend to be.
                   */
                  uflag = myname = optarg;
                  break;
            case 'i':
                  /*
                   * User wants to ignore interrupts.
                   * Set the variable "ignore"
                   */
                  assign("ignore", "");
                  break;
            case 'd':
                  debug++;
                  break;
            case 'D':
                  assign("disconnected", "");
                  break;
            case 'e':
                  existonly++;
                  break;
            case 's':
                  /*
                   * Give a subject field for sending from
                   * non terminal
                   */
                  subject = optarg;
                  sendflag++;
                  break;
            case 'f':
                  /*
                   * User is specifying file to "edit" with Mail,
                   * as opposed to reading system mailbox.
                   * If no argument is given, we read his
                   * mbox file.
                   *
                   * Check for remaining arguments later.
                   */
                  ef = "&";
                  break;
            case 'q':
                  /*
                   * User is specifying file to quote in front of
                   * the mail to be collected.
                   */
                  if ((argv[optind]) && (argv[optind][0] != '-'))
                        qf = argv[optind++];
                  else
                        qf = NULL;
                  sendflag++;
                  break;
            case 'n':
                  /*
                   * User doesn't want to source /usr/lib/Mail.rc
                   */
                  nosrc++;
                  break;
            case 'N':
                  /*
                   * Avoid initial header printing.
                   */
                  Nflag = 1;
                  unset_internal("header");
                  break;
            case 'v':
                  /*
                   * Send mailer verbose flag
                   */
                  assign("verbose", "");
                  break;
            case 'r':
                  /*
                   * Set From address.
                   */
                  fromaddr = optarg;
                  smopts = cat(smopts, nalloc("-r", 0));
                  smopts = cat(smopts, nalloc(optarg, 0));
                  tildeflag = -1;
                  sendflag++;
                  break;
            case 'a':
                  /*
                   * Get attachment filenames
                   */
                  if ((attach = add_attachment(attach, optarg)) == NULL) {
                        perror(optarg);
                        exit(1);
                  }
                  sendflag++;
                  break;
            case 'c':
                  /*
                   * Get Carbon Copy Recipient list
                   */
                  cc = checkaddrs(cat(cc, extract(optarg, GCC|GFULL)));
                  sendflag++;
                  break;
            case 'b':
                  /*
                   * Get Blind Carbon Copy Recipient list
                   */
                  bcc = checkaddrs(cat(bcc, extract(optarg, GBCC|GFULL)));
                  sendflag++;
                  break;
            case 'h':
                  /*
                   * Hop count for sendmail
                   */
                  smopts = cat(smopts, nalloc("-h", 0));
                  smopts = cat(smopts, nalloc(optarg, 0));
                  sendflag++;
                  break;
            case '~':
                  if (tildeflag == 0)
                        tildeflag = 1;
                  break;
            case 't':
                  sendflag = 1;
                  tflag = 1;
                  break;
            case 'A':
                  Aflag = optarg;
                  break;
            case 'R':
                  Rflag = 1;
                  break;
            case '?':
usage:
                  fprintf(stderr, catgets(catd, CATSET, 135,
"Usage: %s -eiIUdEFntBDNHRV~ -T FILE -u USER -h hops -r address -s SUBJECT -a FILE -q FILE -f FILE -A ACCOUNT -b USERS -c USERS -S OPTION users\n"), progname);
                  exit(2);
            }
      }
      if (ef != NULL) {
            if (optind < argc) {
                  if (optind + 1 < argc) {
                        fprintf(stderr, catgets(catd, CATSET, 205,
                              "More than one file given with -f\n"));
                        goto usage;
                  }
                  ef = argv[optind];
            }
      } else {
            for (i = optind; argv[i]; i++)
                  to = checkaddrs(cat(to, extract(argv[i], GTO|GFULL)));
      }
      /*
       * Check for inconsistent arguments.
       */
      if (ef != NULL && to != NULL) {
            fprintf(stderr, catgets(catd, CATSET, 137,
                  "Cannot give -f and people to send to.\n"));
            goto usage;
      }
      if (sendflag && !tflag && to == NULL) {
            fprintf(stderr, catgets(catd, CATSET, 138,
                  "Send options without primary recipient specified.\n"));
            goto usage;
      }
      if (Rflag && to != NULL) {
            fprintf(stderr, "The -R option is meaningless in send mode.\n");
            goto usage;
      }
      if (Iflag && ef == NULL) {
            fprintf(stderr, catgets(catd, CATSET, 204,
                              "Need -f with -I.\n"));
            goto usage;
      }
      tinit();
      setscreensize(0);
#ifdef      SIGWINCH
      if (value("interactive"))
            if (safe_signal(SIGWINCH, SIG_IGN) != SIG_IGN)
                  safe_signal(SIGWINCH, setscreensize);
#endif      /* SIGWINCH */
      input = stdin;
      rcvmode = !to && !tflag;
      spreserve();
      if (!nosrc)
            load(MAILRC);
      /*
       * Expand returns a savestr, but load only uses the file name
       * for fopen, so it's safe to do this.
       */
      if ((cp = getenv("MAILRC")) != NULL)
            load(expand(cp));
      else if ((cp = getenv("NAILRC")) != NULL)
            load(expand(cp));
      else
            load(expand("~/.mailrc"));
      if (getenv("NAIL_EXTRA_RC") == NULL &&
                  (cp = value("NAIL_EXTRA_RC")) != NULL)
            load(expand(cp));
      /*
       * Now we can set the account.
       */
      if (Aflag) {
            char  *a[2];
            a[0] = Aflag;
            a[1] = NULL;
            account(a);
      }

      /*
       * Override 'skipemptybody' if '-E' flag was given.
       */
      if (Eflag)
            assign("skipemptybody", "");

      starting = 0;

      /*
       * From address from command line overrides rc files.
       */
      if (fromaddr)
            assign("from", fromaddr);
      if (!rcvmode) {
            mail(to, cc, bcc, smopts, subject, attach, qf, Fflag, tflag,
                Eflag);
            /*
             * why wait?
             */
            exit(senderr ? 1 : 0);
      }
      /*
       * Ok, we are reading mail.
       * Decide whether we are editing a mailbox or reading
       * the system mailbox, and open up the right stuff.
       */
      if (ef == NULL)
            ef = "%";
      else if (*ef == '@') {
            /*
             * This must be treated specially to make invocation like
             * -A imap -f @mailbox work.
             */
            if ((cp = value("folder")) != NULL &&
                        which_protocol(cp) == PROTO_IMAP)
                  strncpy(mailname, cp, PATHSIZE)[PATHSIZE-1] = '\0';
      }
      i = setfile(ef, 0);
      if (i < 0)
            exit(1);          /* error already reported */
      if (existonly)
            exit(i);
      if (headersonly) {
            if (mb.mb_type == MB_IMAP)
                  imap_getheaders(1, msgCount);
            for (i = 1; i <= msgCount; i++)
                  printhead(i, stdout, 0);
            exit(exit_status);
      }
      callhook(mailname, 0);
      if (i > 0 && value("emptystart") == NULL)
            exit(1);
      if (sigsetjmp(hdrjmp, 1) == 0) {
            if ((prevint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
                  safe_signal(SIGINT, hdrstop);
            if (Nflag == 0) {
                  if (value("quiet") == NULL)
                        printf(catgets(catd, CATSET, 140,
                              "Heirloom %s version %s.  "
                              "Type ? for help.\n"),
                              value("bsdcompat") ? "Mail" : "mailx",
                              version);
                  announce(1);
                  fflush(stdout);
            }
            safe_signal(SIGINT, prevint);
      }
      commands();
      if (mb.mb_type == MB_FILE || mb.mb_type == MB_MAILDIR) {
            safe_signal(SIGHUP, SIG_IGN);
            safe_signal(SIGINT, SIG_IGN);
            safe_signal(SIGQUIT, SIG_IGN);
      }
      strncpy(mboxname, expand("&"), sizeof mboxname)[sizeof mboxname-1]='\0';
      quit();
      return exit_status;
}

/*
 * Interrupt printing of the headers.
 */
/*ARGSUSED*/
static void 
hdrstop(int signo)
{

      fflush(stdout);
      fprintf(stderr, catgets(catd, CATSET, 141, "\nInterrupt\n"));
      siglongjmp(hdrjmp, 1);
}

/*
 * Compute what the screen size for printing headers should be.
 * We use the following algorithm for the height:
 *    If baud rate < 1200, use  9
 *    If baud rate = 1200, use 14
 *    If baud rate > 1200, use 24 or ws_row
 * Width is either 80 or ws_col;
 */
/*ARGSUSED*/
static void 
setscreensize(int dummy)
{
      struct termios tbuf;
#ifdef      TIOCGWINSZ
      struct winsize ws;
#endif
      speed_t ospeed;

#ifdef      TIOCGWINSZ
      if (ioctl(1, TIOCGWINSZ, &ws) < 0)
            ws.ws_col = ws.ws_row = 0;
#endif
      if (tcgetattr(1, &tbuf) < 0)
            ospeed = B9600;
      else
            ospeed = cfgetospeed(&tbuf);
      if (ospeed < B1200)
            scrnheight = 9;
      else if (ospeed == B1200)
            scrnheight = 14;
#ifdef      TIOCGWINSZ
      else if (ws.ws_row != 0)
            scrnheight = ws.ws_row;
#endif
      else
            scrnheight = 24;
#ifdef      TIOCGWINSZ
      if ((realscreenheight = ws.ws_row) == 0)
            realscreenheight = 24;
#endif
#ifdef      TIOCGWINSZ
      if ((scrnwidth = ws.ws_col) == 0)
#endif
            scrnwidth = 80;
}

Generated by  Doxygen 1.6.0   Back to index