/*
* 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.50 (gritter) 6/16/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:BHFINVT: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 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 '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 -eiIUdFntBDNHRV~ -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);
}
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);
/*
* 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;
}
syntax highlighted by Code2HTML, v. 0.9.1