s/qmail 4.3.20
Next generation secure email transport
Loading...
Searching...
No Matches
qmail-pop3d.c
Go to the documentation of this file.
1#include <unistd.h>
2#include <sys/types.h>
3#include <sys/stat.h>
4#include "commands.h"
5#include "sig.h"
6#include "getln.h"
7#include "stralloc.h"
8#include "buffer.h"
9#include "alloc.h"
10#include "open.h"
11#include "prioq.h"
12#include "scan.h"
13#include "fmt.h"
14#include "str.h"
15#include "exit.h"
16#include "maildir.h"
17#include "timeout.h"
18#include "qmail.h"
19
20#define FDIN 0
21#define FDOUT 1
22#define POP3_TIMEOUT 1200
23
24int rename(const char *,const char *); // stdio.h
25
26static void done() { _exit(0); }
27
28static ssize_t safewrite(int fd,char *buf,int len)
29{
30 int r;
31 r = timeoutwrite(POP3_TIMEOUT,fd,buf,len);
32 if (r <= 0) _exit(0);
33 return r;
34}
35
37buffer bo = BUFFER_INIT(safewrite,FDOUT,outbuf,sizeof(outbuf));
38
39static ssize_t saferead(int fd,char *buf,int len)
40{
41 int r;
42 r = timeoutread(POP3_TIMEOUT,fd,buf,len);
43 if (r == -1) if (errno == ETIMEDOUT) { buffer_flush(&bo); _exit(0); }
44 if (r <= 0) _exit(0);
45 return r;
46}
47
49buffer bi = BUFFER_INIT(saferead,FDIN,inbuf,sizeof(inbuf));
50
51static void out(char *buf,int len)
52{
53 buffer_put(&bo,buf,len);
54}
55static void outs(char *s)
56{
57 buffer_puts(&bo,s);
58}
59static void flush()
60{
61 buffer_flush(&bo);
62}
63static void err(char *s)
64{
65 outs("-ERR ");
66 outs(s);
67 outs("\r\n");
68 flush();
69}
70
71static void die_nomem() { err("out of memory"); done(); }
72static void die_nomaildir() { err("this user has no $HOME/Maildir"); done(); }
73static void die_scan() { err("unable to scan $HOME/Maildir"); done(); }
74
75static void err_syntax() { err("syntax error"); }
76static void err_unimpl() { err("unimplemented"); }
77static void err_deleted() { err("already deleted"); }
78static void err_nozero() { err("messages are counted from 1"); }
79static void err_toobig() { err("not that many messages"); }
80static void err_nosuch() { err("unable to open that message"); }
81static void err_nounlink() { err("unable to unlink all deleted messages"); }
82
83static void okay() { outs("+OK \r\n"); flush(); }
84
85static void printfn(char *fn)
86{
87 fn += 4;
88 out(fn,str_chr(fn,':'));
89}
90
91char strnum[FMT_ULONG];
92stralloc line = {0};
93
94static void blast(buffer *bf,unsigned long limit)
95{
96 int match;
97 int inheaders = 1;
98
99 for (;;) {
100 if (getln(bf,&line,&match,'\n') != 0) done();
101 if (!match && !line.len) break;
102 if (match) --line.len; /* no way to pass this info over POP */
103 if (limit) if (!inheaders) if (!--limit) break;
104 if (!line.len)
105 inheaders = 0;
106 else
107 if (line.s[0] == '.')
108 out(".",1);
109 out(line.s,line.len);
110 out("\r\n",2);
111
112 if (!match) break;
113 }
114 out("\r\n.\r\n",5);
115 flush();
116}
117
118stralloc filenames = {0};
119prioq pq = {0};
120
121struct message {
123 unsigned long size;
124 char *fn;
125} *m;
126
128int last = 0;
129
130static void getlist()
131{
132 struct prioq_elt pe;
133 struct stat st;
134 int i;
135
137 if (maildir_scan(&pq,&filenames,1,1) == -1) die_scan();
138
139 numm = pq.p ? pq.len : 0;
140 m = (struct message *) alloc(numm * sizeof(struct message));
141 if (!m) die_nomem();
142
143 for (i = 0; i < numm; ++i) {
144 if (!prioq_min(&pq,&pe)) { numm = i; break; }
146 m[i].fn = filenames.s + pe.id;
147 m[i].flagdeleted = 0;
148 if (stat(m[i].fn,&st) == -1)
149 m[i].size = 0;
150 else
151 m[i].size = st.st_size;
152 }
153}
154
155static void pop3_stat()
156{
157 int i;
158 unsigned long total;
159
160 total = 0;
161 for (i = 0; i < numm; ++i)
162 if (!m[i].flagdeleted) total += m[i].size;
163
164 outs("+OK ");
165 out(strnum,fmt_uint(strnum,numm));
166 outs(" ");
167 out(strnum,fmt_ulong(strnum,total));
168 outs("\r\n");
169 flush();
170}
171
172static void pop3_rset()
173{
174 int i;
175
176 for (i = 0; i < numm; ++i)
177 m[i].flagdeleted = 0;
178 last = 0;
179 okay();
180}
181
182static void pop3_last()
183{
184 outs("+OK ");
185 out(strnum,fmt_uint(strnum,last));
186 outs("\r\n");
187 flush();
188}
189
190static void pop3_quit()
191{
192 int i;
193
194 for (i = 0; i < numm; ++i)
195 if (m[i].flagdeleted) {
196 if (unlink(m[i].fn) == -1) err_nounlink();
197 } else {
198 if (str_start(m[i].fn,"new/")) {
199 if (!stralloc_copys(&line,"cur/")) die_nomem();
200 if (!stralloc_cats(&line,m[i].fn + 4)) die_nomem();
201 if (!stralloc_cats(&line,":2,")) die_nomem();
202 if (!stralloc_0(&line)) die_nomem();
203 rename(m[i].fn,line.s); /* if it fails, bummer */
204 }
205 }
206 okay();
207 done();
208}
209
210static int msgno(char *arg)
211{
212 unsigned long u;
213
214 if (!scan_ulong(arg,&u)) { err_syntax(); return -1; }
215 if (!u) { err_nozero(); return -1; }
216 --u;
217 if (u >= numm) { err_toobig(); return -1; }
218 if (m[u].flagdeleted) { err_deleted(); return -1; }
219 return u;
220}
221
222static void pop3_dele(char *arg)
223{
224 int i;
225
226 i = msgno(arg);
227 if (i == -1) return;
228 m[i].flagdeleted = 1;
229 if (i + 1 > last) last = i + 1;
230 okay();
231}
232
233static void list(int i,int flaguidl)
234{
235 out(strnum,fmt_uint(strnum,i + 1));
236 outs(" ");
237 if (flaguidl) printfn(m[i].fn);
238 else out(strnum,fmt_ulong(strnum,m[i].size));
239 outs("\r\n");
240}
241
242static void dolisting(char *arg,int flaguidl)
243{
244 unsigned int i;
245
246 if (*arg) {
247 i = msgno(arg);
248 if (i == -1) return;
249
250 outs("+OK ");
251 list(i,flaguidl);
252 } else {
253 okay();
254 for (i = 0; i < numm; ++i)
255 if (!m[i].flagdeleted) list(i,flaguidl);
256 outs(".\r\n");
257 }
258 flush();
259}
260
261static void pop3_uidl(char *arg) { dolisting(arg,1); }
262static void pop3_list(char *arg) { dolisting(arg,0); }
263
265buffer bm;
266
267static void pop3_top(char *arg)
268{
269 int i;
270 unsigned long limit;
271 int fd;
272
273 i = msgno(arg);
274 if (i == -1) return;
275
276 arg += scan_ulong(arg,&limit);
277 while (*arg == ' ') ++arg;
278 if (scan_ulong(arg,&limit)) ++limit;
279 else limit = 0;
280
281 fd = open_read(m[i].fn);
282 if (fd == -1) { err_nosuch(); return; }
283 okay();
284 buffer_init(&bm,read,fd,msgbuf,sizeof(msgbuf));
285 blast(&bm,limit);
286 close(fd);
287}
288
290 { "quit", pop3_quit, 0 }
291, { "stat", pop3_stat, 0 }
292, { "list", pop3_list, 0 }
293, { "uidl", pop3_uidl, 0 }
294, { "dele", pop3_dele, 0 }
295, { "retr", pop3_top, 0 }
296, { "rset", pop3_rset, 0 }
297, { "last", pop3_last, 0 }
298, { "top", pop3_top, 0 }
299, { "noop", okay, 0 }
300, { 0, err_unimpl, 0 }
301} ;
302
303int main(int argc,char * const *argv)
304{
305 sig_alarmcatch(done);
306 sig_pipeignore();
307
308 if (!argv[1]) die_nomaildir();
309 if (chdir(argv[1]) == -1) die_nomaildir();
310
311 getlist();
312
313 okay();
315 done();
316}
void outs(char *s)
Definition: auto-gid.c:12
int main()
Definition: chkshsgr.c:6
int stralloc_copys(stralloc *, char const *)
stralloc out
Definition: dnscname.c:12
void _exit(int)
strset done
Definition: fastforward.c:75
char buf[100+FMT_ULONG]
Definition: hier.c:11
int maildir_scan(prioq *, stralloc *, int, int)
Definition: maildir.c:83
void maildir_clean(stralloc *)
Definition: maildir.c:27
int match
Definition: matchup.c:196
struct prioq_elt *int prioq_min(prioq *, struct prioq_elt *)
Definition: prioq.c:24
void prioq_delmin(prioq *)
Definition: prioq.c:32
int fd
stralloc filenames
Definition: qmail-pop3d.c:118
char strnum[FMT_ULONG]
Definition: qmail-pop3d.c:91
int rename(const char *, const char *)
int last
Definition: qmail-pop3d.c:128
struct message * m
prioq pq
Definition: qmail-pop3d.c:119
int numm
Definition: qmail-pop3d.c:127
char outbuf[BUFSIZE_LINE]
Definition: qmail-pop3d.c:36
stralloc line
Definition: qmail-pop3d.c:92
buffer bi
Definition: qmail-pop3d.c:49
#define FDOUT
Definition: qmail-pop3d.c:21
buffer bm
Definition: qmail-pop3d.c:265
#define FDIN
Definition: qmail-pop3d.c:20
buffer bo
Definition: qmail-pop3d.c:37
char msgbuf[BUFSIZE_MESS]
Definition: qmail-pop3d.c:264
char inbuf[BUFSIZE_LINE]
Definition: qmail-pop3d.c:48
struct commands pop3commands[]
Definition: qmail-pop3d.c:289
#define POP3_TIMEOUT
Definition: qmail-pop3d.c:22
stralloc fn
Definition: qmail-qmaint.c:551
unsigned long size
Definition: qmail-qread.c:56
void blast()
Definition: qmail-remote.c:385
buffer bf
Definition: qmail-remote.c:325
#define BUFSIZE_MESS
Definition: qmail.h:7
#define BUFSIZE_LINE
Definition: qmail.h:8
ssize_t safewrite(int, char *, int)
Definition: qmail-qmqpc.c:49
void flush(void)
Definition: qmail-smtpd.c:91
void err_syntax(void)
Definition: smtpdlog.c:73
void die_nomem(void)
Definition: qreceipt.c:23
void err_unimpl(void)
Definition: smtpdlog.c:72
unsigned long size
Definition: qmail-pop3d.c:123
int flagdeleted
Definition: qmail-pop3d.c:122
char * fn
Definition: qmail-pop3d.c:124
Definition: prioq.h:7
unsigned long id
Definition: prioq.h:7