1 /* $Id$ */
2
3 /*
4 * Copyright (c) 2006 Nicholas Marriott <nicholas.marriott@gmail.com>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/types.h>
20
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27
28 #include "fdm.h"
29 #include "fetch.h"
30
31 void fetch_stdin_abort(struct account *);
32 u_int fetch_stdin_total(struct account *);
33 void fetch_stdin_desc(struct account *, char *, size_t);
34
35 int fetch_stdin_state_init(struct account *, struct fetch_ctx *);
36 int fetch_stdin_state_mail(struct account *, struct fetch_ctx *);
37 int fetch_stdin_state_exit(struct account *, struct fetch_ctx *);
38
39 struct fetch fetch_stdin = {
40 "stdin",
41 fetch_stdin_state_init,
42
43 NULL,
44 NULL,
45 fetch_stdin_abort,
46 NULL,
47 fetch_stdin_desc
48 };
49
50 /* Abort; close stdin. */
51 void
fetch_stdin_abort(unused struct account * a)52 fetch_stdin_abort(unused struct account *a)
53 {
54 close(STDIN_FILENO);
55 }
56
57 /* Initialise stdin fetch. */
58 int
fetch_stdin_state_init(struct account * a,struct fetch_ctx * fctx)59 fetch_stdin_state_init(struct account *a, struct fetch_ctx *fctx)
60 {
61 /* Check stdin is valid. */
62 if (isatty(STDIN_FILENO)) {
63 log_warnx("%s: stdin is a tty. ignoring", a->name);
64 return (FETCH_ERROR);
65 }
66 if (fcntl(STDIN_FILENO, F_GETFL) == -1) {
67 if (errno != EBADF)
68 fatal("fcntl failed");
69 log_warnx("%s: stdin is invalid", a->name);
70 return (FETCH_ERROR);
71 }
72
73 fctx->state = fetch_stdin_state_mail;
74 return (FETCH_AGAIN);
75 }
76
77 /* Fetch mail from stdin. */
78 int
fetch_stdin_state_mail(struct account * a,struct fetch_ctx * fctx)79 fetch_stdin_state_mail(struct account *a, struct fetch_ctx *fctx)
80 {
81 struct mail *m = fctx->mail;
82 struct io *io;
83 char *line, *cause;
84
85 /* Open io for stdin. */
86 io = io_create(STDIN_FILENO, NULL, IO_LF);
87 if (conf.debug > 3 && !conf.syslog)
88 io->dup_fd = STDOUT_FILENO;
89
90 /* Initialise the mail. */
91 if (mail_open(m, IO_BLOCKSIZE) != 0) {
92 log_warn("%s: failed to create mail", a->name);
93 goto error;
94 }
95 m->size = 0;
96
97 /* Add default tags. */
98 default_tags(&m->tags, NULL);
99
100 /* Loop reading the mail. */
101 for (;;) {
102 /*
103 * There can only be one mail on stdin so reentrancy is
104 * irrelevent. This is a good thing since we want to check for
105 * close which means end of mail.
106 */
107 switch (io_pollline2(io,
108 &line, &fctx->lbuf, &fctx->llen, conf.timeout, &cause)) {
109 case 0:
110 /* Normal close is fine. */
111 goto out;
112 case -1:
113 if (errno == EAGAIN)
114 continue;
115 log_warnx("%s: %s", a->name, cause);
116 xfree(cause);
117 goto error;
118 }
119
120 if (append_line(m, line, strlen(line)) != 0) {
121 log_warn("%s: failed to resize mail", a->name);
122 goto error;
123 }
124 if (m->size > conf.max_size)
125 break;
126 }
127
128 out:
129 if (io != NULL)
130 io_free(io);
131
132 fctx->state = fetch_stdin_state_exit;
133 return (FETCH_MAIL);
134
135
136 error:
137 if (io != NULL)
138 io_free(io);
139
140 return (FETCH_ERROR);
141 }
142
143 /* Fetch finished; return exit. */
144 int
fetch_stdin_state_exit(unused struct account * a,unused struct fetch_ctx * fctx)145 fetch_stdin_state_exit(unused struct account *a, unused struct fetch_ctx *fctx)
146 {
147 close(STDIN_FILENO);
148 return (FETCH_EXIT);
149 }
150
151 void
fetch_stdin_desc(unused struct account * a,char * buf,size_t len)152 fetch_stdin_desc(unused struct account *a, char *buf, size_t len)
153 {
154 strlcpy(buf, "stdin", len);
155 }
156