Spaces -> tabs.
Nicholas Marriott
9 years ago
37 | 37 | if (SIZE_MAX / ((a)->num + (n)) < ARRAY_ITEMSIZE(a)) \ |
38 | 38 | fatalx("size too big"); \ |
39 | 39 | if ((a)->space == 0) { \ |
40 | (a)->space = ARRAY_INITIALSPACE(a); \ | |
40 | (a)->space = ARRAY_INITIALSPACE(a); \ | |
41 | 41 | (a)->list = xrealloc((a)->list, 1, (a)->space); \ |
42 | 42 | } \ |
43 | 43 | while ((a)->space <= ((a)->num + (n)) * ARRAY_ITEMSIZE(a)) { \ |
55 | 55 | |
56 | 56 | #define ARRAY_INIT(a) do { \ |
57 | 57 | (a)->num = 0; \ |
58 | (a)->list = NULL; \ | |
58 | (a)->list = NULL; \ | |
59 | 59 | (a)->space = 0; \ |
60 | 60 | } while (0) |
61 | 61 | #define ARRAY_CLEAR(a) do { \ |
74 | 74 | #define ARRAY_INSERT(a, i, s) do { \ |
75 | 75 | ARRAY_ENSURE(a, 1); \ |
76 | 76 | if ((i) < (a)->num) { \ |
77 | memmove((a)->list + (i) + 1, (a)->list + (i), \ | |
77 | memmove((a)->list + (i) + 1, (a)->list + (i), \ | |
78 | 78 | ARRAY_ITEMSIZE(a) * ((a)->num - (i))); \ |
79 | 79 | } \ |
80 | 80 | (a)->list[i] = s; \ |
82 | 82 | } while (0) |
83 | 83 | #define ARRAY_REMOVE(a, i) do { \ |
84 | 84 | if ((i) < (a)->num - 1) { \ |
85 | memmove((a)->list + (i), (a)->list + (i) + 1, \ | |
85 | memmove((a)->list + (i), (a)->list + (i) + 1, \ | |
86 | 86 | ARRAY_ITEMSIZE(a) * ((a)->num - (i) - 1)); \ |
87 | 87 | } \ |
88 | 88 | (a)->num--; \ |
96 | 96 | } while (0) |
97 | 97 | #define ARRAY_TRUNC(a, n) do { \ |
98 | 98 | if ((a)->num > n) \ |
99 | (a)->num -= n; \ | |
99 | (a)->num -= n; \ | |
100 | 100 | else \ |
101 | 101 | ARRAY_FREE(a); \ |
102 | 102 | } while (0) |
22 | 22 | |
23 | 23 | #include "fdm.h" |
24 | 24 | |
25 | char *attach_type(struct mail *, char *, const char *, char **); | |
25 | char *attach_type(struct mail *, char *, const char *, char **); | |
26 | 26 | struct attach *attach_get(struct mail *, char **, size_t *, const char *, |
27 | 27 | int *); |
28 | 28 | |
180 | 180 | if (ptr == NULL) |
181 | 181 | break; |
182 | 182 | if (ptr - hdr == namelen && strncmp(hdr, name, namelen) == 0) { |
183 | llen -= (ptr - hdr + 1); | |
183 | llen -= (ptr - hdr + 1); | |
184 | 184 | hdr = ptr + 1; |
185 | 185 | |
186 | 186 | ptr = memchr(hdr, ';', llen); |
135 | 135 | int flags, status, found = 0; |
136 | 136 | char *s, *cause, *lbuf, *out, *err, tag[24]; |
137 | 137 | size_t llen; |
138 | struct cmd *cmd = NULL; | |
138 | struct cmd *cmd = NULL; | |
139 | 139 | struct rmlist rml; |
140 | 140 | u_int i; |
141 | 141 | |
148 | 148 | /* Sort out the command. */ |
149 | 149 | s = replacepath( |
150 | 150 | &cmddata->cmd, m->tags, m, &m->rml, find_tag(m->tags, "home")); |
151 | if (s == NULL || *s == '\0') { | |
151 | if (s == NULL || *s == '\0') { | |
152 | 152 | log_warnx("%s: empty command", a->name); |
153 | 153 | goto error; |
154 | } | |
154 | } | |
155 | 155 | |
156 | 156 | log_debug2("%s: %s: started (ret=%d re=%s)", a->name, s, cmddata->ret, |
157 | 157 | cmddata->re.str == NULL ? "none" : cmddata->re.str); |
183 | 183 | log_warnx("%s: %s: %s", a->name, s, cause); |
184 | 184 | goto error; |
185 | 185 | } |
186 | if (status != 0) | |
186 | if (status != 0) | |
187 | 187 | break; |
188 | 188 | if (err != NULL) |
189 | 189 | log_warnx("%s: %s: %s", a->name, s, err); |
49 | 49 | double fetch_time_blocked = 0.0; |
50 | 50 | #endif |
51 | 51 | |
52 | struct mail_queue fetch_matchq; | |
53 | struct mail_queue fetch_deliverq; | |
54 | ||
55 | u_int fetch_dropped; | |
56 | u_int fetch_kept; | |
57 | ||
58 | u_int fetch_queued; /* number of mails queued */ | |
59 | u_int fetch_blocked; /* blocked for parent */ | |
52 | struct mail_queue fetch_matchq; | |
53 | struct mail_queue fetch_deliverq; | |
54 | ||
55 | u_int fetch_dropped; | |
56 | u_int fetch_kept; | |
57 | ||
58 | u_int fetch_queued; /* number of mails queued */ | |
59 | u_int fetch_blocked; /* blocked for parent */ | |
60 | 60 | |
61 | 61 | int |
62 | 62 | open_cache(struct account *a, struct cache *cache) |
93 | 93 | child_fetch(struct child *child, struct io *pio) |
94 | 94 | { |
95 | 95 | struct child_fetch_data *data = child->data; |
96 | enum fdmop op = data->op; | |
97 | struct account *a = data->account; | |
98 | struct msg msg; | |
96 | enum fdmop op = data->op; | |
97 | struct account *a = data->account; | |
98 | struct msg msg; | |
99 | 99 | int error, flags; |
100 | 100 | double tim; |
101 | 101 | |
345 | 345 | struct msgbuf msgbuf; |
346 | 346 | struct fetch_ctx fctx; |
347 | 347 | struct cache *cache; |
348 | struct iolist iol; | |
348 | struct iolist iol; | |
349 | 349 | int aborted, complete, holding, timeout; |
350 | 350 | |
351 | 351 | log_debug2("%s: fetching", a->name); |
352 | 352 | |
353 | 353 | TAILQ_INIT(&fetch_matchq); |
354 | TAILQ_INIT(&fetch_deliverq); | |
354 | TAILQ_INIT(&fetch_deliverq); | |
355 | 355 | fetch_queued = fetch_dropped = fetch_kept = 0; |
356 | 356 | |
357 | 357 | if (nflags & FETCH_POLL && a->fetch->total == NULL) { |
523 | 523 | { |
524 | 524 | struct mail_ctx *mctx; |
525 | 525 | char *hdr, rtime[128], *rhost, total[16]; |
526 | u_int n, b; | |
527 | size_t size; | |
528 | int error; | |
529 | struct tm *tm; | |
530 | time_t t; | |
526 | u_int n, b; | |
527 | size_t size; | |
528 | int error; | |
529 | struct tm *tm; | |
530 | time_t t; | |
531 | 531 | |
532 | 532 | /* |
533 | 533 | * Check for oversize mails. This must be first since there is no |
549 | 549 | return (0); |
550 | 550 | } |
551 | 551 | |
552 | /* | |
552 | /* | |
553 | 553 | * Find the mail body (needed by trim_from). This is probably slower |
554 | 554 | * than doing it during fetching but it guarantees consistency. |
555 | 555 | */ |
556 | 556 | m->body = find_body(m); |
557 | 557 | |
558 | /* Trim "From" line, if any. */ | |
558 | /* Trim "From" line, if any. */ | |
559 | 559 | trim_from(m); |
560 | 560 | |
561 | 561 | /* Check for empty mails. */ |
570 | 570 | m->tim = get_time(); |
571 | 571 | |
572 | 572 | /* Add account name tag. */ |
573 | add_tag(&m->tags, "account", "%s", a->name); | |
573 | add_tag(&m->tags, "account", "%s", a->name); | |
574 | 574 | |
575 | 575 | /* Add mail time tags. */ |
576 | 576 | if (mailtime(m, &t) != 0) { |
37 | 37 | |
38 | 38 | if (!TAILQ_EMPTY(&cleanlist)) { |
39 | 39 | TAILQ_FOREACH(cent, &cleanlist, entry) |
40 | log_debug("cleanup: %s", cent->path); | |
40 | log_debug("cleanup: %s", cent->path); | |
41 | 41 | fatalx("list not empty"); |
42 | 42 | } |
43 | 43 | } |
53 | 53 | */ |
54 | 54 | |
55 | 55 | saved_errno = errno; |
56 | TAILQ_FOREACH(cent, &cleanlist, entry) { | |
56 | TAILQ_FOREACH(cent, &cleanlist, entry) { | |
57 | 57 | if (unlink(cent->path) != 0) { |
58 | 58 | write(STDERR_FILENO, "unlink failed\n", 14); |
59 | 59 | _exit(1); |
116 | 116 | struct cleanent *cent; |
117 | 117 | |
118 | 118 | #if 0 |
119 | log_debug("cleanup_deregister: %s by %ld", path, (long) getpid()); | |
119 | log_debug("cleanup_deregister: %s by %ld", path, (long) getpid()); | |
120 | 120 | #endif |
121 | 121 | |
122 | 122 | if (path == NULL || *path == '\0') |
126 | 126 | if (sigprocmask(SIG_BLOCK, &set, &oset) < 0) |
127 | 127 | fatal("sigprocmask failed"); |
128 | 128 | |
129 | TAILQ_FOREACH(cent, &cleanlist, entry) { | |
129 | TAILQ_FOREACH(cent, &cleanlist, entry) { | |
130 | 130 | if (strcmp(cent->path, path) == 0) { |
131 | 131 | TAILQ_REMOVE(&cleanlist, cent, entry); |
132 | 132 | xfree(cent->path); |
37 | 37 | cmd_start(const char *s, int flags, const char *buf, size_t len, char **cause) |
38 | 38 | { |
39 | 39 | struct cmd *cmd; |
40 | int fd_in[2], fd_out[2], fd_err[2]; | |
40 | int fd_in[2], fd_out[2], fd_err[2]; | |
41 | 41 | |
42 | 42 | cmd = xmalloc(sizeof *cmd); |
43 | 43 | cmd->pid = -1; |
116 | 116 | close(fd_err[1]); |
117 | 117 | |
118 | 118 | #ifdef SIGINFO |
119 | if (signal(SIGINFO, SIG_DFL) == SIG_ERR) | |
119 | if (signal(SIGINFO, SIG_DFL) == SIG_ERR) | |
120 | 120 | fatal("signal failed"); |
121 | 121 | #endif |
122 | if (signal(SIGUSR1, SIG_DFL) == SIG_ERR) | |
123 | fatal("signal failed"); | |
124 | if (signal(SIGINT, SIG_DFL) == SIG_ERR) | |
125 | fatal("signal failed"); | |
126 | if (signal(SIGTERM, SIG_DFL) == SIG_ERR) | |
127 | fatal("signal failed"); | |
128 | if (signal(SIGPIPE, SIG_DFL) == SIG_ERR) | |
129 | fatal("signal failed"); | |
130 | if (signal(SIGUSR1, SIG_DFL) == SIG_ERR) | |
131 | fatal("signal failed"); | |
132 | if (signal(SIGUSR2, SIG_DFL) == SIG_ERR) | |
133 | fatal("signal failed"); | |
134 | if (signal(SIGCHLD, SIG_DFL) == SIG_ERR) | |
122 | if (signal(SIGUSR1, SIG_DFL) == SIG_ERR) | |
123 | fatal("signal failed"); | |
124 | if (signal(SIGINT, SIG_DFL) == SIG_ERR) | |
125 | fatal("signal failed"); | |
126 | if (signal(SIGTERM, SIG_DFL) == SIG_ERR) | |
127 | fatal("signal failed"); | |
128 | if (signal(SIGPIPE, SIG_DFL) == SIG_ERR) | |
129 | fatal("signal failed"); | |
130 | if (signal(SIGUSR1, SIG_DFL) == SIG_ERR) | |
131 | fatal("signal failed"); | |
132 | if (signal(SIGUSR2, SIG_DFL) == SIG_ERR) | |
133 | fatal("signal failed"); | |
134 | if (signal(SIGCHLD, SIG_DFL) == SIG_ERR) | |
135 | 135 | fatal("signal failed"); |
136 | 136 | |
137 | 137 | execl(_PATH_BSHELL, "sh", "-c", s, (char *) NULL); |
160 | 160 | if (fd_in[1] != -1) { |
161 | 161 | cmd->io_in = io_create(fd_in[1], NULL, IO_LF); |
162 | 162 | io_writeonly(cmd->io_in); |
163 | if (cmd->len != 0) | |
163 | if (cmd->len != 0) | |
164 | 164 | cmd->io_in->flags |= IOF_MUSTWR; |
165 | 165 | } |
166 | 166 | cmd->io_out = NULL; |
224 | 224 | int ssl; |
225 | 225 | const char *port; |
226 | 226 | } *proxyent, proxylist[] = { |
227 | { "http://", PROXY_HTTP, 0, "http" }, | |
228 | { "https://", PROXY_HTTPS, 1, "https" }, | |
229 | { "socks://", PROXY_SOCKS5, 0, "socks" }, | |
230 | { "socks5://", PROXY_SOCKS5, 0, "socks" }, | |
231 | { NULL, 0, 0, NULL } | |
227 | { "http://", PROXY_HTTP, 0, "http" }, | |
228 | { "https://", PROXY_HTTPS, 1, "https" }, | |
229 | { "socks://", PROXY_SOCKS5, 0, "socks" }, | |
230 | { "socks5://", PROXY_SOCKS5, 0, "socks" }, | |
231 | { NULL, 0, 0, NULL } | |
232 | 232 | }; |
233 | 233 | |
234 | 234 | /* Copy the url so we can mangle it. */ |
356 | 356 | getport(char *port) |
357 | 357 | { |
358 | 358 | struct servent *sv; |
359 | int n; | |
359 | int n; | |
360 | 360 | const char *errstr; |
361 | 361 | |
362 | 362 | sv = getservbyname(port, "tcp"); |
576 | 576 | SSL_CTX_set_options(ctx, SSL_OP_ALL); |
577 | 577 | else |
578 | 578 | SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_TLSv1); |
579 | SSL_CTX_set_default_verify_paths(ctx); | |
579 | SSL_CTX_set_default_verify_paths(ctx); | |
580 | 580 | SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); |
581 | 581 | |
582 | 582 | ssl = SSL_new(ctx); |
103 | 103 | db_print_item( |
104 | 104 | unused TDB_CONTEXT *tdb, unused TDB_DATA key, TDB_DATA value, void *ptr) |
105 | 105 | { |
106 | void (*p)(const char *, ...) = ptr; | |
106 | void (*p)(const char *, ...) = ptr; | |
107 | 107 | struct cacheitem v; |
108 | 108 | uint64_t tim; |
109 | 109 | |
110 | if (value.dsize != sizeof v) | |
110 | if (value.dsize != sizeof v) | |
111 | 111 | return (-1); |
112 | 112 | memcpy(&v, value.dptr, sizeof v); |
113 | 113 | |
131 | 131 | uint64_t *lim = ptr; |
132 | 132 | struct cacheitem v; |
133 | 133 | |
134 | if (value.dsize != sizeof v) | |
134 | if (value.dsize != sizeof v) | |
135 | 135 | return (-1); |
136 | 136 | memcpy(&v, value.dptr, sizeof v); |
137 | 137 | |
158 | 158 | int |
159 | 159 | db_clear_item(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value, unused void *ptr) |
160 | 160 | { |
161 | if (value.dsize != sizeof (struct cacheitem)) | |
161 | if (value.dsize != sizeof (struct cacheitem)) | |
162 | 162 | return (-1); |
163 | 163 | |
164 | 164 | return (tdb_delete(tdb, key)); |
169 | 169 | struct fetch_ctx fctx; |
170 | 170 | struct fetch_imap_data fdata; |
171 | 171 | char *cause, *folder, *ptr, *line; |
172 | size_t len, maillen; | |
172 | size_t len, maillen; | |
173 | 173 | u_int total, body; |
174 | 174 | |
175 | 175 | /* Connect to the IMAP server. */ |
32 | 32 | int deliver_maildir_deliver(struct deliver_ctx *, struct actitem *); |
33 | 33 | void deliver_maildir_desc(struct actitem *, char *, size_t); |
34 | 34 | |
35 | char *deliver_maildir_host(void); | |
35 | char *deliver_maildir_host(void); | |
36 | 36 | int deliver_maildir_create(struct account *, const char *); |
37 | 37 | |
38 | 38 | struct deliver deliver_maildir = { |
143 | 143 | static u_int delivered = 0; |
144 | 144 | char *host, *name, *path; |
145 | 145 | char src[MAXPATHLEN], dst[MAXPATHLEN]; |
146 | int fd; | |
147 | ssize_t n; | |
146 | int fd; | |
147 | ssize_t n; | |
148 | 148 | |
149 | 149 | name = NULL; |
150 | 150 | fd = -1; |
168 | 168 | do { |
169 | 169 | if (name != NULL) |
170 | 170 | xfree(name); |
171 | xasprintf(&name, "%ld.%ld_%u.%s", | |
171 | xasprintf(&name, "%ld.%ld_%u.%s", | |
172 | 172 | (long) time(NULL), (long) getpid(), delivered, host); |
173 | 173 | |
174 | 174 | if (ppath(src, sizeof src, "%s/tmp/%s", path, name) != 0) { |
70 | 70 | struct deliver_mbox_data *data = ti->data; |
71 | 71 | char *path, *ptr, *lptr, *from = NULL; |
72 | 72 | const char *msg; |
73 | size_t len, llen; | |
74 | int fd, saved_errno; | |
73 | size_t len, llen; | |
74 | int fd, saved_errno; | |
75 | 75 | FILE *f; |
76 | 76 | gzFile gzf; |
77 | 77 | long long used; |
78 | sigset_t set, oset; | |
78 | sigset_t set, oset; | |
79 | 79 | struct stat sb; |
80 | 80 | |
81 | 81 | f = gzf = NULL; |
153 | 153 | * done. |
154 | 154 | */ |
155 | 155 | sigemptyset(&set); |
156 | sigaddset(&set, SIGTERM); | |
156 | sigaddset(&set, SIGTERM); | |
157 | 157 | if (sigprocmask(SIG_BLOCK, &set, &oset) < 0) |
158 | 158 | fatal("sigprocmask failed"); |
159 | 159 |
42 | 42 | struct account *a = dctx->account; |
43 | 43 | struct mail *m = dctx->mail; |
44 | 44 | struct deliver_pipe_data *data = ti->data; |
45 | char *s, *cause, *err; | |
45 | char *s, *cause, *err; | |
46 | 46 | int status; |
47 | 47 | struct cmd *cmd = NULL; |
48 | 48 | char *lbuf; |
49 | 49 | size_t llen; |
50 | 50 | |
51 | 51 | s = replacepath(&data->cmd, m->tags, m, &m->rml, dctx->udata->home); |
52 | if (s == NULL || *s == '\0') { | |
52 | if (s == NULL || *s == '\0') { | |
53 | 53 | log_warnx("%s: empty command", a->name); |
54 | 54 | goto error; |
55 | } | |
55 | } | |
56 | 56 | |
57 | 57 | if (data->pipe) { |
58 | 58 | log_debug2("%s: piping to \"%s\"", a->name, s); |
75 | 75 | xfree(lbuf); |
76 | 76 | goto error_cause; |
77 | 77 | } |
78 | if (status == 0 && err != NULL) | |
78 | if (status == 0 && err != NULL) | |
79 | 79 | log_warnx("%s: %s: %s", a->name, s, err); |
80 | 80 | } while (status == 0); |
81 | 81 | status--; |
39 | 39 | struct mail *m = dctx->mail; |
40 | 40 | struct deliver_remove_header_data *data = ti->data; |
41 | 41 | char *ptr, *hdr; |
42 | size_t len, off, wrap; | |
42 | size_t len, off, wrap; | |
43 | 43 | u_int i, j; |
44 | 44 | |
45 | 45 |
45 | 45 | struct mail *m = dctx->mail; |
46 | 46 | struct deliver_rewrite_data *data = ti->data; |
47 | 47 | struct mail *md = &dctx->wr_mail; |
48 | char *s, *cause, *out, *err; | |
49 | int status; | |
48 | char *s, *cause, *out, *err; | |
49 | int status; | |
50 | 50 | struct cmd *cmd = NULL; |
51 | 51 | char *lbuf; |
52 | 52 | size_t llen; |
53 | 53 | |
54 | 54 | s = replacepath(&data->cmd, m->tags, m, &m->rml, dctx->udata->home); |
55 | if (s == NULL || *s == '\0') { | |
55 | if (s == NULL || *s == '\0') { | |
56 | 56 | log_warnx("%s: empty command", a->name); |
57 | 57 | goto error; |
58 | } | |
58 | } | |
59 | 59 | |
60 | 60 | log_debug2("%s: rewriting using \"%s\"", a->name, s); |
61 | 61 |
44 | 44 | { |
45 | 45 | char ch; |
46 | 46 | const char *errstr; |
47 | int n; | |
47 | int n; | |
48 | 48 | size_t len; |
49 | 49 | |
50 | 50 | len = strspn(line, "0123456789"); |
67 | 67 | struct account *a = dctx->account; |
68 | 68 | struct mail *m = dctx->mail; |
69 | 69 | struct deliver_smtp_data *data = ti->data; |
70 | int done, code; | |
70 | int done, code; | |
71 | 71 | struct io *io; |
72 | 72 | char *cause, *to, *from, *line, *ptr, *lbuf; |
73 | 73 | enum deliver_smtp_state state; |
74 | size_t len, llen; | |
74 | size_t len, llen; | |
75 | 75 | |
76 | 76 | io = connectproxy(&data->server, |
77 | 77 | conf.verify_certs, conf.proxy, IO_CRLF, conf.timeout, &cause); |
87 | 87 | lbuf = xmalloc(llen); |
88 | 88 | |
89 | 89 | if (conf.host_fqdn != NULL) |
90 | xasprintf(&ptr, "%s@%s", dctx->udata->name, conf.host_fqdn); | |
90 | xasprintf(&ptr, "%s@%s", dctx->udata->name, conf.host_fqdn); | |
91 | 91 | else |
92 | xasprintf(&ptr, "%s@%s", dctx->udata->name, conf.host_name); | |
92 | xasprintf(&ptr, "%s@%s", dctx->udata->name, conf.host_name); | |
93 | 93 | if (data->to.str == NULL) |
94 | 94 | to = xstrdup(ptr); |
95 | 95 | else { |
132 | 132 | goto error; |
133 | 133 | state = SMTP_HELO; |
134 | 134 | if (conf.host_fqdn != NULL) |
135 | io_writeline(io, "HELO %s", conf.host_fqdn); | |
135 | io_writeline(io, "HELO %s", conf.host_fqdn); | |
136 | 136 | else |
137 | io_writeline(io, "HELO %s", conf.host_name); | |
137 | io_writeline(io, "HELO %s", conf.host_name); | |
138 | 138 | break; |
139 | 139 | case SMTP_HELO: |
140 | 140 | if (code != 250) |
42 | 42 | struct account *a = dctx->account; |
43 | 43 | struct mail *m = dctx->mail; |
44 | 44 | struct deliver_write_data *data = ti->data; |
45 | char *path; | |
46 | FILE *f; | |
45 | char *path; | |
46 | FILE *f; | |
47 | 47 | |
48 | 48 | path = replacepath(&data->path, m->tags, m, &m->rml, dctx->udata->home); |
49 | if (path == NULL || *path == '\0') { | |
49 | if (path == NULL || *path == '\0') { | |
50 | 50 | if (path != NULL) |
51 | 51 | xfree(path); |
52 | 52 | log_warnx("%s: empty command", a->name); |
53 | return (DELIVER_FAILURE); | |
54 | } | |
53 | return (DELIVER_FAILURE); | |
54 | } | |
55 | 55 | |
56 | 56 | if (data->append) { |
57 | 57 | log_debug2("%s: appending to %s", a->name, path); |
60 | 60 | log_debug2("%s: writing to %s", a->name, path); |
61 | 61 | f = fopen(path, "w"); |
62 | 62 | } |
63 | if (f == NULL) { | |
63 | if (f == NULL) { | |
64 | 64 | log_warn("%s: %s: fopen", a->name, path); |
65 | 65 | goto error; |
66 | 66 | } |
24 | 24 | |
25 | 25 | /* Deliver context. */ |
26 | 26 | struct deliver_ctx { |
27 | double tim; | |
27 | double tim; | |
28 | 28 | |
29 | 29 | struct action *action; |
30 | 30 | struct actitem *actitem; |
35 | 35 | |
36 | 36 | struct userdata *udata; |
37 | 37 | |
38 | struct mail wr_mail; | |
38 | struct mail wr_mail; | |
39 | 39 | |
40 | 40 | TAILQ_ENTRY(deliver_ctx) entry; |
41 | 41 | }; |
52 | 52 | const char *name; |
53 | 53 | enum delivertype type; |
54 | 54 | |
55 | int (*deliver)(struct deliver_ctx *, struct actitem *); | |
55 | int (*deliver)(struct deliver_ctx *, struct actitem *); | |
56 | 56 | void (*desc)(struct actitem *, char *, size_t); |
57 | 57 | }; |
58 | 58 | |
160 | 160 | extern struct deliver deliver_tag; |
161 | 161 | |
162 | 162 | /* deliver-pipe.c */ |
163 | extern struct deliver deliver_pipe; | |
163 | extern struct deliver deliver_pipe; | |
164 | 164 | |
165 | 165 | /* deliver-drop.c */ |
166 | extern struct deliver deliver_drop; | |
166 | extern struct deliver deliver_drop; | |
167 | 167 | |
168 | 168 | /* deliver-keep.c */ |
169 | extern struct deliver deliver_keep; | |
169 | extern struct deliver deliver_keep; | |
170 | 170 | |
171 | 171 | /* deliver-maildir.c */ |
172 | extern struct deliver deliver_maildir; | |
172 | extern struct deliver deliver_maildir; | |
173 | 173 | |
174 | 174 | /* deliver-remove-header.c */ |
175 | 175 | extern struct deliver deliver_remove_header; |
178 | 178 | extern struct deliver deliver_add_header; |
179 | 179 | |
180 | 180 | /* deliver-mbox.c */ |
181 | extern struct deliver deliver_mbox; | |
181 | extern struct deliver deliver_mbox; | |
182 | 182 | |
183 | 183 | /* deliver-write.c */ |
184 | extern struct deliver deliver_write; | |
184 | extern struct deliver deliver_write; | |
185 | 185 | |
186 | 186 | /* deliver-rewrite.c */ |
187 | extern struct deliver deliver_rewrite; | |
187 | extern struct deliver deliver_rewrite; | |
188 | 188 | |
189 | 189 | /* deliver-add-to-cache.c */ |
190 | extern struct deliver deliver_add_to_cache; | |
190 | extern struct deliver deliver_add_to_cache; | |
191 | 191 | |
192 | 192 | /* deliver-remove-from-cache.c */ |
193 | extern struct deliver deliver_remove_from_cache; | |
193 | extern struct deliver deliver_remove_from_cache; | |
194 | 194 | |
195 | 195 | #endif |
267 | 267 | fprintf(stderr, |
268 | 268 | "usage: %s [-hklmnqv] [-a name] [-D name=value] [-f conffile] " |
269 | 269 | "[-u user] [-x name] [fetch|poll|cache] [arguments]\n", __progname); |
270 | exit(1); | |
270 | exit(1); | |
271 | 271 | } |
272 | 272 | |
273 | 273 | int |
274 | 274 | main(int argc, char **argv) |
275 | 275 | { |
276 | int opt, lockfd, status, res; | |
276 | int opt, lockfd, status, res; | |
277 | 277 | u_int i; |
278 | enum fdmop op = FDMOP_NONE; | |
278 | enum fdmop op = FDMOP_NONE; | |
279 | 279 | const char *proxy = NULL, *s; |
280 | 280 | char tmp[BUFSIZ], *ptr, *lock = NULL, *user, *home = NULL; |
281 | 281 | struct utsname un; |
287 | 287 | pid_t pid; |
288 | 288 | struct children children, dead_children; |
289 | 289 | struct child *child; |
290 | struct io *dead_io; | |
290 | struct io *dead_io; | |
291 | 291 | struct iolist iol; |
292 | 292 | double tim; |
293 | 293 | struct sigaction act; |
332 | 332 | ARRAY_INIT(&conf.excl); |
333 | 333 | |
334 | 334 | ARRAY_INIT(¯os); |
335 | while ((opt = getopt(argc, argv, "a:D:f:hklmnqu:vx:")) != -1) { | |
336 | switch (opt) { | |
335 | while ((opt = getopt(argc, argv, "a:D:f:hklmnqu:vx:")) != -1) { | |
336 | switch (opt) { | |
337 | 337 | case 'a': |
338 | 338 | ARRAY_ADD(&conf.incl, xstrdup(optarg)); |
339 | 339 | break; |
340 | 340 | case 'D': |
341 | 341 | ARRAY_ADD(¯os, optarg); |
342 | 342 | break; |
343 | case 'f': | |
343 | case 'f': | |
344 | 344 | if (conf.conf_file == NULL) |
345 | 345 | conf.conf_file = xstrdup(optarg); |
346 | break; | |
346 | break; | |
347 | 347 | case 'h': |
348 | 348 | home = getenv("HOME"); |
349 | 349 | break; |
363 | 363 | if (conf.def_user == NULL) |
364 | 364 | conf.def_user = xstrdup(optarg); |
365 | 365 | break; |
366 | case 'v': | |
366 | case 'v': | |
367 | 367 | if (conf.debug != -1) |
368 | 368 | conf.debug++; |
369 | break; | |
369 | break; | |
370 | 370 | case 'q': |
371 | 371 | conf.debug = -1; |
372 | 372 | break; |
373 | 373 | case 'x': |
374 | 374 | ARRAY_ADD(&conf.excl, xstrdup(optarg)); |
375 | 375 | break; |
376 | default: | |
377 | usage(); | |
378 | } | |
379 | } | |
376 | default: | |
377 | usage(); | |
378 | } | |
379 | } | |
380 | 380 | argc -= optind; |
381 | 381 | argv += optind; |
382 | 382 | if (conf.check_only) { |
425 | 425 | log_warnx("unknown user: %lu", (u_long) geteuid()); |
426 | 426 | exit(1); |
427 | 427 | } |
428 | user = xstrdup(pw->pw_name); | |
428 | user = xstrdup(pw->pw_name); | |
429 | 429 | if (home != NULL && *home != '\0') |
430 | 430 | conf.user_home = xstrdup(home); |
431 | 431 | else |
444 | 444 | } |
445 | 445 | log_debug2("loading configuration from %s", conf.conf_file); |
446 | 446 | if (stat(conf.conf_file, &sb) == -1) { |
447 | log_warn("%s", conf.conf_file); | |
447 | log_warn("%s", conf.conf_file); | |
448 | 448 | exit(1); |
449 | 449 | } |
450 | 450 | if (geteuid() != 0 && (sb.st_mode & (S_IROTH|S_IWOTH)) != 0) |
451 | 451 | log_warnx("%s: world readable or writable", conf.conf_file); |
452 | if (parse_conf(conf.conf_file, ¯os) != 0) { | |
453 | log_warn("%s", conf.conf_file); | |
452 | if (parse_conf(conf.conf_file, ¯os) != 0) { | |
453 | log_warn("%s", conf.conf_file); | |
454 | 454 | exit(1); |
455 | 455 | } |
456 | 456 | ARRAY_FREE(¯os); |
470 | 470 | conf.queue_low = conf.queue_high * 3 / 4; |
471 | 471 | if (conf.queue_low >= conf.queue_high) |
472 | 472 | conf.queue_low = conf.queue_high - 1; |
473 | } | |
473 | } | |
474 | 474 | |
475 | 475 | /* Set the umask. */ |
476 | 476 | umask(conf.file_umask); |
618 | 618 | /* If -n, bail now, otherwise check there is something to work with. */ |
619 | 619 | if (conf.check_only) |
620 | 620 | exit(0); |
621 | if (TAILQ_EMPTY(&conf.accounts)) { | |
622 | log_warnx("no accounts specified"); | |
621 | if (TAILQ_EMPTY(&conf.accounts)) { | |
622 | log_warnx("no accounts specified"); | |
623 | 623 | exit(1); |
624 | 624 | } |
625 | if (op == FDMOP_FETCH && TAILQ_EMPTY(&conf.rules)) { | |
626 | log_warnx("no rules specified"); | |
625 | if (op == FDMOP_FETCH && TAILQ_EMPTY(&conf.rules)) { | |
626 | log_warnx("no rules specified"); | |
627 | 627 | exit(1); |
628 | 628 | } |
629 | 629 | |
699 | 699 | } |
700 | 700 | conf.lock_file = lock; |
701 | 701 | |
702 | SSL_library_init(); | |
703 | SSL_load_error_strings(); | |
702 | SSL_library_init(); | |
703 | SSL_load_error_strings(); | |
704 | 704 | |
705 | 705 | #ifdef DEBUG |
706 | 706 | COUNTFDS("parent"); |
713 | 713 | TAILQ_INSERT_HEAD(&actaq, a, active_entry); |
714 | 714 | } |
715 | 715 | if (TAILQ_EMPTY(&actaq)) { |
716 | log_warnx("no accounts found"); | |
716 | log_warnx("no accounts found"); | |
717 | 717 | res = 1; |
718 | 718 | goto out; |
719 | 719 | } |
868 | 868 | } |
869 | 869 | |
870 | 870 | tim = get_time() - tim; |
871 | log_debug2("parent: finished, total time %.3f seconds", tim); | |
871 | log_debug2("parent: finished, total time %.3f seconds", tim); | |
872 | 872 | |
873 | 873 | out: |
874 | 874 | if (!conf.allow_many && *conf.lock_file != '\0') |
882 | 882 | if (conf.proxy->user != NULL) |
883 | 883 | xfree(conf.proxy->user); |
884 | 884 | if (conf.proxy->pass != NULL) |
885 | xfree(conf.proxy->pass); | |
885 | xfree(conf.proxy->pass); | |
886 | 886 | if (conf.proxy->server.host != NULL) |
887 | xfree(conf.proxy->server.host); | |
887 | xfree(conf.proxy->server.host); | |
888 | 888 | if (conf.proxy->server.port != NULL) |
889 | xfree(conf.proxy->server.port); | |
889 | xfree(conf.proxy->server.port); | |
890 | 890 | xfree(conf.proxy); |
891 | 891 | } |
892 | 892 | while (!TAILQ_EMPTY(&conf.caches)) { |
61 | 61 | #define DEFSTRIPCHARS "\\<>$%^&*|{}[]\"'`;" |
62 | 62 | #define MAXACTIONCHAIN 5 |
63 | 63 | #define DEFTIMEOUT (900 * 1000) |
64 | #define LOCKSLEEPTIME 10000 /* 0.1 seconds */ | |
64 | #define LOCKSLEEPTIME 10000 /* 0.1 seconds */ | |
65 | 65 | #define LOCKTOTALTIME 10000000 /* 10 seconds */ |
66 | 66 | #define MAXNAMESIZE 64 |
67 | 67 | #define DEFUMASK (S_IRWXG|S_IRWXO) |
121 | 121 | /* Convert a file mode for %o%o%o printf. */ |
122 | 122 | #define MODE(m) \ |
123 | 123 | (m & S_IRUSR ? 4 : 0) + (m & S_IWUSR ? 2 : 0) + (m & S_IXUSR ? 1 : 0), \ |
124 | (m & S_IRGRP ? 4 : 0) + (m & S_IWGRP ? 2 : 0) + (m & S_IXGRP ? 1 : 0), \ | |
124 | (m & S_IRGRP ? 4 : 0) + (m & S_IWGRP ? 2 : 0) + (m & S_IXGRP ? 1 : 0), \ | |
125 | 125 | (m & S_IROTH ? 4 : 0) + (m & S_IWOTH ? 2 : 0) + (m & S_IXOTH ? 1 : 0) |
126 | 126 | |
127 | 127 | /* Definition to shut gcc up about unused arguments. */ |
264 | 264 | u_int ent_max; |
265 | 265 | |
266 | 266 | size_t str_used; |
267 | size_t str_size; | |
267 | size_t str_size; | |
268 | 268 | }; |
269 | 269 | |
270 | 270 | /* Initial string block slots and block size. */ |
315 | 315 | |
316 | 316 | /* Cache data. */ |
317 | 317 | struct cache { |
318 | TDB_CONTEXT *db; | |
319 | ||
320 | char *path; | |
318 | TDB_CONTEXT *db; | |
319 | ||
320 | char *path; | |
321 | 321 | uint64_t expire; |
322 | 322 | |
323 | 323 | TAILQ_ENTRY(cache) entry; |
324 | 324 | }; |
325 | 325 | struct cacheitem { |
326 | uint64_t tim; | |
326 | uint64_t tim; | |
327 | 327 | uint32_t pad[4]; |
328 | 328 | } __packed; |
329 | 329 | |
344 | 344 | char *data; |
345 | 345 | size_t off; |
346 | 346 | |
347 | size_t size; /* size of mail */ | |
348 | size_t space; /* size of allocated area */ | |
349 | ||
350 | size_t body; /* offset of body */ | |
347 | size_t size; /* size of mail */ | |
348 | size_t space; /* size of allocated area */ | |
349 | ||
350 | size_t body; /* offset of body */ | |
351 | 351 | |
352 | 352 | ARRAY_DECL(, size_t) wrapped; /* list of wrapped lines */ |
353 | 353 | char wrapchar; /* wrapped character */ |
393 | 393 | |
394 | 394 | /* An attachment. */ |
395 | 395 | struct attach { |
396 | u_int idx; | |
397 | ||
398 | size_t data; | |
399 | size_t body; | |
400 | size_t size; | |
396 | u_int idx; | |
397 | ||
398 | size_t data; | |
399 | size_t body; | |
400 | size_t size; | |
401 | 401 | |
402 | 402 | char *type; |
403 | 403 | char *name; |
418 | 418 | |
419 | 419 | /* Privsep message data. */ |
420 | 420 | struct msgdata { |
421 | int error; | |
422 | struct mail mail; | |
421 | int error; | |
422 | struct mail mail; | |
423 | 423 | |
424 | 424 | /* These only work so long as they aren't moved in either process. */ |
425 | 425 | struct account *account; |
427 | 427 | struct match_command_data *cmddata; |
428 | 428 | |
429 | 429 | uid_t uid; |
430 | gid_t gid; | |
430 | gid_t gid; | |
431 | 431 | }; |
432 | 432 | |
433 | 433 | /* Privsep message buffer. */ |
473 | 473 | void (*hook)(int, struct account *, struct msg *, |
474 | 474 | struct child_deliver_data *, int *); |
475 | 475 | |
476 | struct child *child; /* the source of the request */ | |
476 | struct child *child; /* the source of the request */ | |
477 | 477 | |
478 | 478 | uid_t uid; |
479 | 479 | gid_t gid; |
604 | 604 | |
605 | 605 | /* Configuration settings. */ |
606 | 606 | struct conf { |
607 | int debug; | |
607 | int debug; | |
608 | 608 | int syslog; |
609 | 609 | |
610 | 610 | uid_t child_uid; |
611 | 611 | gid_t child_gid; |
612 | 612 | char *tmp_dir; |
613 | 613 | |
614 | struct strings incl; | |
614 | struct strings incl; | |
615 | 615 | struct strings excl; |
616 | 616 | |
617 | 617 | struct proxy *proxy; |
644 | 644 | |
645 | 645 | size_t max_size; |
646 | 646 | int timeout; |
647 | int del_big; | |
647 | int del_big; | |
648 | 648 | u_int lock_types; |
649 | 649 | |
650 | 650 | char *def_user; |
652 | 652 | |
653 | 653 | TAILQ_HEAD(, cache) caches; |
654 | 654 | TAILQ_HEAD(, account) accounts; |
655 | TAILQ_HEAD(, action) actions; | |
655 | TAILQ_HEAD(, action) actions; | |
656 | 656 | struct rules rules; |
657 | 657 | }; |
658 | 658 | extern struct conf conf; |
659 | 659 | |
660 | 660 | /* Command flags. */ |
661 | #define CMD_IN 0x1 | |
661 | #define CMD_IN 0x1 | |
662 | 662 | #define CMD_OUT 0x2 |
663 | 663 | #define CMD_ONCE 0x4 |
664 | 664 | |
665 | 665 | /* Command data. */ |
666 | 666 | struct cmd { |
667 | pid_t pid; | |
667 | pid_t pid; | |
668 | 668 | int status; |
669 | 669 | int flags; |
670 | 670 | |
707 | 707 | |
708 | 708 | #ifndef HAVE_STRLCPY |
709 | 709 | /* strlcpy.c */ |
710 | size_t strlcpy(char *, const char *, size_t); | |
710 | size_t strlcpy(char *, const char *, size_t); | |
711 | 711 | #endif |
712 | 712 | |
713 | 713 | #ifndef HAVE_STRLCAT |
714 | 714 | /* strlcat.c */ |
715 | size_t strlcat(char *, const char *, size_t); | |
715 | size_t strlcat(char *, const char *, size_t); | |
716 | 716 | #endif |
717 | 717 | |
718 | 718 | /* shm.c */ |
719 | char *shm_path(struct shm *); | |
719 | char *shm_path(struct shm *); | |
720 | 720 | void *shm_create(struct shm *, size_t); |
721 | 721 | int shm_owner(struct shm *, uid_t, gid_t); |
722 | 722 | void shm_destroy(struct shm *); |
725 | 725 | void *shm_resize(struct shm *, size_t, size_t); |
726 | 726 | |
727 | 727 | /* lex.c */ |
728 | int yylex(void); | |
728 | int yylex(void); | |
729 | 729 | |
730 | 730 | /* parse.y */ |
731 | 731 | extern struct macros parse_macros; |
732 | extern struct files parse_filestack; | |
732 | extern struct files parse_filestack; | |
733 | 733 | extern struct file *parse_file; |
734 | 734 | extern struct strb *parse_tags; |
735 | int parse_conf(const char *, struct strings *); | |
735 | int parse_conf(const char *, struct strings *); | |
736 | 736 | __dead printflike1 void yyerror(const char *, ...); |
737 | 737 | |
738 | 738 | /* parse-fn.c */ |
739 | 739 | char *expand_path(const char *, const char *); |
740 | 740 | char *run_command(const char *, const char *); |
741 | char *fmt_replstrs(const char *, struct replstrs *); | |
742 | char *fmt_strings(const char *, struct strings *); | |
741 | char *fmt_replstrs(const char *, struct replstrs *); | |
742 | char *fmt_strings(const char *, struct strings *); | |
743 | 743 | int have_accounts(char *); |
744 | 744 | struct account *find_account(char *); |
745 | struct action *find_action(char *); | |
745 | struct action *find_action(char *); | |
746 | 746 | struct actions *match_actions(const char *); |
747 | struct macro *extract_macro(char *); | |
747 | struct macro *extract_macro(char *); | |
748 | 748 | struct macro *find_macro(const char *); |
749 | 749 | void find_netrc(const char *, char **, char **); |
750 | 750 | int find_netrc1(const char *, char **, char **, char **); |
760 | 760 | void print_rule(struct rule *); |
761 | 761 | |
762 | 762 | /* netrc.c */ |
763 | FILE *netrc_open(const char *, char **); | |
763 | FILE *netrc_open(const char *, char **); | |
764 | 764 | void netrc_close(FILE *); |
765 | 765 | int netrc_lookup(FILE *, const char *, char **, char **); |
766 | 766 | |
771 | 771 | double get_time(void); |
772 | 772 | void dropto(uid_t, gid_t); |
773 | 773 | int check_incl(const char *); |
774 | int check_excl(const char *); | |
774 | int check_excl(const char *); | |
775 | 775 | int use_account(struct account *, char **); |
776 | 776 | void fill_host(void); |
777 | 777 | __dead void usage(void); |
787 | 787 | void re_free(struct re *); |
788 | 788 | |
789 | 789 | /* attach.c */ |
790 | struct attach *attach_visit(struct attach *, u_int *); | |
790 | struct attach *attach_visit(struct attach *, u_int *); | |
791 | 791 | void printflike2 attach_log(struct attach *, const char *, ...); |
792 | struct attach *attach_build(struct mail *); | |
792 | struct attach *attach_build(struct mail *); | |
793 | 793 | void attach_free(struct attach *); |
794 | 794 | |
795 | 795 | /* lookup.c */ |
807 | 807 | int privsep_recv(struct io *, struct msg *, struct msgbuf *); |
808 | 808 | |
809 | 809 | /* command.c */ |
810 | struct cmd *cmd_start(const char *, int, const char *, size_t, char **); | |
810 | struct cmd *cmd_start(const char *, int, const char *, size_t, char **); | |
811 | 811 | int cmd_poll(struct cmd *, char **, char **, char **, size_t *, |
812 | 812 | int, char **); |
813 | 813 | void cmd_free(struct cmd *); |
815 | 815 | /* child.c */ |
816 | 816 | int child_fork(void); |
817 | 817 | __dead void child_exit(int); |
818 | struct child *child_start(struct children *, uid_t, gid_t, | |
819 | int (*)(struct child *, struct io *), | |
820 | int (*)(struct child *, struct msg *, struct msgbuf *), | |
818 | struct child *child_start(struct children *, uid_t, gid_t, | |
819 | int (*)(struct child *, struct io *), | |
820 | int (*)(struct child *, struct msg *, struct msgbuf *), | |
821 | 821 | void *, struct child *); |
822 | 822 | |
823 | 823 | /* child-fetch.c */ |
827 | 827 | /* child-deliver.c */ |
828 | 828 | int child_deliver(struct child *, struct io *); |
829 | 829 | void child_deliver_action_hook(int, struct account *, struct msg *, |
830 | struct child_deliver_data *, int *); | |
830 | struct child_deliver_data *, int *); | |
831 | 831 | void child_deliver_cmd_hook(int, struct account *, struct msg *, |
832 | struct child_deliver_data *, int *); | |
832 | struct child_deliver_data *, int *); | |
833 | 833 | |
834 | 834 | /* parent-fetch.c */ |
835 | 835 | int parent_fetch(struct child *, struct msg *, struct msgbuf *); |
843 | 843 | void timer_cancel(void); |
844 | 844 | |
845 | 845 | /* connect.c */ |
846 | char *sslerror(const char *); | |
846 | char *sslerror(const char *); | |
847 | 847 | char *sslerror2(int, const char *); |
848 | 848 | void getaddrs(const char *, char **, char **); |
849 | struct proxy *getproxy(const char *); | |
850 | struct io *connectproxy(struct server *, int, struct proxy *, | |
851 | const char *, int, char **); | |
849 | struct proxy *getproxy(const char *); | |
850 | struct io *connectproxy(struct server *, int, struct proxy *, | |
851 | const char *, int, char **); | |
852 | 852 | struct io *connectio(struct server *, int, const char *, int, char **); |
853 | 853 | |
854 | 854 | /* file.c */ |
855 | 855 | int printflike3 ppath(char *, size_t, const char *, ...); |
856 | 856 | int vppath(char *, size_t, const char *, va_list); |
857 | int openlock(const char *, int, u_int); | |
858 | int createlock(const char *, int, uid_t, gid_t, mode_t, u_int); | |
859 | void closelock(int, const char *, u_int); | |
857 | int openlock(const char *, int, u_int); | |
858 | int createlock(const char *, int, uid_t, gid_t, mode_t, u_int); | |
859 | void closelock(int, const char *, u_int); | |
860 | 860 | int locksleep(const char *, const char *, long long *); |
861 | int xcreate(const char *, int, uid_t, gid_t, mode_t); | |
861 | int xcreate(const char *, int, uid_t, gid_t, mode_t); | |
862 | 862 | int xmkdir(const char *, uid_t, gid_t, mode_t); |
863 | 863 | int xmkpath(const char *, uid_t, gid_t, mode_t); |
864 | const char *checkmode(struct stat *, mode_t); | |
865 | const char *checkowner(struct stat *, uid_t); | |
866 | const char *checkgroup(struct stat *, gid_t); | |
864 | const char *checkmode(struct stat *, mode_t); | |
865 | const char *checkowner(struct stat *, uid_t); | |
866 | const char *checkgroup(struct stat *, gid_t); | |
867 | 867 | int safemove(const char *, const char *); |
868 | 868 | |
869 | 869 | /* mail.c */ |
884 | 884 | int append_line(struct mail *, const char *, size_t); |
885 | 885 | char *find_address(char *, size_t, size_t *); |
886 | 886 | void trim_from(struct mail *); |
887 | char *make_from(struct mail *, char *); | |
887 | char *make_from(struct mail *, char *); | |
888 | 888 | u_int fill_wrapped(struct mail *); |
889 | 889 | void set_wrapped(struct mail *, char); |
890 | 890 | |
911 | 911 | void cleanup_check(void); |
912 | 912 | void cleanup_flush(void); |
913 | 913 | void cleanup_purge(void); |
914 | void cleanup_register(const char *); | |
915 | void cleanup_deregister(const char *); | |
914 | void cleanup_register(const char *); | |
915 | void cleanup_deregister(const char *); | |
916 | 916 | |
917 | 917 | /* strb.c */ |
918 | 918 | void strb_create(struct strb **); |
919 | 919 | void strb_clear(struct strb **); |
920 | 920 | void strb_destroy(struct strb **); |
921 | 921 | void strb_dump(struct strb *, const char *, |
922 | void (*)(const char *, ...)); | |
922 | void (*)(const char *, ...)); | |
923 | 923 | void printflike3 strb_add(struct strb **, const char *, const char *, ...); |
924 | 924 | void strb_vadd(struct strb **, const char *, const char *, va_list); |
925 | 925 | struct strbent *strb_find(struct strb *, const char *); |
926 | struct strbent *strb_match(struct strb *, const char *); | |
926 | struct strbent *strb_match(struct strb *, const char *); | |
927 | 927 | |
928 | 928 | /* replace.c */ |
929 | 929 | void printflike3 add_tag(struct strb **, const char *, const char *, ...); |
932 | 932 | void default_tags(struct strb **, const char *); |
933 | 933 | void update_tags(struct strb **, struct userdata *); |
934 | 934 | void reset_tags(struct strb **); |
935 | char *replacestr(struct replstr *, struct strb *, struct mail *, | |
936 | struct rmlist *); | |
937 | char *replacepath(struct replpath *, struct strb *, struct mail *, | |
935 | char *replacestr(struct replstr *, struct strb *, struct mail *, | |
936 | struct rmlist *); | |
937 | char *replacepath(struct replpath *, struct strb *, struct mail *, | |
938 | 938 | struct rmlist *, const char *); |
939 | 939 | |
940 | 940 | /* log.c */ |
968 | 968 | int printflike3 xsnprintf(char *, size_t, const char *, ...); |
969 | 969 | int xvsnprintf(char *, size_t, const char *, va_list); |
970 | 970 | int printflike3 printpath(char *, size_t, const char *, ...); |
971 | char *xdirname(const char *); | |
972 | char *xbasename(const char *); | |
971 | char *xdirname(const char *); | |
972 | char *xbasename(const char *); | |
973 | 973 | |
974 | 974 | /* xmalloc-debug.c */ |
975 | 975 | #ifdef DEBUG |
134 | 134 | fetch_maildir_freepaths(struct account *a) |
135 | 135 | { |
136 | 136 | struct fetch_maildir_data *data = a->data; |
137 | u_int i; | |
137 | u_int i; | |
138 | 138 | |
139 | 139 | if (data->paths == NULL) |
140 | 140 | return; |
312 | 312 | struct fetch_maildir_data *data = a->data; |
313 | 313 | char *path; |
314 | 314 | |
315 | path = ARRAY_ITEM(data->paths, data->index); | |
315 | path = ARRAY_ITEM(data->paths, data->index); | |
316 | 316 | |
317 | 317 | /* Open the directory. */ |
318 | 318 | log_debug2("%s: trying path: %s", a->name, path); |
333 | 333 | struct mail *m = fctx->mail; |
334 | 334 | struct fetch_maildir_mail *aux; |
335 | 335 | struct dirent *dp; |
336 | char *path, *maildir, name[MAXPATHLEN]; | |
336 | char *path, *maildir, name[MAXPATHLEN]; | |
337 | 337 | struct stat sb; |
338 | 338 | uintmax_t size; |
339 | 339 | int fd; |
340 | 340 | ssize_t n; |
341 | 341 | |
342 | path = ARRAY_ITEM(data->paths, data->index); | |
342 | path = ARRAY_ITEM(data->paths, data->index); | |
343 | 343 | |
344 | 344 | restart: |
345 | 345 | /* Read the next dir entry. */ |
301 | 301 | struct fetch_mbox_data *data = a->data; |
302 | 302 | struct fetch_mbox_mbox *fmbox; |
303 | 303 | char *ptr; |
304 | struct stat sb; | |
304 | struct stat sb; | |
305 | 305 | uintmax_t size; |
306 | 306 | long long used; |
307 | 307 |
90 | 90 | { |
91 | 91 | char ch; |
92 | 92 | const char *errstr; |
93 | int n; | |
93 | int n; | |
94 | 94 | size_t len; |
95 | 95 | |
96 | 96 | len = strspn(line, "0123456789"); |
254 | 254 | error: |
255 | 255 | if (f != NULL) |
256 | 256 | fclose(f); |
257 | if (fd != -1) | |
257 | if (fd != -1) | |
258 | 258 | closelock(fd, data->path, conf.lock_types); |
259 | 259 | return (-1); |
260 | 260 | } |
420 | 420 | return (FETCH_BLOCK); |
421 | 421 | |
422 | 422 | if (data->user == NULL || data->pass == NULL) { |
423 | fctx->state = fetch_nntp_state_group; | |
423 | fctx->state = fetch_nntp_state_group; | |
424 | 424 | return (FETCH_AGAIN); |
425 | 425 | } |
426 | 426 |
32 | 32 | |
33 | 33 | /* Fetch context. */ |
34 | 34 | struct fetch_ctx { |
35 | int (*state)(struct account *, struct fetch_ctx *); | |
35 | int (*state)(struct account *, struct fetch_ctx *); | |
36 | 36 | int flags; |
37 | 37 | |
38 | 38 | struct mail *mail; |
90 | 90 | }; |
91 | 91 | |
92 | 92 | struct fetch_mbox_mbox { |
93 | char *path; | |
93 | char *path; | |
94 | 94 | u_int reference; |
95 | 95 | u_int total; |
96 | 96 | |
100 | 100 | }; |
101 | 101 | |
102 | 102 | struct fetch_mbox_mail { |
103 | size_t off; | |
103 | size_t off; | |
104 | 104 | size_t size; |
105 | 105 | |
106 | 106 | struct fetch_mbox_mbox *fmbox; |
248 | 248 | #define IMAP_CAPA_XYZZY 0x2 |
249 | 249 | |
250 | 250 | /* fetch-maildir.c */ |
251 | extern struct fetch fetch_maildir; | |
251 | extern struct fetch fetch_maildir; | |
252 | 252 | |
253 | 253 | /* fetch-mbx.c */ |
254 | extern struct fetch fetch_mbox; | |
254 | extern struct fetch fetch_mbox; | |
255 | 255 | |
256 | 256 | /* fetch-stdin.c */ |
257 | extern struct fetch fetch_stdin; | |
257 | extern struct fetch fetch_stdin; | |
258 | 258 | |
259 | 259 | /* fetch-nntp.c */ |
260 | extern struct fetch fetch_nntp; | |
260 | extern struct fetch fetch_nntp; | |
261 | 261 | |
262 | 262 | /* fetch-pop3.c */ |
263 | extern struct fetch fetch_pop3; | |
263 | extern struct fetch fetch_pop3; | |
264 | 264 | |
265 | 265 | /* fetch-pop3pipe.c */ |
266 | extern struct fetch fetch_pop3pipe; | |
266 | extern struct fetch fetch_pop3pipe; | |
267 | 267 | |
268 | 268 | /* fetch-imap.c */ |
269 | extern struct fetch fetch_imap; | |
269 | extern struct fetch fetch_imap; | |
270 | 270 | int fetch_imap_putln(struct account *, const char *, va_list); |
271 | 271 | int fetch_imap_getln(struct account *, struct fetch_ctx *, char **); |
272 | 272 | int fetch_imap_state_init(struct account *, struct fetch_ctx *); |
273 | 273 | |
274 | 274 | /* fetch-imappipe.c */ |
275 | extern struct fetch fetch_imappipe; | |
275 | extern struct fetch fetch_imappipe; | |
276 | 276 | |
277 | 277 | /* imap-common.c */ |
278 | 278 | int imap_tag(char *); |
243 | 243 | xmkpath(const char *path, uid_t uid, gid_t gid, mode_t mode) |
244 | 244 | { |
245 | 245 | struct stat sb; |
246 | char *copy, *ptr, ch; | |
246 | char *copy, *ptr, ch; | |
247 | 247 | |
248 | 248 | copy = ptr = xstrdup(path); |
249 | do { | |
250 | ptr += strspn(ptr, "/"); | |
251 | ptr += strcspn(ptr, "/"); | |
249 | do { | |
250 | ptr += strspn(ptr, "/"); | |
251 | ptr += strcspn(ptr, "/"); | |
252 | 252 | ch = *ptr; |
253 | 253 | |
254 | 254 | *ptr = '\0'; |
255 | if (stat(copy, &sb) != 0) { | |
256 | if (errno == ENOENT && | |
255 | if (stat(copy, &sb) != 0) { | |
256 | if (errno == ENOENT && | |
257 | 257 | xmkdir(copy, uid, gid, mode) != 0 && |
258 | 258 | errno != EEXIST) |
259 | 259 | return (-1); |
260 | } else if (!S_ISDIR(sb.st_mode)) { | |
260 | } else if (!S_ISDIR(sb.st_mode)) { | |
261 | 261 | errno = ENOTDIR; |
262 | return (-1); | |
263 | } | |
262 | return (-1); | |
263 | } | |
264 | 264 | *ptr = ch; |
265 | 265 | } while (ch != '\0'); |
266 | 266 | xfree(copy); |
83 | 83 | imap_getln(struct account *a, struct fetch_ctx *fctx, int type, char **line) |
84 | 84 | { |
85 | 85 | struct fetch_imap_data *data = a->data; |
86 | int n; | |
86 | int n; | |
87 | 87 | |
88 | 88 | do { |
89 | 89 | if (data->getln(a, fctx, line) != 0) |
175 | 175 | int |
176 | 176 | imap_tag(char *line) |
177 | 177 | { |
178 | int tag; | |
178 | int tag; | |
179 | 179 | const char *errstr; |
180 | 180 | char *ptr; |
181 | 181 | |
288 | 288 | { |
289 | 289 | struct fetch_imap_data *data = a->data; |
290 | 290 | |
291 | ARRAY_INIT(&data->dropped); | |
292 | ARRAY_INIT(&data->kept); | |
291 | ARRAY_INIT(&data->dropped); | |
292 | ARRAY_INIT(&data->kept); | |
293 | 293 | ARRAY_INIT(&data->wanted); |
294 | 294 | |
295 | 295 | data->tag = 0; |
564 | 564 | struct fetch_imap_data *data = a->data; |
565 | 565 | char *line; |
566 | 566 | |
567 | if (imap_getln(a, fctx, IMAP_TAGGED, &line) != 0) | |
568 | return (FETCH_ERROR); | |
569 | if (line == NULL) | |
570 | return (FETCH_BLOCK); | |
571 | if (!imap_okay(line)) | |
572 | return (imap_bad(a, line)); | |
567 | if (imap_getln(a, fctx, IMAP_TAGGED, &line) != 0) | |
568 | return (FETCH_ERROR); | |
569 | if (line == NULL) | |
570 | return (FETCH_BLOCK); | |
571 | if (!imap_okay(line)) | |
572 | return (imap_bad(a, line)); | |
573 | 573 | |
574 | 574 | /* If no mails, stop early. */ |
575 | 575 | if (data->total == 0) { |
580 | 580 | } |
581 | 581 | |
582 | 582 | fctx->state = imap_state_search1; |
583 | return (FETCH_AGAIN); | |
583 | return (FETCH_AGAIN); | |
584 | 584 | } |
585 | 585 | |
586 | 586 | /* Search state 1. Request list of mail required. */ |
130 | 130 | io_polln(struct io **iop, u_int n, struct io **rio, int timeout, char **cause) |
131 | 131 | { |
132 | 132 | struct io *io; |
133 | struct pollfd *pfds; | |
133 | struct pollfd *pfds; | |
134 | 134 | int error; |
135 | 135 | u_int i; |
136 | 136 | |
177 | 177 | /* Check all the ios. */ |
178 | 178 | for (i = 0; i < n; i++) { |
179 | 179 | io = iop[i]; |
180 | if (rio != NULL) | |
180 | if (rio != NULL) | |
181 | 181 | *rio = io; |
182 | 182 | if (io_after_poll(io, &pfds[i]) == -1) |
183 | 183 | goto error; |
365 | 365 | if (io->dup_fd != -1) { |
366 | 366 | write(io->dup_fd, "< ", 2); |
367 | 367 | write(io->dup_fd, BUFFER_IN(io->rd), n); |
368 | } | |
368 | } | |
369 | 369 | |
370 | 370 | /* Adjust the buffer size. */ |
371 | 371 | buffer_add(io->rd, n); |
457 | 457 | { |
458 | 458 | void *buf; |
459 | 459 | |
460 | IO_DEBUG(io, "in: %zu bytes, rd: used=%zu, free=%zu", len, | |
460 | IO_DEBUG(io, "in: %zu bytes, rd: used=%zu, free=%zu", len, | |
461 | 461 | BUFFER_USED(io->rd), BUFFER_FREE(io->rd)); |
462 | 462 | |
463 | 463 | if (io->error != NULL) |
469 | 469 | buf = xmalloc(len); |
470 | 470 | buffer_read(io->rd, buf, len); |
471 | 471 | |
472 | IO_DEBUG(io, "out: %zu bytes, rd: used=%zu, free=%zu", len, | |
472 | IO_DEBUG(io, "out: %zu bytes, rd: used=%zu, free=%zu", len, | |
473 | 473 | BUFFER_USED(io->rd), BUFFER_FREE(io->rd)); |
474 | 474 | |
475 | 475 | return (buf); |
482 | 482 | if (io->error != NULL) |
483 | 483 | return (-1); |
484 | 484 | |
485 | IO_DEBUG(io, "in: %zu bytes, rd: used=%zu, free=%zu", len, | |
485 | IO_DEBUG(io, "in: %zu bytes, rd: used=%zu, free=%zu", len, | |
486 | 486 | BUFFER_USED(io->rd), BUFFER_FREE(io->rd)); |
487 | 487 | |
488 | 488 | if (BUFFER_USED(io->rd) < len) |
490 | 490 | |
491 | 491 | buffer_read(io->rd, buf, len); |
492 | 492 | |
493 | IO_DEBUG(io, "out: %zu bytes, rd: used=%zu, free=%zu", len, | |
493 | IO_DEBUG(io, "out: %zu bytes, rd: used=%zu, free=%zu", len, | |
494 | 494 | BUFFER_USED(io->rd), BUFFER_FREE(io->rd)); |
495 | 495 | |
496 | 496 | return (0); |
503 | 503 | if (io->error != NULL) |
504 | 504 | return; |
505 | 505 | |
506 | IO_DEBUG(io, "in: %zu bytes, wr: used=%zu, free=%zu", len, | |
506 | IO_DEBUG(io, "in: %zu bytes, wr: used=%zu, free=%zu", len, | |
507 | 507 | BUFFER_USED(io->wr), BUFFER_FREE(io->wr)); |
508 | 508 | |
509 | 509 | buffer_write(io->wr, buf, len); |
510 | 510 | |
511 | IO_DEBUG(io, "out: %zu bytes, wr: used=%zu, free=%zu", len, | |
511 | IO_DEBUG(io, "out: %zu bytes, wr: used=%zu, free=%zu", len, | |
512 | 512 | BUFFER_USED(io->wr), BUFFER_FREE(io->wr)); |
513 | 513 | } |
514 | 514 | |
532 | 532 | if (BUFFER_USED(io->rd) < eollen) |
533 | 533 | return (NULL); |
534 | 534 | |
535 | IO_DEBUG(io, "in: rd: used=%zu, free=%zu", | |
535 | IO_DEBUG(io, "in: rd: used=%zu, free=%zu", | |
536 | 536 | BUFFER_USED(io->rd), BUFFER_FREE(io->rd)); |
537 | 537 | |
538 | 538 | base = ptr = BUFFER_OUT(io->rd); |
597 | 597 | /* Discard the EOL from the buffer. */ |
598 | 598 | buffer_remove(io->rd, eollen); |
599 | 599 | |
600 | IO_DEBUG(io, "out: %zu bytes, rd: used=%zu, free=%zu", | |
600 | IO_DEBUG(io, "out: %zu bytes, rd: used=%zu, free=%zu", | |
601 | 601 | size, BUFFER_USED(io->rd), BUFFER_FREE(io->rd)); |
602 | 602 | |
603 | 603 | return (*buf); |
646 | 646 | if (io->error != NULL) |
647 | 647 | return; |
648 | 648 | |
649 | IO_DEBUG(io, "in: wr: used=%zu, free=%zu", | |
649 | IO_DEBUG(io, "in: wr: used=%zu, free=%zu", | |
650 | 650 | BUFFER_USED(io->wr), BUFFER_FREE(io->wr)); |
651 | 651 | |
652 | 652 | if (fmt != NULL) { |
655 | 655 | va_end(aq); |
656 | 656 | |
657 | 657 | buffer_ensure(io->wr, n + 1); |
658 | xvsnprintf(BUFFER_IN(io->wr), n + 1, fmt, ap); | |
658 | xvsnprintf(BUFFER_IN(io->wr), n + 1, fmt, ap); | |
659 | 659 | buffer_add(io->wr, n); |
660 | 660 | } else |
661 | 661 | n = 0; |
662 | 662 | io_write(io, io->eol, strlen(io->eol)); |
663 | 663 | |
664 | IO_DEBUG(io, "out: %zu bytes, wr: used=%zu, free=%zu", | |
664 | IO_DEBUG(io, "out: %zu bytes, wr: used=%zu, free=%zu", | |
665 | 665 | n + strlen(io->eol), BUFFER_USED(io->wr), BUFFER_FREE(io->wr)); |
666 | 666 | } |
667 | 667 |
38 | 38 | |
39 | 39 | /* IO line endings. */ |
40 | 40 | #define IO_CRLF "\r\n" |
41 | #define IO_CR "\r" | |
42 | #define IO_LF "\n" | |
41 | #define IO_CR "\r" | |
42 | #define IO_LF "\n" | |
43 | 43 | |
44 | 44 | /* Initial block size of buffer and minimum amount to try to read. */ |
45 | 45 | #define IO_BLOCKSIZE 16384 |
85 | 85 | ARRAY_DECL(iolist, struct io *); |
86 | 86 | |
87 | 87 | /* buffer.c */ |
88 | struct buffer *buffer_create(size_t); | |
88 | struct buffer *buffer_create(size_t); | |
89 | 89 | void buffer_destroy(struct buffer *); |
90 | 90 | void buffer_clear(struct buffer *); |
91 | 91 | void buffer_ensure(struct buffer *, size_t); |
97 | 97 | void buffer_delete_range(struct buffer *, size_t, size_t); |
98 | 98 | void buffer_write(struct buffer *, const void *, size_t); |
99 | 99 | void buffer_read(struct buffer *, void *, size_t); |
100 | void buffer_write8(struct buffer *, uint8_t); | |
101 | void buffer_write16(struct buffer *, uint16_t); | |
100 | void buffer_write8(struct buffer *, uint8_t); | |
101 | void buffer_write16(struct buffer *, uint16_t); | |
102 | 102 | uint8_t buffer_read8(struct buffer *); |
103 | uint16_t buffer_read16(struct buffer *); | |
103 | uint16_t buffer_read16(struct buffer *); | |
104 | 104 | |
105 | 105 | /* io.c */ |
106 | 106 | struct io *io_create(int, SSL *, const char *); |
111 | 111 | int io_polln(struct io **, u_int, struct io **, int, char **); |
112 | 112 | int io_poll(struct io *, int, char **); |
113 | 113 | int io_read2(struct io *, void *, size_t); |
114 | void *io_read(struct io *, size_t); | |
114 | void *io_read(struct io *, size_t); | |
115 | 115 | void io_write(struct io *, const void *, size_t); |
116 | char *io_readline2(struct io *, char **, size_t *); | |
117 | char *io_readline(struct io *); | |
116 | char *io_readline2(struct io *, char **, size_t *); | |
117 | char *io_readline(struct io *); | |
118 | 118 | void printflike2 io_writeline(struct io *, const char *, ...); |
119 | 119 | void io_vwriteline(struct io *, const char *, va_list); |
120 | 120 | int io_pollline2(struct io *, char **, char **, size_t *, int, |
203 | 203 | int |
204 | 204 | yylex(void) |
205 | 205 | { |
206 | int ch, value; | |
206 | int ch, value; | |
207 | 207 | char *path; |
208 | struct replpath rp; | |
208 | struct replpath rp; | |
209 | 209 | |
210 | 210 | /* Switch to new file. See comment in read_token below. */ |
211 | 211 | if (lex_include) { |
335 | 335 | { |
336 | 336 | const struct token *token = ptr; |
337 | 337 | |
338 | return (strcmp(name, token->name)); | |
338 | return (strcmp(name, token->name)); | |
339 | 339 | } |
340 | 340 | |
341 | 341 | int |
406 | 406 | * can). If we don't do this, there are problems with things |
407 | 407 | * like: |
408 | 408 | * |
409 | * $file = "abc" | |
410 | * include "${file}" | |
409 | * $file = "abc" | |
410 | * include "${file}" | |
411 | 411 | * |
412 | 412 | * The include token is seen before yacc has matched the |
413 | 413 | * previous line, so the macro doesn't exist when we try to |
419 | 419 | |
420 | 420 | ptr = bsearch(token, tokens, |
421 | 421 | (sizeof tokens)/(sizeof tokens[0]), sizeof tokens[0], cmp_token); |
422 | if (ptr == NULL) | |
422 | if (ptr == NULL) | |
423 | 423 | yyerror("unknown token: %s", token); |
424 | 424 | return (ptr->value); |
425 | 425 | } |
429 | 429 | { |
430 | 430 | char number[32]; |
431 | 431 | size_t nlen; |
432 | const char *errstr; | |
432 | const char *errstr; | |
433 | 433 | long long n; |
434 | 434 | |
435 | 435 | nlen = 0; |
475 | 475 | if (nlen == (sizeof name) - 1) |
476 | 476 | yyerror("macro name too long"); |
477 | 477 | } |
478 | name[nlen] = '\0'; | |
478 | name[nlen] = '\0'; | |
479 | 479 | if (!brackets) |
480 | 480 | lex_ungetc(ch); |
481 | 481 | |
495 | 495 | char *buf, *s; |
496 | 496 | |
497 | 497 | len = 24; |
498 | buf = xmalloc(len + 1); | |
498 | buf = xmalloc(len + 1); | |
499 | 499 | |
500 | 500 | nesting = 0; |
501 | while ((ch = lex_getc()) != EOF) { | |
501 | while ((ch = lex_getc()) != EOF) { | |
502 | 502 | switch (ch) { |
503 | 503 | case '(': |
504 | 504 | nesting++; |
530 | 530 | buf[pos++] = '\''; |
531 | 531 | xfree(s); |
532 | 532 | continue; |
533 | } | |
534 | ||
535 | buf[pos++] = ch; | |
536 | ENSURE_SIZE(buf, len, pos); | |
537 | } | |
533 | } | |
534 | ||
535 | buf[pos++] = ch; | |
536 | ENSURE_SIZE(buf, len, pos); | |
537 | } | |
538 | 538 | |
539 | 539 | yyerror("missing )"); |
540 | 540 | } |
544 | 544 | { |
545 | 545 | int ch, oldch; |
546 | 546 | size_t pos, len, slen; |
547 | char *name, *s, *buf; | |
547 | char *name, *s, *buf; | |
548 | 548 | struct macro *macro; |
549 | 549 | |
550 | 550 | len = 24; |
551 | buf = xmalloc(len + 1); | |
551 | buf = xmalloc(len + 1); | |
552 | 552 | |
553 | 553 | pos = 0; |
554 | while ((ch = lex_getc()) != endch) { | |
555 | switch (ch) { | |
554 | while ((ch = lex_getc()) != endch) { | |
555 | switch (ch) { | |
556 | 556 | case EOF: |
557 | 557 | yyerror("missing %c", endch); |
558 | case '\\': | |
558 | case '\\': | |
559 | 559 | if (!esc) |
560 | 560 | break; |
561 | switch (ch = lex_getc()) { | |
561 | switch (ch = lex_getc()) { | |
562 | 562 | case EOF: |
563 | 563 | yyerror("missing %c", endch); |
564 | case 'r': | |
565 | ch = '\r'; | |
566 | break; | |
567 | case 'n': | |
568 | ch = '\n'; | |
569 | break; | |
570 | case 't': | |
571 | ch = '\t'; | |
572 | break; | |
573 | } | |
574 | break; | |
564 | case 'r': | |
565 | ch = '\r'; | |
566 | break; | |
567 | case 'n': | |
568 | ch = '\n'; | |
569 | break; | |
570 | case 't': | |
571 | ch = '\t'; | |
572 | break; | |
573 | } | |
574 | break; | |
575 | 575 | case '$': |
576 | 576 | case '%': |
577 | 577 | if (!esc) |
595 | 595 | xfree(name); |
596 | 596 | |
597 | 597 | if (macro->type == MACRO_NUMBER) |
598 | xasprintf(&s, "%lld", macro->value.num); | |
598 | xasprintf(&s, "%lld", macro->value.num); | |
599 | 599 | else |
600 | 600 | s = macro->value.str; |
601 | 601 | slen = strlen(s); |
607 | 607 | if (macro->type == MACRO_NUMBER) |
608 | 608 | xfree(s); |
609 | 609 | continue; |
610 | } | |
611 | ||
612 | buf[pos++] = ch; | |
613 | ENSURE_SIZE(buf, len, pos); | |
614 | } | |
615 | ||
616 | buf[pos] = '\0'; | |
610 | } | |
611 | ||
612 | buf[pos++] = ch; | |
613 | ENSURE_SIZE(buf, len, pos); | |
614 | } | |
615 | ||
616 | buf[pos] = '\0'; | |
617 | 617 | |
618 | 618 | return (buf); |
619 | 619 | } |
218 | 218 | log_vwrite(LOG_CRIT, fmt, ap); |
219 | 219 | } else { |
220 | 220 | if (asprintf(&fmt, "fatal: %s", msg) == -1) |
221 | exit(1); | |
221 | exit(1); | |
222 | 222 | log_vwrite(LOG_CRIT, fmt, ap); |
223 | 223 | } |
224 | 224 | free(fmt); |
33 | 33 | int fill_from_string(struct mail_ctx *, struct rule *, |
34 | 34 | struct replstr *); |
35 | 35 | int fill_from_action(struct mail_ctx *, struct rule *, |
36 | struct action *, struct replstrs *); | |
36 | struct action *, struct replstrs *); | |
37 | 37 | |
38 | 38 | int start_action(struct mail_ctx *, struct deliver_ctx *); |
39 | 39 | int finish_action(struct deliver_ctx *, struct msg *, |
46 | 46 | /* |
47 | 47 | * Number of chained actions. Limit on recursion with things like: |
48 | 48 | * |
49 | * action "name" { action "name" } | |
49 | * action "name" { action "name" } | |
50 | 50 | */ |
51 | 51 | u_int chained; |
52 | 52 | |
415 | 415 | struct deliver_action_data *data; |
416 | 416 | struct actitem *ti; |
417 | 417 | struct deliver_ctx *dctx; |
418 | u_int i; | |
418 | u_int i; | |
419 | 419 | char *user; |
420 | 420 | struct userdata *udata; |
421 | 421 | |
471 | 471 | { |
472 | 472 | struct account *a = dctx->account; |
473 | 473 | struct action *t = dctx->action; |
474 | struct actitem *ti = dctx->actitem; | |
474 | struct actitem *ti = dctx->actitem; | |
475 | 475 | struct mail *m = dctx->mail; |
476 | 476 | struct msg msg; |
477 | 477 | struct msgbuf msgbuf; |
525 | 525 | finish_action(struct deliver_ctx *dctx, struct msg *msg, struct msgbuf *msgbuf) |
526 | 526 | { |
527 | 527 | struct account *a = dctx->account; |
528 | struct actitem *ti = dctx->actitem; | |
528 | struct actitem *ti = dctx->actitem; | |
529 | 529 | struct mail *m = dctx->mail; |
530 | 530 | u_int lines; |
531 | 531 |
39 | 39 | |
40 | 40 | if ((m->base = shm_create(&m->shm, m->space)) == NULL) |
41 | 41 | return (-1); |
42 | SHM_REGISTER(&m->shm); | |
42 | SHM_REGISTER(&m->shm); | |
43 | 43 | |
44 | 44 | m->off = 0; |
45 | 45 | m->data = m->base + m->off; |
89 | 89 | memcpy(m, mm, sizeof *m); |
90 | 90 | if ((m->base = shm_reopen(&m->shm)) == NULL) |
91 | 91 | return (-1); |
92 | SHM_REGISTER(&m->shm); | |
92 | SHM_REGISTER(&m->shm); | |
93 | 93 | |
94 | 94 | m->data = m->base + m->off; |
95 | 95 | ARRAY_INIT(&m->wrapped); |
451 | 451 | |
452 | 452 | /* |
453 | 453 | * Now, look for sections matching: |
454 | * [< ][A-Za-z0-9._%+-]+@[A-Za-z0-9.\[\]-]+[> ,;]. | |
454 | * [< ][A-Za-z0-9._%+-]+@[A-Za-z0-9.\[\]-]+[> ,;]. | |
455 | 455 | */ |
456 | 456 | #define isfirst(c) ((c) == '<' || (c) == ' ') |
457 | 457 | #define islast(c) ((c) == '>' || (c) == ' ' || (c) == ',' || (c) == ';') |
537 | 537 | from = find_header(m, "from", &fromlen, 1); |
538 | 538 | if (from != NULL && fromlen > 0) |
539 | 539 | from = find_address(from, fromlen, &fromlen); |
540 | if (fromlen > INT_MAX) | |
540 | if (fromlen > INT_MAX) | |
541 | 541 | from = NULL; |
542 | 542 | if (from == NULL) { |
543 | 543 | from = user; |
559 | 559 | fill_wrapped(struct mail *m) |
560 | 560 | { |
561 | 561 | char *ptr; |
562 | size_t end, off; | |
562 | size_t end, off; | |
563 | 563 | u_int n; |
564 | 564 | |
565 | 565 | if (!ARRAY_EMPTY(&m->wrapped)) |
161 | 161 | match_attachment_desc(struct expritem *ei, char *buf, size_t len) |
162 | 162 | { |
163 | 163 | struct match_attachment_data *data = ei->data; |
164 | const char *cmp = ""; | |
164 | const char *cmp = ""; | |
165 | 165 | |
166 | 166 | if (data->cmp == CMP_LT) |
167 | 167 | cmp = "<"; |
38 | 38 | struct account *a = mctx->account; |
39 | 39 | struct mail *m = mctx->mail; |
40 | 40 | int res; |
41 | char *cause; | |
41 | char *cause; | |
42 | 42 | size_t so, eo; |
43 | 43 | |
44 | 44 | so = 0; |
31 | 31 | const char *name; |
32 | 32 | |
33 | 33 | int (*match)(struct mail_ctx *, struct expritem *); |
34 | void (*desc)(struct expritem *, char *, size_t); | |
34 | void (*desc)(struct expritem *, char *, size_t); | |
35 | 35 | }; |
36 | 36 | |
37 | 37 | /* Match attachment data. */ |
44 | 44 | ATTACHOP_ANYNAME |
45 | 45 | } op; |
46 | 46 | |
47 | enum cmp cmp; | |
47 | enum cmp cmp; | |
48 | 48 | union { |
49 | 49 | size_t size; |
50 | 50 | long long num; |
78 | 78 | /* Match string data. */ |
79 | 79 | struct match_string_data { |
80 | 80 | struct replstr str; |
81 | struct re re; | |
81 | struct re re; | |
82 | 82 | }; |
83 | 83 | |
84 | 84 | /* Match regexp data. */ |
85 | 85 | struct match_regexp_data { |
86 | 86 | struct re re; |
87 | 87 | |
88 | enum area area; | |
88 | enum area area; | |
89 | 89 | }; |
90 | 90 | |
91 | 91 | /* Match command data. */ |
153 | 153 | { |
154 | 154 | static char token[BUFSIZ]; |
155 | 155 | char *cp; |
156 | int c; | |
156 | int c; | |
157 | 157 | |
158 | 158 | if (feof(f) || ferror(f)) |
159 | 159 | return (1); |
30 | 30 | |
31 | 31 | void parent_fetch_error(struct child *, struct msg *); |
32 | 32 | void parent_fetch_action(struct child *, struct children *, |
33 | struct deliver_ctx *, struct msg *); | |
33 | struct deliver_ctx *, struct msg *); | |
34 | 34 | void parent_fetch_cmd(struct child *, struct children *, struct mail_ctx *, |
35 | 35 | struct msg *); |
36 | 36 | |
104 | 104 | struct mail *m = dctx->mail; |
105 | 105 | struct mail *md = &dctx->wr_mail; |
106 | 106 | struct child_deliver_data *data; |
107 | uid_t uid = msg->data.uid; | |
107 | uid_t uid = msg->data.uid; | |
108 | 108 | gid_t gid = msg->data.gid; |
109 | 109 | |
110 | 110 | memset(md, 0, sizeof *md); |
151 | 151 | { |
152 | 152 | struct mail *m = mctx->mail; |
153 | 153 | struct child_deliver_data *data; |
154 | uid_t uid = msg->data.uid; | |
154 | uid_t uid = msg->data.uid; | |
155 | 155 | gid_t gid = msg->data.gid; |
156 | 156 | |
157 | 157 | data = xmalloc(sizeof *data); |
253 | 253 | struct actitem *ti; |
254 | 254 | struct deliver_action_data *data; |
255 | 255 | char desc[DESCBUFSIZE], *s; |
256 | size_t off; | |
256 | size_t off; | |
257 | 257 | |
258 | 258 | off = 0; |
259 | 259 | TAILQ_FOREACH(ti, tl, entry) { |
451 | 451 | |
452 | 452 | if (a->fetch == &fetch_pop3) { |
453 | 453 | struct fetch_pop3_data *data = a->data; |
454 | if (data->path != NULL) | |
454 | if (data->path != NULL) | |
455 | 455 | xfree(data->path); |
456 | 456 | xfree(data->user); |
457 | 457 | xfree(data->pass); |
461 | 461 | freeaddrinfo(data->server.ai); |
462 | 462 | } else if (a->fetch == &fetch_pop3pipe) { |
463 | 463 | struct fetch_pop3_data *data = a->data; |
464 | if (data->path != NULL) | |
464 | if (data->path != NULL) | |
465 | 465 | xfree(data->path); |
466 | 466 | xfree(data->user); |
467 | 467 | xfree(data->pass); |
471 | 471 | xfree(data->user); |
472 | 472 | xfree(data->pass); |
473 | 473 | free_strings(data->folders); |
474 | ARRAY_FREEALL(data->folders); | |
474 | ARRAY_FREEALL(data->folders); | |
475 | 475 | xfree(data->server.host); |
476 | 476 | xfree(data->server.port); |
477 | 477 | if (data->server.ai != NULL) |
483 | 483 | if (data->pass != NULL) |
484 | 484 | xfree(data->pass); |
485 | 485 | free_strings(data->folders); |
486 | ARRAY_FREEALL(data->folders); | |
486 | ARRAY_FREEALL(data->folders); | |
487 | 487 | xfree(data->pipecmd); |
488 | 488 | } else if (a->fetch == &fetch_maildir) { |
489 | 489 | struct fetch_maildir_data *data = a->data; |
217 | 217 | error: |
218 | 218 | if (f != NULL) |
219 | 219 | fclose(f); |
220 | if (fd != -1) | |
220 | if (fd != -1) | |
221 | 221 | closelock(fd, data->path, conf.lock_types); |
222 | 222 | return (-1); |
223 | 223 | } |
881 | 881 | { |
882 | 882 | struct fetch_pop3_data *data = a->data; |
883 | 883 | struct mail *m = fctx->mail; |
884 | struct fetch_pop3_mail *aux = m->auxdata; | |
884 | struct fetch_pop3_mail *aux = m->auxdata; | |
885 | 885 | char *line; |
886 | 886 | |
887 | 887 | if (pop3_getln(a, fctx, &line) != 0) |
24 | 24 | |
25 | 25 | #include "fdm.h" |
26 | 26 | |
27 | #define ALIAS_IDX(ch) /* LINTED */ \ | |
28 | (((ch) >= 'a' && (ch) <= 'z') ? (ch) - 'a' : \ | |
27 | #define ALIAS_IDX(ch) /* LINTED */ \ | |
28 | (((ch) >= 'a' && (ch) <= 'z') ? (ch) - 'a' : \ | |
29 | 29 | (((ch) >= 'A' && (ch) <= 'Z') ? 26 + (ch) - 'A' : -1)) |
30 | 30 | |
31 | 31 | static const char *aliases[] = { |
32 | "account", /* a */ | |
33 | NULL, /* b */ | |
34 | NULL, /* c */ | |
35 | "day", /* d */ | |
36 | NULL, /* e */ | |
37 | NULL, /* f */ | |
38 | NULL, /* g */ | |
39 | "home", /* h */ | |
40 | NULL, /* i */ | |
41 | NULL, /* j */ | |
42 | NULL, /* l */ | |
43 | NULL, /* l */ | |
44 | "month", /* m */ | |
45 | "uid", /* n */ | |
46 | NULL, /* o */ | |
47 | NULL, /* p */ | |
48 | NULL, /* q */ | |
49 | NULL, /* r */ | |
50 | "source", /* s */ | |
51 | "action", /* t */ | |
52 | "user", /* u */ | |
53 | NULL, /* v */ | |
54 | NULL, /* w */ | |
55 | NULL, /* x */ | |
56 | "year", /* y */ | |
57 | NULL, /* z */ | |
58 | ||
59 | NULL, /* A */ | |
60 | NULL, /* B */ | |
61 | NULL, /* C */ | |
62 | NULL, /* D */ | |
63 | NULL, /* E */ | |
64 | NULL, /* F */ | |
65 | NULL, /* G */ | |
66 | "hour", /* H */ | |
67 | NULL, /* I */ | |
68 | NULL, /* J */ | |
69 | NULL, /* K */ | |
70 | NULL, /* L */ | |
71 | "minute", /* M */ | |
72 | NULL, /* N */ | |
73 | NULL, /* O */ | |
74 | NULL, /* P */ | |
32 | "account", /* a */ | |
33 | NULL, /* b */ | |
34 | NULL, /* c */ | |
35 | "day", /* d */ | |
36 | NULL, /* e */ | |
37 | NULL, /* f */ | |
38 | NULL, /* g */ | |
39 | "home", /* h */ | |
40 | NULL, /* i */ | |
41 | NULL, /* j */ | |
42 | NULL, /* l */ | |
43 | NULL, /* l */ | |
44 | "month", /* m */ | |
45 | "uid", /* n */ | |
46 | NULL, /* o */ | |
47 | NULL, /* p */ | |
48 | NULL, /* q */ | |
49 | NULL, /* r */ | |
50 | "source", /* s */ | |
51 | "action", /* t */ | |
52 | "user", /* u */ | |
53 | NULL, /* v */ | |
54 | NULL, /* w */ | |
55 | NULL, /* x */ | |
56 | "year", /* y */ | |
57 | NULL, /* z */ | |
58 | ||
59 | NULL, /* A */ | |
60 | NULL, /* B */ | |
61 | NULL, /* C */ | |
62 | NULL, /* D */ | |
63 | NULL, /* E */ | |
64 | NULL, /* F */ | |
65 | NULL, /* G */ | |
66 | "hour", /* H */ | |
67 | NULL, /* I */ | |
68 | NULL, /* J */ | |
69 | NULL, /* K */ | |
70 | NULL, /* L */ | |
71 | "minute", /* M */ | |
72 | NULL, /* N */ | |
73 | NULL, /* O */ | |
74 | NULL, /* P */ | |
75 | 75 | "quarter", /* Q */ |
76 | NULL, /* R */ | |
76 | NULL, /* R */ | |
77 | 77 | "second", /* S */ |
78 | NULL, /* T */ | |
79 | NULL, /* U */ | |
80 | NULL, /* V */ | |
81 | "dayofweek", /* W */ | |
82 | NULL, /* X */ | |
83 | "dayofyear", /* Y */ | |
84 | NULL, /* Z */ | |
78 | NULL, /* T */ | |
79 | NULL, /* U */ | |
80 | NULL, /* V */ | |
81 | "dayofweek", /* W */ | |
82 | NULL, /* X */ | |
83 | "dayofyear", /* Y */ | |
84 | NULL, /* Z */ | |
85 | 85 | }; |
86 | 86 | |
87 | 87 | char *replace(char *, struct strb *, struct mail *, struct rmlist *); |
88 | const char *submatch(char, struct mail *, struct rmlist *, size_t *); | |
88 | const char *submatch(char, struct mail *, struct rmlist *, size_t *); | |
89 | 89 | |
90 | 90 | void printflike3 |
91 | 91 | add_tag(struct strb **tags, const char *key, const char *value, ...) |
195 | 195 | char *s, *t; |
196 | 196 | |
197 | 197 | s = replace(rp->str, tags, m, rml); |
198 | if ((t = expand_path(s, home)) == NULL) | |
198 | if ((t = expand_path(s, home)) == NULL) | |
199 | 199 | return (s); |
200 | 200 | xfree(s); |
201 | 201 | return (t); |
222 | 222 | { |
223 | 223 | const char *tptr, *alias; |
224 | 224 | char *ptr, *tend, *dst, ch; |
225 | size_t i, off, len, tlen; | |
225 | size_t i, off, len, tlen; | |
226 | 226 | int strip; |
227 | 227 | |
228 | 228 | if (src == NULL) |
103 | 103 | int saved_errno; |
104 | 104 | char *path; |
105 | 105 | |
106 | if (size == 0) | |
107 | fatalx("zero size"); | |
106 | if (size == 0) | |
107 | fatalx("zero size"); | |
108 | 108 | |
109 | 109 | if (ppath( |
110 | 110 | shm->name, sizeof shm->name, "%s.XXXXXXXXXX", __progname) != 0) |
203 | 203 | size_t newsize = nmemb * size; |
204 | 204 | |
205 | 205 | if (size == 0) |
206 | fatalx("zero size"); | |
207 | if (SIZE_MAX / nmemb < size) | |
208 | fatalx("nmemb * size > SIZE_MAX"); | |
206 | fatalx("zero size"); | |
207 | if (SIZE_MAX / nmemb < size) | |
208 | fatalx("nmemb * size > SIZE_MAX"); | |
209 | 209 | |
210 | 210 | #ifndef HAVE_MREMAP |
211 | 211 | if (munmap(shm->data, shm->size) != 0) |
169 | 169 | strb_match(struct strb *sb, const char *patt) |
170 | 170 | { |
171 | 171 | static struct strbent sbe; |
172 | u_int i; | |
172 | u_int i; | |
173 | 173 | |
174 | 174 | for (i = 0; i < sb->ent_used; i++) { |
175 | 175 | memcpy(&sbe, STRB_ENTRY(sb, i), sizeof sbe); |
85 | 85 | void |
86 | 86 | xmalloc_clear(void) |
87 | 87 | { |
88 | struct xmalloc_blk *blk; | |
88 | struct xmalloc_blk *blk; | |
89 | 89 | |
90 | 90 | xmalloc_allocated = 0; |
91 | 91 | xmalloc_freed = 0; |
105 | 105 | void |
106 | 106 | xmalloc_report(pid_t pid, const char *hdr) |
107 | 107 | { |
108 | struct xmalloc_blk *blk; | |
108 | struct xmalloc_blk *blk; | |
109 | 109 | u_char *iptr; |
110 | char buf[4 * XMALLOC_BYTES + 1], *optr; | |
111 | size_t len; | |
112 | u_int n; | |
110 | char buf[4 * XMALLOC_BYTES + 1], *optr; | |
111 | size_t len; | |
112 | u_int n; | |
113 | 113 | Dl_info info; |
114 | 114 | |
115 | XMALLOC_PRINT("%s: %ld: allocated=%zu, freed=%zu, difference=%zd, " | |
115 | XMALLOC_PRINT("%s: %ld: allocated=%zu, freed=%zu, difference=%zd, " | |
116 | 116 | "peak=%zu", hdr, (long) pid, xmalloc_allocated, xmalloc_freed, |
117 | 117 | xmalloc_allocated - xmalloc_freed, xmalloc_peak); |
118 | XMALLOC_PRINT("%s: %ld: mallocs=%u, reallocs=%u, frees=%u", hdr, | |
118 | XMALLOC_PRINT("%s: %ld: mallocs=%u, reallocs=%u, frees=%u", hdr, | |
119 | 119 | (long) pid, xmalloc_mallocs, xmalloc_reallocs, xmalloc_frees); |
120 | 120 | |
121 | 121 | n = 0; |
203 | 203 | |
204 | 204 | SPLAY_REMOVE(xmalloc_tree, &xmalloc_tree, blk); |
205 | 205 | |
206 | blk->ptr = newptr; | |
206 | blk->ptr = newptr; | |
207 | 207 | blk->size = newsize; |
208 | 208 | |
209 | 209 | blk->caller = caller; |
77 | 77 | len = strlen(s) + 1; |
78 | 78 | ptr = xmalloc(len); |
79 | 79 | |
80 | return (strncpy(ptr, s, len)); | |
80 | return (strncpy(ptr, s, len)); | |
81 | 81 | } |
82 | 82 | |
83 | 83 | void * |
84 | 84 | xcalloc(size_t nmemb, size_t size) |
85 | 85 | { |
86 | void *ptr; | |
87 | ||
88 | if (size == 0 || nmemb == 0) | |
89 | fatalx("zero size"); | |
90 | if (SIZE_MAX / nmemb < size) | |
91 | fatalx("nmemb * size > SIZE_MAX"); | |
92 | if ((ptr = calloc(nmemb, size)) == NULL) | |
86 | void *ptr; | |
87 | ||
88 | if (size == 0 || nmemb == 0) | |
89 | fatalx("zero size"); | |
90 | if (SIZE_MAX / nmemb < size) | |
91 | fatalx("nmemb * size > SIZE_MAX"); | |
92 | if ((ptr = calloc(nmemb, size)) == NULL) | |
93 | 93 | fatal("xcalloc failed"); |
94 | 94 | |
95 | 95 | #ifdef DEBUG |
96 | 96 | xmalloc_new(xmalloc_caller(), ptr, nmemb * size); |
97 | 97 | #endif |
98 | return (ptr); | |
98 | return (ptr); | |
99 | 99 | } |
100 | 100 | |
101 | 101 | void * |
103 | 103 | { |
104 | 104 | void *ptr; |
105 | 105 | |
106 | if (size == 0) | |
107 | fatalx("zero size"); | |
108 | if ((ptr = malloc(size)) == NULL) | |
106 | if (size == 0) | |
107 | fatalx("zero size"); | |
108 | if ((ptr = malloc(size)) == NULL) | |
109 | 109 | fatal("xmalloc failed"); |
110 | 110 | |
111 | 111 | #ifdef DEBUG |
112 | 112 | xmalloc_new(xmalloc_caller(), ptr, size); |
113 | 113 | #endif |
114 | return (ptr); | |
114 | return (ptr); | |
115 | 115 | } |
116 | 116 | |
117 | 117 | void * |
121 | 121 | void *newptr; |
122 | 122 | |
123 | 123 | if (newsize == 0) |
124 | fatalx("zero size"); | |
125 | if (SIZE_MAX / nmemb < size) | |
126 | fatalx("nmemb * size > SIZE_MAX"); | |
127 | if ((newptr = realloc(oldptr, newsize)) == NULL) | |
124 | fatalx("zero size"); | |
125 | if (SIZE_MAX / nmemb < size) | |
126 | fatalx("nmemb * size > SIZE_MAX"); | |
127 | if ((newptr = realloc(oldptr, newsize)) == NULL) | |
128 | 128 | fatal("xrealloc failed"); |
129 | 129 | |
130 | 130 | #ifdef DEBUG |
131 | 131 | xmalloc_change(xmalloc_caller(), oldptr, newptr, nmemb * size); |
132 | 132 | #endif |
133 | return (newptr); | |
133 | return (newptr); | |
134 | 134 | } |
135 | 135 | |
136 | 136 | void |
148 | 148 | int printflike2 |
149 | 149 | xasprintf(char **ret, const char *fmt, ...) |
150 | 150 | { |
151 | va_list ap; | |
152 | int i; | |
153 | ||
154 | va_start(ap, fmt); | |
155 | i = xvasprintf(ret, fmt, ap); | |
156 | va_end(ap); | |
151 | va_list ap; | |
152 | int i; | |
153 | ||
154 | va_start(ap, fmt); | |
155 | i = xvasprintf(ret, fmt, ap); | |
156 | va_end(ap); | |
157 | 157 | |
158 | 158 | return (i); |
159 | 159 | } |
164 | 164 | int i; |
165 | 165 | |
166 | 166 | i = vasprintf(ret, fmt, ap); |
167 | if (i < 0 || *ret == NULL) | |
168 | fatal("xvasprintf failed"); | |
167 | if (i < 0 || *ret == NULL) | |
168 | fatal("xvasprintf failed"); | |
169 | 169 | |
170 | 170 | #ifdef DEBUG |
171 | 171 | xmalloc_new(xmalloc_caller(), *ret, i + 1); |
172 | 172 | #endif |
173 | return (i); | |
173 | return (i); | |
174 | 174 | } |
175 | 175 | |
176 | 176 | int printflike3 |
177 | 177 | xsnprintf(char *buf, size_t len, const char *fmt, ...) |
178 | 178 | { |
179 | va_list ap; | |
180 | int i; | |
181 | ||
182 | va_start(ap, fmt); | |
183 | i = xvsnprintf(buf, len, fmt, ap); | |
184 | va_end(ap); | |
179 | va_list ap; | |
180 | int i; | |
181 | ||
182 | va_start(ap, fmt); | |
183 | i = xvsnprintf(buf, len, fmt, ap); | |
184 | va_end(ap); | |
185 | 185 | |
186 | 186 | return (i); |
187 | 187 | } |
195 | 195 | fatalx("len > INT_MAX"); |
196 | 196 | |
197 | 197 | i = vsnprintf(buf, len, fmt, ap); |
198 | if (i < 0) | |
199 | fatal("vsnprintf failed"); | |
200 | ||
201 | return (i); | |
198 | if (i < 0) | |
199 | fatal("vsnprintf failed"); | |
200 | ||
201 | return (i); | |
202 | 202 | } |
203 | 203 | |
204 | 204 | /* |