/* * 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 * --- * 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, */ #include "config.h" #ifdef HAVE_NL_LANGINFO #include #endif /* HAVE_NL_LANGINFO */ #define _MAIL_GLOBS_ #include "rcv.h" #include "extern.h" #include #include #include #include #include #ifdef HAVE_SETLOCALE #include #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; }