|  | #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; | 
|  | } |