/*
** dropsbr.c -- append to mbox files
**
** This code is Copyright (c) 2002, by the authors of nmh.  See the
** COPYRIGHT file in the root directory of the nmh distribution for
** complete copyright information.
*/

#include <h/mh.h>
#include <h/utils.h>
#include <h/dropsbr.h>
#include <h/tws.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>


/*
** Main entry point to open/create and lock
** a file or maildrop.
*/
int
mbox_open(char *file, uid_t uid, gid_t gid, mode_t mode)
{
	int i, count, fd;
	struct stat st;

	i = 0;

	/* attempt to open and lock file */
	for (count = 4; count > 0; count--) {
		if ((fd = lkopen(file, O_RDWR | O_CREAT | O_NONBLOCK, mode))
				== NOTOK) {
			switch (errno) {
#if defined(FCNTL_LOCKING) || defined(LOCKF_LOCKING)
			case EACCES:
			case EAGAIN:
#endif

#ifdef FLOCK_LOCKING
			case EWOULDBLOCK:
#endif
			case ETXTBSY:
				i = errno;
				sleep(1);
				continue;

			default:
				/* just return error */
				return NOTOK;
			}
		}

		/* good file descriptor */
		break;
	}

	errno = i;

	/*
	** Return if we still failed after 4 attempts,
	** or we just want to skip the sanity checks.
	*/
	if (fd == NOTOK)
		return fd;

	/* Do sanity checks on maildrop. */
	if (fstat(fd, &st) == NOTOK) {
		/*
		** The stat failed.  So we make sure file
		** has right ownership/modes
		*/
		chown(file, uid, gid);
		chmod(file, mode);
	} else if (st.st_size > (off_t) 0) {
		int status;

		/* Check/prepare MBOX style maildrop for appending. */
		if (lseek(fd, (off_t) 0, SEEK_END) == (off_t) NOTOK) {
			status = NOTOK;
		} else {
			status = OK;
		}

		/* if error, attempt to close it */
		if (status == NOTOK) {
			close(fd);
			return NOTOK;
		}
	}

	return fd;
}


/*
** Append message to end of mbox.
*/
int
mbox_copy(int to, int from)
{
	int i;
	char buffer[BUFSIZ];
	FILE *fp;

	if ((i = dup(from)) == NOTOK)
		return NOTOK;
	if ((fp = fdopen(i, "r")) == NULL) {
		close(i);
		return NOTOK;
	}

	for (i = 0; fgets(buffer, sizeof(buffer), fp) != NULL; i++) {
		/*
		** Check the first line, and make some changes.
		*/
		if (i == 0) {
			/*
			** Change the "Return-Path:" field
			** (if in first line) back to "From ".
			*/
			if (strncmp(buffer, "Return-Path:", 12)==0) {
				char tmpbuffer[BUFSIZ];
				char *tp, *ep, *fp;

				strncpy(tmpbuffer, buffer, sizeof(tmpbuffer));
				ep = tmpbuffer + 13;
				if (!(fp = strchr(ep + 1, ' ')))
					fp = strchr(ep + 1, '\n');
				tp = dctime(dlocaltimenow());
					snprintf(buffer, sizeof(buffer),
							"From %.*s %s",
							(int)(fp-ep), ep, tp);
			} else if (strncmp(buffer, "X-Envelope-From:",
					16)==0) {
				/*
				** Change the "X-Envelope-From:" field
				** (if first line) back to "From ".
				*/
				char tmpbuffer[BUFSIZ];
				char *ep;

				strncpy(tmpbuffer, buffer, sizeof(tmpbuffer));
				ep = tmpbuffer + 17;
				snprintf(buffer, sizeof(buffer), "From %s",
						ep);
			} else if (strncmp(buffer, "From ", 5)!=0) {
				/*
				** If there is already a "From " line,
				** then leave it alone.  Else we add one.
				*/
				char tmpbuffer[BUFSIZ];
				char *tp, *ep;

				strncpy(tmpbuffer, buffer, sizeof(tmpbuffer));
				ep = "nobody@nowhere";
				tp = dctime(dlocaltimenow());
				snprintf(buffer, sizeof(buffer),
						"From %s %s%s", ep, tp,
						tmpbuffer);
			}
		}

		/*
		** If this is not first line, and begins with "From ",
		** then prepend line with ">". (`mboxo' format is used.)
		*/
		if (i != 0 && strncmp(buffer, "From ", 5) == 0) {
			write(to, ">", 1);
		}
		if (write(to, buffer, strlen(buffer)) != (int)strlen(buffer)) {
			fclose(fp);
			return NOTOK;
		}
	}

	if (write(to, "\n", 1) != 1) {
		fclose(fp);
		return NOTOK;
	}
	fclose(fp);
	lseek(from, (off_t) 0, SEEK_END);

	return OK;
}


/*
** Close and unlock file/maildrop.
*/
int
mbox_close(char *mailbox, int md)
{
	if (lkclose(md, mailbox) == 0)
		return OK;
	return NOTOK;
}
