/*
 * The client command for printing documents.  Opens the file
 * and sends it to the printer spooling daemon.  Usage:
 * 	print [-t] filename
 */
#include "apue.h"
#include "print.h"
#include <fcntl.h>
#include <pwd.h>

/*
 * Needed for logging funtions.
 */
int log_to_stderr = 1;

void submit_file(int, int, const char *, size_t, int);

int
main(int argc, char *argv[])
{
	int				fd, sockfd, err, text, c;
	struct stat		sbuf;
	char			*host;
	struct addrinfo	*ailist, *aip;

	err = 0;
	text = 0;
	while ((c = getopt(argc, argv, "t")) != -1) {
		switch (c) {
		case 't':
			text = 1;
			break;

		case '?':
			err = 1;
			break;
		}
	}
	if (err || (optind != argc - 1))
		err_quit("usage: print [-t] filename");
	if ((fd = open(argv[optind], O_RDONLY)) < 0)
		err_sys("print: can't open %s", argv[1]);
	if (fstat(fd, &sbuf) < 0)
		err_sys("print: can't stat %s", argv[1]);
	if (!S_ISREG(sbuf.st_mode))
		err_quit("print: %s must be a regular file\n", argv[1]);

	/*
	 * Get the hostname of the host acting as the print server.
	 */
	if ((host = get_printserver()) == NULL)
		err_quit("print: no print server defined");
	if ((err = getaddrlist(host, "print", &ailist)) != 0)
		err_quit("print: getaddrinfo error: %s", gai_strerror(err));

	for (aip = ailist; aip != NULL; aip = aip->ai_next) {
		if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
			err = errno;
		} else if (connect_retry(sockfd, aip->ai_addr,
		  aip->ai_addrlen) < 0) {
			err = errno;
		} else {
			submit_file(fd, sockfd, argv[1], sbuf.st_size, text);
			exit(0);
		}
	}
	errno = err;
	err_ret("print: can't contact %s", host);
	exit(1);
}

/*
 * Send a file to the printer daemon.
 */
void
submit_file(int fd, int sockfd, const char *fname, size_t nbytes,
            int text)
{
	int					nr, nw, len;
	struct passwd		*pwd;
	struct printreq		req;
	struct printresp	res;
	char				buf[IOBUFSZ];

	/*
	 * First build the header.
	 */
	if ((pwd = getpwuid(geteuid())) == NULL)
		strcpy(req.usernm, "unknown");
	else
		strcpy(req.usernm, pwd->pw_name);
	req.size = htonl(nbytes);
	if (text)
		req.flags = htonl(PR_TEXT);
	else
		req.flags = 0;
	if ((len = strlen(fname)) >= JOBNM_MAX) {
		/*
		 * Truncate the filename (+-5 accounts for the leading
		 * four characters and the terminating null).
		 */
		strcpy(req.jobnm, "... ");
		strncat(req.jobnm, &fname[len-JOBNM_MAX+5], JOBNM_MAX-5);
	} else {
		strcpy(req.jobnm, fname);
	}

	/*
	 * Send the header to the server.
	 */
	nw = writen(sockfd, &req, sizeof(struct printreq));
	if (nw != sizeof(struct printreq)) {
		if (nw < 0)
			err_sys("can't write to print server");
		else
			err_quit("short write (%d/%d) to print server",
			  nw, sizeof(struct printreq));
	}

	/*
	 * Now send the file.
	 */
	while ((nr = read(fd, buf, IOBUFSZ)) != 0) {
		nw = writen(sockfd, buf, nr);
		if (nw != nr) {
			if (nw < 0)
				err_sys("can't write to print server");
			else
				err_quit("short write (%d/%d) to print server",
				  nw, nr);
		}
	}

	/*
	 * Read the response.
	 */
	if ((nr = readn(sockfd, &res, sizeof(struct printresp))) !=
	  sizeof(struct printresp))
		err_sys("can't read response from server");
	if (res.retcode != 0) {
		printf("rejected: %s\n", res.msg);
		exit(1);
	} else {
		printf("job ID %ld\n", ntohl(res.jobid));
	}
	exit(0);
}
