author | James Turner <james@calminferno.net> |
Wed, 09 Apr 2014 21:36:45 -0400 | |
changeset 11 | 12ebfb79038d |
parent 7 | bb148c4cfe52 |
child 18 | 1d773aa5e87e |
permissions | -rw-r--r-- |
0 | 1 |
/* |
2 |
* Copyright (c) 2014 Sunil Nimmagadda <sunil@nimmagadda.net> |
|
3 |
* |
|
4 |
* Permission to use, copy, modify, and distribute this software for any |
|
5 |
* purpose with or without fee is hereby granted, provided that the above |
|
6 |
* copyright notice and this permission notice appear in all copies. |
|
7 |
* |
|
8 |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|
9 |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|
10 |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|
11 |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
12 |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|
13 |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|
14 |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
15 |
*/ |
|
16 |
||
17 |
#include <sys/param.h> |
|
18 |
#include <sys/types.h> |
|
19 |
#include <sys/socket.h> |
|
20 |
#include <sys/stat.h> |
|
21 |
||
22 |
#include <event.h> |
|
23 |
#include <fcntl.h> |
|
24 |
#include <pwd.h> |
|
25 |
#include <signal.h> |
|
26 |
#include <stdio.h> |
|
27 |
#include <stdlib.h> |
|
28 |
#include <string.h> |
|
29 |
#include <syslog.h> |
|
30 |
#include <unistd.h> |
|
31 |
||
32 |
#include "imsgev.h" |
|
33 |
#include "pop3d.h" |
|
34 |
||
35 |
static void session_imsgev(struct imsgev *, int, struct imsg *); |
|
36 |
static void update(struct imsgev *, struct imsg *, struct m_backend *); |
|
37 |
static void retr(struct imsgev *, struct imsg *, struct m_backend *); |
|
38 |
static void dele(struct imsgev *, struct imsg *, struct m_backend *); |
|
39 |
static void rset(struct imsgev *, struct imsg *, struct m_backend *); |
|
40 |
static void list(struct imsgev *, struct imsg *, struct m_backend *); |
|
2
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
41 |
static void list_all(struct imsgev *, struct imsg *, struct m_backend *); |
0 | 42 |
static void do_list(unsigned int, size_t *, char *, size_t); |
43 |
static struct m_backend *m_backend_lookup(enum m_type); |
|
44 |
static void sig_handler(int, short, void *); |
|
45 |
static void needfd(struct imsgev *); |
|
46 |
static size_t expand(char *, const char *, size_t, struct passwd *); |
|
47 |
||
48 |
static struct mdrop m; |
|
49 |
||
4 | 50 |
pid_t |
0 | 51 |
maildrop_init(uint32_t session_id, int pair[2], struct passwd *pw, |
52 |
int type, const char *path) |
|
53 |
{ |
|
54 |
struct imsgev iev_session; |
|
55 |
struct event ev_sigint, ev_sigterm; |
|
56 |
struct stats stats; |
|
57 |
struct m_backend *mb; |
|
58 |
char buf[MAXPATHLEN]; |
|
59 |
pid_t pid; |
|
60 |
mode_t old_mask; |
|
61 |
int fd, flags, res = -1; |
|
62 |
||
4 | 63 |
if ((pid = fork()) != 0) |
64 |
return (pid); |
|
0 | 65 |
|
4 | 66 |
if (setgroups(1, &pw->pw_gid) || |
67 |
setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || |
|
68 |
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) |
|
69 |
fatal("cannot drop privileges"); |
|
0 | 70 |
|
71 |
close(pair[0]); |
|
72 |
setproctitle("maildrop"); |
|
73 |
if ((mb = m_backend_lookup(type)) == NULL) |
|
74 |
fatalx("maildrop: invalid backend"); |
|
75 |
||
76 |
if (expand(buf, path, sizeof(buf), pw) >= sizeof(buf)) |
|
77 |
fatalx("maildrop: path truncation"); |
|
78 |
||
79 |
flags = O_CREAT; |
|
80 |
if (type == M_MBOX) |
|
81 |
flags |= O_RDWR; |
|
82 |
else |
|
83 |
flags |= O_RDONLY; |
|
84 |
||
85 |
old_mask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); |
|
86 |
if ((fd = open(buf, flags)) == -1) |
|
87 |
logit(LOG_CRIT, "%zu: failed to open %s", session_id , buf); |
|
88 |
||
89 |
if (fd != -1) { |
|
90 |
m.fd = fd; |
|
91 |
res = mb->init(&m, &stats.nmsgs, &stats.sz); |
|
92 |
} |
|
93 |
||
94 |
umask(old_mask); |
|
95 |
event_init(); |
|
96 |
signal_set(&ev_sigint, SIGINT, sig_handler, NULL); |
|
97 |
signal_set(&ev_sigterm, SIGTERM, sig_handler, NULL); |
|
98 |
signal_add(&ev_sigint, NULL); |
|
99 |
signal_add(&ev_sigterm, NULL); |
|
100 |
imsgev_init(&iev_session, pair[1], mb, session_imsgev, needfd); |
|
101 |
||
102 |
if (res == 0) { |
|
103 |
imsgev_xcompose(&iev_session, IMSG_MAILDROP_INIT, session_id, |
|
104 |
0, -1, &stats, sizeof(struct stats), "maildrop_init"); |
|
105 |
} else { |
|
106 |
logit(LOG_CRIT, "%zu: maildrop init failed %s", |
|
107 |
session_id, buf); |
|
108 |
imsgev_xcompose(&iev_session, IMSG_MAILDROP_INIT, session_id, |
|
109 |
0, -1, NULL, 0, "maildrop_init"); |
|
110 |
} |
|
111 |
||
112 |
if (event_dispatch() < 0) |
|
113 |
fatal("event_dispatch"); |
|
114 |
||
115 |
logit(LOG_INFO, "maildrop process exiting"); |
|
116 |
_exit(0); |
|
117 |
} |
|
118 |
||
119 |
/* |
|
120 |
* Build dst by substituting '~' with user's home dir and '%u' with user name |
|
121 |
* in src. Return the length of string built. If return value >= dst_sz then |
|
122 |
* dst is truncated. |
|
123 |
*/ |
|
124 |
static size_t |
|
125 |
expand(char *dst, const char *src, size_t dst_sz, struct passwd *pw) |
|
126 |
{ |
|
127 |
size_t i = 0, r; |
|
128 |
int c; |
|
129 |
||
3
a32da8616e0e
Properly NUL terminate expanded path by memsetting it.
Sunil Nimmagadda <sunil@sunilnimmagadda.com>
parents:
2
diff
changeset
|
130 |
memset(dst, 0, dst_sz); |
0 | 131 |
while ((c = *src++)) { |
132 |
if (i >= dst_sz) |
|
133 |
break; |
|
134 |
||
135 |
switch (c) { |
|
136 |
case '~': |
|
137 |
if ((r = strlcpy(&dst[i], pw->pw_dir, |
|
138 |
(dst_sz - i))) >= (dst_sz - i)) { |
|
139 |
i += r; |
|
140 |
goto end; |
|
141 |
} |
|
142 |
i += r; |
|
143 |
break; |
|
144 |
case '%': |
|
145 |
if (*src == 'u') { |
|
146 |
if ((r = strlcpy(&dst[i], pw->pw_name, |
|
147 |
(dst_sz - i))) >= (dst_sz - i)) { |
|
148 |
i += r; |
|
149 |
goto end; |
|
150 |
} |
|
151 |
i += r; |
|
152 |
src++; |
|
153 |
} else |
|
154 |
dst[i++] = c; |
|
155 |
break; |
|
156 |
default: |
|
157 |
dst[i++] = c; |
|
158 |
break; |
|
159 |
} |
|
160 |
} |
|
161 |
||
162 |
end: |
|
163 |
if (c) |
|
164 |
while ((c = *src++)) |
|
165 |
i++; |
|
166 |
||
167 |
dst[dst_sz - 1] = '\0'; |
|
168 |
return (i); |
|
169 |
} |
|
170 |
||
171 |
static void |
|
172 |
session_imsgev(struct imsgev *iev, int code, struct imsg *imsg) |
|
173 |
{ |
|
174 |
struct m_backend *mb = iev->data; |
|
175 |
||
176 |
switch (code) { |
|
177 |
case IMSGEV_IMSG: |
|
178 |
switch (imsg->hdr.type) { |
|
179 |
case IMSG_MAILDROP_UPDATE: |
|
180 |
update(iev, imsg, mb); |
|
181 |
break; |
|
182 |
case IMSG_MAILDROP_RETR: |
|
183 |
retr(iev, imsg, mb); |
|
184 |
break; |
|
185 |
case IMSG_MAILDROP_DELE: |
|
186 |
dele(iev, imsg, mb); |
|
187 |
break; |
|
188 |
case IMSG_MAILDROP_RSET: |
|
189 |
rset(iev, imsg, mb); |
|
190 |
break; |
|
191 |
case IMSG_MAILDROP_LIST: |
|
192 |
list(iev, imsg, mb); |
|
193 |
break; |
|
194 |
case IMSG_MAILDROP_LISTALL: |
|
2
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
195 |
list_all(iev, imsg, mb); |
0 | 196 |
break; |
197 |
default: |
|
198 |
logit(LOG_DEBUG, "%s: unexpected imsg %u", |
|
199 |
__func__, imsg->hdr.type); |
|
200 |
break; |
|
201 |
} |
|
202 |
break; |
|
203 |
case IMSGEV_EREAD: |
|
204 |
case IMSGEV_EWRITE: |
|
205 |
case IMSGEV_EIMSG: |
|
206 |
fatal("maildrop: imsgev read/write error"); |
|
207 |
break; |
|
208 |
case IMSGEV_DONE: |
|
209 |
event_loopexit(NULL); |
|
210 |
break; |
|
211 |
} |
|
212 |
} |
|
213 |
||
214 |
static void |
|
215 |
update(struct imsgev *iev, struct imsg *imsg, struct m_backend *mb) |
|
216 |
{ |
|
217 |
int res; |
|
218 |
uint32_t session_id = imsg->hdr.peerid; |
|
219 |
||
220 |
if ((res = mb->update(&m)) == 0) |
|
221 |
logit(LOG_INFO, "%zu: maildrop updated", session_id); |
|
222 |
else |
|
223 |
logit(LOG_CRIT, "%zu: maildrop updated failed", session_id); |
|
224 |
||
225 |
imsgev_xcompose(iev, IMSG_MAILDROP_UPDATE, session_id, 0, |
|
226 |
-1, &res, sizeof(res), "maildrop_update"); |
|
227 |
} |
|
228 |
||
229 |
static void |
|
230 |
retr(struct imsgev *iev, struct imsg *imsg, struct m_backend *mb) |
|
231 |
{ |
|
232 |
struct retr_res res; |
|
233 |
struct retr_req *req = imsg->data; |
|
234 |
int fd; |
|
235 |
||
236 |
fd = mb->retr(&m, req->idx, &res.nlines, &res.offset); |
|
237 |
/* pass on top arguments */ |
|
238 |
res.top = req->top; |
|
239 |
res.ntop = req->ntop; |
|
240 |
imsgev_xcompose(iev, IMSG_MAILDROP_RETR, imsg->hdr.peerid, 0, |
|
241 |
fd, &res, sizeof(res), "maildrop_retr"); |
|
242 |
} |
|
243 |
||
244 |
static void |
|
245 |
dele(struct imsgev *iev, struct imsg *imsg, struct m_backend *mb) |
|
246 |
{ |
|
247 |
unsigned int *idx = imsg->data; |
|
248 |
int res = 0; |
|
249 |
||
250 |
if (m.msgs_index[*idx]->flags & F_DELE) { |
|
251 |
res = -1; |
|
252 |
goto end; |
|
253 |
} |
|
254 |
||
255 |
m.msgs_index[*idx]->flags |= F_DELE; |
|
256 |
end: |
|
257 |
imsgev_xcompose(iev, IMSG_MAILDROP_DELE, imsg->hdr.peerid, 0, |
|
258 |
-1, &res, sizeof(res), "maildrop_dele"); |
|
259 |
} |
|
260 |
||
261 |
static void |
|
262 |
rset(struct imsgev *iev, struct imsg *imsg, struct m_backend *mb) |
|
263 |
{ |
|
264 |
size_t i; |
|
265 |
||
266 |
for (i = 0; i < m.nmsgs; i++) |
|
267 |
m.msgs_index[i]->flags = 0; |
|
268 |
||
269 |
imsgev_xcompose(iev, IMSG_MAILDROP_RSET, imsg->hdr.peerid, 0, |
|
270 |
-1, NULL, 0, "maildrop_rset"); |
|
271 |
} |
|
272 |
||
273 |
static void |
|
274 |
list(struct imsgev *iev, struct imsg *imsg, struct m_backend *mb) |
|
275 |
{ |
|
276 |
struct list_req *req = imsg->data; |
|
277 |
struct list_res res; |
|
278 |
char hash[SHA1_DIGEST_STRING_LENGTH]; |
|
279 |
size_t sz; |
|
280 |
||
281 |
res.idx = req->idx; |
|
282 |
do_list(req->idx, &sz, hash, sizeof(hash)); |
|
283 |
res.uidl = req->uidl; |
|
284 |
if (res.uidl) |
|
285 |
strlcpy(res.u.hash, hash, sizeof(res.u.hash)); |
|
286 |
else |
|
287 |
res.u.sz = sz; |
|
288 |
||
289 |
imsgev_xcompose(iev, IMSG_MAILDROP_LIST, imsg->hdr.peerid, 0, |
|
290 |
-1, &res, sizeof(res), "maildrop_list"); |
|
291 |
||
292 |
} |
|
293 |
||
294 |
static void |
|
7
bb148c4cfe52
Move it closer to list.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
6
diff
changeset
|
295 |
do_list(unsigned int idx, size_t *sz, char *hash, size_t hash_sz) |
bb148c4cfe52
Move it closer to list.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
6
diff
changeset
|
296 |
{ |
bb148c4cfe52
Move it closer to list.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
6
diff
changeset
|
297 |
if (m.msgs_index[idx]->flags & F_DELE) { |
bb148c4cfe52
Move it closer to list.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
6
diff
changeset
|
298 |
*sz = 0; |
bb148c4cfe52
Move it closer to list.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
6
diff
changeset
|
299 |
strlcpy(hash, "", hash_sz); |
bb148c4cfe52
Move it closer to list.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
6
diff
changeset
|
300 |
return; |
bb148c4cfe52
Move it closer to list.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
6
diff
changeset
|
301 |
} |
bb148c4cfe52
Move it closer to list.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
6
diff
changeset
|
302 |
|
bb148c4cfe52
Move it closer to list.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
6
diff
changeset
|
303 |
*sz = m.msgs_index[idx]->sz; |
bb148c4cfe52
Move it closer to list.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
6
diff
changeset
|
304 |
strlcpy(hash, m.msgs_index[idx]->hash, hash_sz); |
bb148c4cfe52
Move it closer to list.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
6
diff
changeset
|
305 |
} |
bb148c4cfe52
Move it closer to list.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
6
diff
changeset
|
306 |
|
bb148c4cfe52
Move it closer to list.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
6
diff
changeset
|
307 |
static void |
2
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
308 |
list_all(struct imsgev *iev, struct imsg *imsg, struct m_backend *mb) |
0 | 309 |
{ |
2
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
310 |
struct list_res res; |
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
311 |
size_t i; |
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
312 |
int *uidl = imsg->data; |
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
313 |
|
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
314 |
for (i = 0; i < m.nmsgs; i++) { |
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
315 |
if (m.msgs_index[i]->flags & F_DELE) |
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
316 |
continue; |
0 | 317 |
|
2
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
318 |
res.idx = i; |
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
319 |
res.uidl = *uidl; |
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
320 |
if (*uidl) { |
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
321 |
strlcpy(res.u.hash, m.msgs_index[i]->hash, |
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
322 |
sizeof(res.u.hash)); |
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
323 |
} else |
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
324 |
res.u.sz = m.msgs_index[i]->sz; |
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
325 |
|
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
326 |
imsgev_xcompose(iev, IMSG_MAILDROP_LISTALL, |
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
327 |
imsg->hdr.peerid, 0, -1, &res, sizeof(res), |
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
328 |
"maildrop_list"); |
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
329 |
} |
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
330 |
|
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
331 |
/* terminal sentinel: hash = "" and sz = 0 */ |
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
332 |
if (*uidl) |
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
333 |
strlcpy(res.u.hash, "", sizeof(res.u.hash)); |
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
334 |
else |
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
335 |
res.u.sz = 0; |
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
336 |
|
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
337 |
imsgev_xcompose(iev, IMSG_MAILDROP_LISTALL, imsg->hdr.peerid, |
6e7b98264ea2
Simplify list_all handling. Send an imsg for each msg instead of
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
0
diff
changeset
|
338 |
0, -1, &res, sizeof(res), "maildrop_list"); |
0 | 339 |
} |
340 |
||
341 |
static void |
|
342 |
needfd(struct imsgev *iev) |
|
343 |
{ |
|
344 |
fatalx("maildrop should never need an fd"); |
|
345 |
} |
|
346 |
||
347 |
static void |
|
348 |
sig_handler(int sig, short event, void *arg) |
|
349 |
{ |
|
350 |
switch (sig) { |
|
351 |
case SIGINT: |
|
352 |
case SIGTERM: |
|
353 |
event_loopexit(NULL); |
|
354 |
} |
|
355 |
} |
|
356 |
||
357 |
extern struct m_backend m_backend_mbox; |
|
358 |
extern struct m_backend m_backend_maildir; |
|
359 |
||
360 |
static struct m_backend * |
|
361 |
m_backend_lookup(enum m_type type) |
|
362 |
{ |
|
363 |
switch (type) { |
|
364 |
case M_MBOX: |
|
365 |
return &m_backend_mbox; |
|
366 |
break; |
|
367 |
case M_MAILDIR: |
|
368 |
return &m_backend_maildir; |
|
369 |
break; |
|
370 |
default: |
|
371 |
fatalx("m_backend_lookup: invalid m_type"); |
|
372 |
}; |
|
373 |
||
374 |
return (NULL); |
|
375 |
} |
|
376 |