Exemple #1
0
/*
 * User aborted during message composition.
 * Save the partial message in ~/dead.letter.
 */
int
collabort(void)
{
	/*
	 * the control flow is subtle, because we can be called from ~q.
	 */
	if (hadintr == 0 && isatty(0)) {
		if (value("ignore") != NULL) {
			puts("@");
			fflush(stdout);
			clearerr(stdin);
		} else {
			fflush(stdout);
			fputs("\n(Interrupt -- one more to kill letter)\n",
			    stderr);
			hadintr++;
		}
		return(0);
	}
	fflush(stdout);
	rewind(collf);
	if (value("nosave") == NULL)
		savedeadletter(collf);
	return(1);
}
Exemple #2
0
/*ARGSUSED*/
void
collhup(int s __unused)
{
	rewind(collf);
	savedeadletter(collf);
	/*
	 * Let's pretend nobody else wants to clean up,
	 * a true statement at this time.
	 */
	exit(1);
}
Exemple #3
0
/*ARGSUSED*/
void
collint(int s __unused)
{
	/*
	 * the control flow is subtle, because we can be called from ~q.
	 */
	if (!hadintr) {
		if (value("ignore") != NULL) {
			printf("@");
			(void)fflush(stdout);
			clearerr(stdin);
			return;
		}
		hadintr = 1;
		longjmp(colljmp, 1);
	}
	rewind(collf);
	if (value("nosave") == NULL)
		savedeadletter(collf);
	longjmp(collabort, 1);
}
Exemple #4
0
/*ARGSUSED*/
static void 
collint(int s)
{
	/*
	 * the control flow is subtle, because we can be called from ~q.
	 */
	if (!hadintr) {
		if (value("ignore") != NULL) {
			puts("@");
			fflush(stdout);
			clearerr(stdin);
			return;
		}
		hadintr = 1;
		siglongjmp(colljmp, 1);
	}
	exit_status |= 04;
	rewind(collf);
	if (value("save") != NULL && s != 0)
		savedeadletter(collf);
	siglongjmp(collabort, 1);
}
Exemple #5
0
FILE *
collect(struct header *hp, int printheaders)
{
	FILE *fbuf;
	int lc, cc, fd, c, t, lastlong, rc, sig;
	int escape, eofcount, longline;
	char getsub;
	char linebuf[LINESIZE], tempname[PATHSIZE], *cp;

	collf = NULL;
	eofcount = 0;
	hadintr = 0;
	lastlong = 0;
	longline = 0;
	if ((cp = value("escape")) != NULL)
		escape = *cp;
	else
		escape = ESCAPE;
	noreset++;

	(void)snprintf(tempname, sizeof(tempname),
	    "%s/mail.RsXXXXXXXXXX", tmpdir);
	if ((fd = mkstemp(tempname)) == -1 ||
	    (collf = Fdopen(fd, "w+")) == NULL) {
		warn("%s", tempname);
		goto err;
	}
	(void)rm(tempname);

	/*
	 * If we are going to prompt for a subject,
	 * refrain from printing a newline after
	 * the headers (since some people mind).
	 */
	t = GTO|GSUBJECT|GCC|GNL;
	getsub = 0;
	if (hp->h_subject == NULL && value("interactive") != NULL &&
	    (value("ask") != NULL || value("asksub") != NULL))
		t &= ~GNL, getsub++;
	if (printheaders) {
		puthead(hp, stdout, t);
		fflush(stdout);
	}
	if (getsub && gethfromtty(hp, GSUBJECT) == -1)
		goto err;

	if (0) {
cont:
		/* Come here for printing the after-suspend message. */
		if (isatty(0)) {
			puts("(continue)");
			fflush(stdout);
		}
	}
	for (;;) {
		c = readline(stdin, linebuf, LINESIZE, &sig);

		/* Act on any signal caught during readline() ignoring 'c' */
		switch (sig) {
		case 0:
			break;
		case SIGINT:
			if (collabort())
				goto err;
			continue;
		case SIGHUP:
			rewind(collf);
			savedeadletter(collf);
			/*
			 * Let's pretend nobody else wants to clean up,
			 * a true statement at this time.
			 */
			exit(1);
		default:
			/* Stopped due to job control */
			(void)kill(0, sig);
			goto cont;
		}

		/* No signal, check for error */
		if (c < 0) {
			if (value("interactive") != NULL &&
			    value("ignoreeof") != NULL && ++eofcount < 25) {
				puts("Use \".\" to terminate letter");
				continue;
			}
			break;
		}
		lastlong = longline;
		longline = (c == LINESIZE - 1);
		eofcount = 0;
		hadintr = 0;
		if (linebuf[0] == '.' && linebuf[1] == '\0' &&
		    value("interactive") != NULL && !lastlong &&
		    (value("dot") != NULL || value("ignoreeof") != NULL))
			break;
		if (linebuf[0] != escape || value("interactive") == NULL ||
		    lastlong) {
			if (putline(collf, linebuf, !longline) < 0)
				goto err;
			continue;
		}
		c = linebuf[1];
		switch (c) {
		default:
			/*
			 * On double escape, just send the single one.
			 * Otherwise, it's an error.
			 */
			if (c == escape) {
				if (putline(collf, &linebuf[1], !longline) < 0)
					goto err;
				else
					break;
			}
			puts("Unknown tilde escape.");
			break;
		case '!':
			/*
			 * Shell escape, send the balance of the
			 * line to sh -c.
			 */
			shell(&linebuf[2]);
			break;
		case ':':
		case '_':
			/*
			 * Escape to command mode, but be nice!
			 */
			execute(&linebuf[2], 1);
			goto cont;
		case '.':
			/*
			 * Simulate end of file on input.
			 */
			goto out;
		case 'q':
			/*
			 * Force a quit of sending mail.
			 * Act like an interrupt happened.
			 */
			hadintr++;
			collabort();
			fputs("Interrupt\n", stderr);
			goto err;
		case 'x':
			/*
			 * Force a quit of sending mail.
			 * Do not save the message.
			 */
			goto err;
		case 'h':
			/*
			 * Grab a bunch of headers.
			 */
			grabh(hp, GTO|GSUBJECT|GCC|GBCC);
			goto cont;
		case 't':
			/*
			 * Add to the To list.
			 */
			hp->h_to = cat(hp->h_to, extract(&linebuf[2], GTO));
			break;
		case 's':
			/*
			 * Set the Subject list.
			 */
			cp = &linebuf[2];
			while (isspace(*cp))
				cp++;
			hp->h_subject = savestr(cp);
			break;
		case 'c':
			/*
			 * Add to the CC list.
			 */
			hp->h_cc = cat(hp->h_cc, extract(&linebuf[2], GCC));
			break;
		case 'b':
			/*
			 * Add stuff to blind carbon copies list.
			 */
			hp->h_bcc = cat(hp->h_bcc, extract(&linebuf[2], GBCC));
			break;
		case 'd':
			linebuf[2] = '\0';
			strlcat(linebuf, getdeadletter(), sizeof(linebuf));
			/* fall into . . . */
		case 'r':
		case '<':
			/*
			 * Invoke a file:
			 * Search for the file name,
			 * then open it and copy the contents to collf.
			 */
			cp = &linebuf[2];
			while (isspace(*cp))
				cp++;
			if (*cp == '\0') {
				puts("Interpolate what file?");
				break;
			}
			cp = expand(cp);
			if (cp == NULL)
				break;
			if (isdir(cp)) {
				printf("%s: Directory\n", cp);
				break;
			}
			if ((fbuf = Fopen(cp, "r")) == NULL) {
				warn("%s", cp);
				break;
			}
			printf("\"%s\" ", cp);
			fflush(stdout);
			lc = 0;
			cc = 0;
			while ((rc = readline(fbuf, linebuf, LINESIZE, NULL)) >= 0) {
				if (rc != LINESIZE - 1)
					lc++;
				if ((t = putline(collf, linebuf,
						 rc != LINESIZE-1)) < 0) {
					(void)Fclose(fbuf);
					goto err;
				}
				cc += t;
			}
			(void)Fclose(fbuf);
			printf("%d/%d\n", lc, cc);
			break;
		case 'w':
			/*
			 * Write the message on a file.
			 */
			cp = &linebuf[2];
			while (*cp == ' ' || *cp == '\t')
				cp++;
			if (*cp == '\0') {
				fputs("Write what file!?\n", stderr);
				break;
			}
			if ((cp = expand(cp)) == NULL)
				break;
			rewind(collf);
			exwrite(cp, collf, 1);
			break;
		case 'm':
		case 'M':
		case 'f':
		case 'F':
			/*
			 * Interpolate the named messages, if we
			 * are in receiving mail mode.  Does the
			 * standard list processing garbage.
			 * If ~f is given, we don't shift over.
			 */
			if (forward(linebuf + 2, collf, tempname, c) < 0)
				goto err;
			goto cont;
		case '?':
			if ((fbuf = Fopen(_PATH_TILDE, "r")) == NULL) {
				warn(_PATH_TILDE);
				break;
			}
			while ((t = getc(fbuf)) != EOF)
				(void)putchar(t);
			(void)Fclose(fbuf);
			break;
		case 'p':
			/*
			 * Print out the current state of the
			 * message without altering anything.
			 */
			rewind(collf);
			puts("-------\nMessage contains:");
			puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL);
			while ((t = getc(collf)) != EOF)
				(void)putchar(t);
			goto cont;
		case '|':
			/*
			 * Pipe message through command.
			 * Collect output as new message.
			 */
			rewind(collf);
			mespipe(collf, &linebuf[2]);
			goto cont;
		case 'v':
		case 'e':
			/*
			 * Edit the current message.
			 * 'e' means to use EDITOR
			 * 'v' means to use VISUAL
			 */
			rewind(collf);
			mesedit(collf, c);
			goto cont;
		}
	}

	if (value("interactive") != NULL) {
		if (value("askcc") != NULL || value("askbcc") != NULL) {
			if (value("askcc") != NULL) {
				if (gethfromtty(hp, GCC) == -1)
					goto err;
			}
			if (value("askbcc") != NULL) {
				if (gethfromtty(hp, GBCC) == -1)
					goto err;
			}
		} else {
			puts("EOT");
			(void)fflush(stdout);
		}
	}
	goto out;
err:
	if (collf != NULL) {
		(void)Fclose(collf);
		collf = NULL;
	}
out:
	if (collf != NULL)
		rewind(collf);
	noreset--;
	return(collf);
}
Exemple #6
0
/*
 * Mail a message on standard input to the people indicated
 * in the passed header.  (Internal interface).
 */
void
mail1(struct header *hp, int printheaders)
{
	char *cp;
	char *nbuf;
	int pid;
	char **namelist;
	struct name *to, *nsto;
	FILE *mtf;

	/*
	 * Collect user's mail from standard input.
	 * Get the result as mtf.
	 */
	if ((mtf = collect(hp, printheaders)) == NULL)
		return;
	if (value("interactive") != NULL) {
		if (value("askcc") != NULL || value("askbcc") != NULL) {
			if (value("askcc") != NULL)
				grabh(hp, GCC);
			if (value("askbcc") != NULL)
				grabh(hp, GBCC);
		} else {
			printf("EOT\n");
			(void)fflush(stdout);
		}
	}
	if (fsize(mtf) == 0) {
		if (value("dontsendempty") != NULL)
			goto out;
		if (hp->h_subject == NULL)
			printf("No message, no subject; hope that's ok\n");
		else
			printf("Null message body; hope that's ok\n");
	}
	/*
	 * Now, take the user names from the combined
	 * to and cc lists and do all the alias
	 * processing.
	 */
	senderr = 0;
	to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc)));
	if (to == NULL) {
		printf("No recipients specified\n");
		senderr++;
	}
	/*
	 * Look through the recipient list for names with /'s
	 * in them which we write to as files directly.
	 */
	to = outof(to, mtf, hp);
	if (senderr)
		savedeadletter(mtf);
	to = elide(to);
	if (count(to) == 0)
		goto out;
	if (value("recordrecip") != NULL) {
		/*
		 * Before fixing the header, save old To:.
		 * We do this because elide above has sorted To: list, and
		 * we would like to save message in a file named by the first
		 * recipient the user has entered, not the one being the first
		 * after sorting happened.
		 */
		if ((nsto = malloc(sizeof(struct name))) == NULL)
			err(1, "Out of memory");
		bcopy(hp->h_to, nsto, sizeof(struct name));
	}
	fixhead(hp, to);
	if ((mtf = infix(hp, mtf)) == NULL) {
		fprintf(stderr, ". . . message lost, sorry.\n");
		return;
	}
	namelist = unpack(cat(hp->h_smopts, to));
	if (debug) {
		char **t;

		printf("Sendmail arguments:");
		for (t = namelist; *t != NULL; t++)
			printf(" \"%s\"", *t);
		printf("\n");
		goto out;
	}
	if (value("recordrecip") != NULL) {
		/*
		 * Extract first recipient username from saved To: and use it
		 * as a filename.
		 */
		if ((nbuf = malloc(strlen(detract(nsto, 0)) + 1)) == NULL)
			err(1, "Out of memory");
		if ((cp = yanklogin(detract(nsto, 0), nbuf)) != NULL)
			(void)savemail(expand(nbuf), mtf);
		free(nbuf);
		free(nsto);
	} else if ((cp = value("record")) != NULL)
		(void)savemail(expand(cp), mtf);
	/*
	 * Fork, set up the temporary mail file as standard
	 * input for "mail", and exec with the user list we generated
	 * far above.
	 */
	pid = fork();
	if (pid == -1) {
		warn("fork");
		savedeadletter(mtf);
		goto out;
	}
	if (pid == 0) {
		sigset_t nset;
		(void)sigemptyset(&nset);
		(void)sigaddset(&nset, SIGHUP);
		(void)sigaddset(&nset, SIGINT);
		(void)sigaddset(&nset, SIGQUIT);
		(void)sigaddset(&nset, SIGTSTP);
		(void)sigaddset(&nset, SIGTTIN);
		(void)sigaddset(&nset, SIGTTOU);
		prepare_child(&nset, fileno(mtf), -1);
		if ((cp = value("sendmail")) != NULL)
			cp = expand(cp);
		else
			cp = _PATH_SENDMAIL;
		execv(cp, namelist);
		warn("%s", cp);
		_exit(1);
	}
	if (value("verbose") != NULL)
		(void)wait_child(pid);
	else
		free_child(pid);
out:
	(void)Fclose(mtf);
}
Exemple #7
0
/*
 * Mail a message on standard input to the people indicated
 * in the passed header.  (Internal interface).
 */
void
mail1(struct header *hp, int printheaders)
{
	char *cp;
	pid_t pid;
	char **namelist;
	struct name *to;
	FILE *mtf;

	/*
	 * Collect user's mail from standard input.
	 * Get the result as mtf.
	 */
	if ((mtf = collect(hp, printheaders)) == NULL)
		return;
	if (fsize(mtf) == 0) {
		if (value("skipempty") != NULL)
			goto out;
		if (hp->h_subject == NULL || *hp->h_subject == '\0')
			puts("No message, no subject; hope that's ok");
		else
			puts("Null message body; hope that's ok");
	}
	/*
	 * Now, take the user names from the combined
	 * to and cc lists and do all the alias
	 * processing.
	 */
	senderr = 0;
	to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc)));
	if (to == NULL) {
		puts("No recipients specified");
		senderr++;
	}
	/*
	 * Look through the recipient list for names with /'s
	 * in them which we write to as files directly.
	 */
	to = outof(to, mtf, hp);
	if (senderr)
		savedeadletter(mtf);
	to = elide(to);
	if (count(to) == 0)
		goto out;
	fixhead(hp, to);
	if ((mtf = infix(hp, mtf)) == NULL) {
		fputs(". . . message lost, sorry.\n", stderr);
		return;
	}
	namelist = unpack(hp->h_smopts, to);
	if (debug) {
		char **t;

		fputs("Sendmail arguments:", stdout);
		for (t = namelist; *t != NULL; t++)
			printf(" \"%s\"", *t);
		putchar('\n');
		goto out;
	}
	if ((cp = value("record")) != NULL)
		(void)savemail(expand(cp), mtf);
	/*
	 * Fork, set up the temporary mail file as standard
	 * input for "mail", and exec with the user list we generated
	 * far above.
	 */
	pid = fork();
	if (pid == -1) {
		warn("fork");
		savedeadletter(mtf);
		goto out;
	}
	if (pid == 0) {
		sigset_t nset;

		sigemptyset(&nset);
		sigaddset(&nset, SIGHUP);
		sigaddset(&nset, SIGINT);
		sigaddset(&nset, SIGQUIT);
		sigaddset(&nset, SIGTSTP);
		sigaddset(&nset, SIGTTIN);
		sigaddset(&nset, SIGTTOU);
		prepare_child(&nset, fileno(mtf), -1);
		if ((cp = value("sendmail")) != NULL)
			cp = expand(cp);
		else
			cp = _PATH_SENDMAIL;
		execv(cp, namelist);
		warn("%s", cp);
		_exit(1);
	}
	if (value("verbose") != NULL)
		(void)wait_child(pid);
	else
		free_child(pid);
out:
	(void)Fclose(mtf);
}