| #include "common.h" | 
 |  | 
 | typedef struct Qfile Qfile; | 
 | struct Qfile | 
 | { | 
 | 	Qfile	*next; | 
 | 	char	*name; | 
 | 	char	*tname; | 
 | } *files; | 
 |  | 
 | char *user; | 
 | int isnone; | 
 |  | 
 | int	copy(Qfile*); | 
 |  | 
 | void | 
 | usage(void) | 
 | { | 
 | 	fprint(2, "usage: qer [-f file] [-q dir] q-root description reply-to arg-list\n"); | 
 | 	exits("usage"); | 
 | } | 
 |  | 
 | void | 
 | error(char *f, char *a) | 
 | { | 
 | 	char err[Errlen+1]; | 
 | 	char buf[256]; | 
 |  | 
 | 	rerrstr(err, sizeof(err)); | 
 | 	snprint(buf, sizeof(buf),  f, a); | 
 | 	fprint(2, "qer: %s: %s\n", buf, err); | 
 | 	exits(buf); | 
 | } | 
 |  | 
 | void | 
 | main(int argc, char**argv) | 
 | { | 
 | 	Dir	*dir; | 
 | 	String	*f, *c; | 
 | 	int	fd; | 
 | 	char	file[1024]; | 
 | 	char	buf[1024]; | 
 | 	long	n; | 
 | 	char	*cp, *qdir; | 
 | 	int	i; | 
 | 	Qfile	*q, **l; | 
 |  | 
 | 	l = &files; | 
 | 	qdir = 0; | 
 |  | 
 | 	ARGBEGIN { | 
 | 	case 'f': | 
 | 		q = malloc(sizeof(Qfile)); | 
 | 		q->name = ARGF(); | 
 | 		q->next = *l; | 
 | 		*l = q; | 
 | 		break; | 
 | 	case 'q': | 
 | 		qdir = ARGF(); | 
 | 		if(qdir == 0) | 
 | 			usage(); | 
 | 		break; | 
 | 	default: | 
 | 		usage(); | 
 | 	} ARGEND; | 
 |  | 
 | 	if(argc < 3) | 
 | 		usage(); | 
 | 	user = getuser(); | 
 | 	isnone = (qdir != 0) || (strcmp(user, "none") == 0); | 
 |  | 
 | 	if(qdir == 0) { | 
 | 		qdir = user; | 
 | 		if(qdir == 0) | 
 | 			error("unknown user", 0); | 
 | 	} | 
 | 	snprint(file, sizeof(file), "%s/%s", argv[0], qdir); | 
 |  | 
 | 	/* | 
 | 	 *  data file name | 
 | 	 */ | 
 | 	f = s_copy(file); | 
 | 	s_append(f, "/D.XXXXXX"); | 
 | 	mktemp(s_to_c(f)); | 
 | 	cp = utfrrune(s_to_c(f), '/'); | 
 | 	cp++; | 
 |  | 
 | 	/* | 
 | 	 *  create directory and data file.  once the data file | 
 | 	 *  exists, runq won't remove the directory | 
 | 	 */ | 
 | 	fd = -1; | 
 | 	for(i = 0; i < 10; i++){ | 
 | 		int perm; | 
 |  | 
 | 		dir = dirstat(file); | 
 | 		if(dir == nil){ | 
 | 			perm = isnone?0777:0775; | 
 | 			if(sysmkdir(file, perm) < 0) | 
 | 				continue; | 
 | 		} else { | 
 | 			if((dir->qid.type&QTDIR)==0) | 
 | 				error("not a directory %s", file); | 
 | 		} | 
 | 		perm = isnone?0664:0660; | 
 | 		fd = create(s_to_c(f), OWRITE, perm); | 
 | 		if(fd >= 0) | 
 | 			break; | 
 | 		sleep(250); | 
 | 	} | 
 | 	if(fd < 0) | 
 | 		error("creating data file %s", s_to_c(f)); | 
 |  | 
 | 	/* | 
 | 	 *  copy over associated files | 
 | 	 */ | 
 | 	if(files){ | 
 | 		*cp = 'F'; | 
 | 		for(q = files; q; q = q->next){ | 
 | 			q->tname = strdup(s_to_c(f)); | 
 | 			if(copy(q) < 0) | 
 | 				error("copying %s to queue", q->name); | 
 | 			(*cp)++; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 *  copy in the data file | 
 | 	 */ | 
 | 	i = 0; | 
 | 	while((n = read(0, buf, sizeof(buf)-1)) > 0){ | 
 | 		if(i++ == 0 && strncmp(buf, "From", 4) != 0){ | 
 | 			buf[n] = 0; | 
 | 			syslog(0, "smtp", "qer usys data starts with %-40.40s\n", buf); | 
 | 		} | 
 | 		if(write(fd, buf, n) != n) | 
 | 			error("writing data file %s", s_to_c(f)); | 
 | 	} | 
 | /*	if(n < 0) | 
 | 		error("reading input"); */ | 
 | 	close(fd); | 
 |  | 
 | 	/* | 
 | 	 *  create control file | 
 | 	 */ | 
 | 	*cp = 'C'; | 
 | 	fd = syscreatelocked(s_to_c(f), OWRITE, 0664); | 
 | 	if(fd < 0) | 
 | 		error("creating control file %s", s_to_c(f)); | 
 | 	c = s_new(); | 
 | 	for(i = 1; i < argc; i++){ | 
 | 		s_append(c, argv[i]); | 
 | 		s_append(c, " "); | 
 | 	} | 
 | 	for(q = files; q; q = q->next){ | 
 | 		s_append(c, q->tname); | 
 | 		s_append(c, " "); | 
 | 	} | 
 | 	s_append(c, "\n"); | 
 | 	if(write(fd, s_to_c(c), strlen(s_to_c(c))) < 0) { | 
 | 		sysunlockfile(fd); | 
 | 		error("writing control file %s", s_to_c(f)); | 
 | 	} | 
 | 	sysunlockfile(fd); | 
 | 	exits(0); | 
 | } | 
 |  | 
 | int | 
 | copy(Qfile *q) | 
 | { | 
 | 	int from, to, n; | 
 | 	char buf[4096]; | 
 |  | 
 | 	from = open(q->name, OREAD); | 
 | 	if(from < 0) | 
 | 		return -1; | 
 | 	to = create(q->tname, OWRITE, 0660); | 
 | 	if(to < 0){ | 
 | 		close(from); | 
 | 		return -1; | 
 | 	} | 
 | 	for(;;){ | 
 | 		n = read(from, buf, sizeof(buf)); | 
 | 		if(n <= 0) | 
 | 			break; | 
 | 		n = write(to, buf, n); | 
 | 		if(n < 0) | 
 | 			break; | 
 | 	} | 
 | 	close(to); | 
 | 	close(from); | 
 | 	return n; | 
 | } |