16 #include "readwrite.h"
17 #include "timeoutread.h"
18 #include "timeoutwrite.h"
20 void die() { _exit(0); }
22 int saferead(fd
,buf
,len
) int fd
; char *buf
; int len
;
25 r
= timeoutread(1200,fd
,buf
,len
);
30 int safewrite(fd
,buf
,len
) int fd
; char *buf
; int len
;
33 r
= timeoutwrite(1200,fd
,buf
,len
);
39 substdio ssout
= SUBSTDIO_FDBUF(safewrite
,1,ssoutbuf
,sizeof ssoutbuf
);
42 substdio ssin
= SUBSTDIO_FDBUF(saferead
,0,ssinbuf
,sizeof ssinbuf
);
44 void put(buf
,len
) char *buf
; int len
;
46 substdio_put(&ssout
,buf
,len
);
50 substdio_puts(&ssout
,s
);
54 substdio_flush(&ssout
);
64 void die_nomem() { err("out of memory"); die(); }
65 void die_nomaildir() { err("this user has no $HOME/Maildir"); die(); }
66 void die_scan() { err("unable to scan $HOME/Maildir"); die(); }
68 void err_syntax() { err("syntax error"); }
69 void err_unimpl() { err("unimplemented"); }
70 void err_deleted() { err("already deleted"); }
71 void err_nozero() { err("messages are counted from 1"); }
72 void err_toobig() { err("not that many messages"); }
73 void err_nosuch() { err("unable to open that message"); }
74 void err_nounlink() { err("unable to unlink all deleted messages"); }
76 void okay() { puts("+OK \r\n"); flush(); }
78 void printfn(fn
) char *fn
;
81 put(fn
,str_chr(fn
,':'));
84 char strnum
[FMT_ULONG
];
87 void blast(ssfrom
,limit
)
95 if (getln(ssfrom
,&line
,&match
,'\n') != 0) die();
96 if (!match
&& !line
.len
) break;
97 if (match
) --line
.len
; /* no way to pass this info over POP */
98 if (limit
) if (!inheaders
) if (!--limit
) break;
102 if (line
.s
[0] == '.')
104 put(line
.s
,line
.len
);
112 stralloc filenames
= {0};
130 maildir_clean(&line
);
131 if (maildir_scan(&pq
,&filenames
,1,1) == -1) die_scan();
133 numm
= pq
.p ? pq
.len
: 0;
134 m
= (struct message
*) alloc(numm
* sizeof(struct message
));
137 for (i
= 0;i
< numm
;++i
) {
138 if (!prioq_min(&pq
,&pe
)) { numm
= i
; break; }
140 m
[i
].fn
= filenames
.s
+ pe
.id
;
141 m
[i
].flagdeleted
= 0;
142 if (stat(m
[i
].fn
,&st
) == -1)
145 m
[i
].size
= st
.st_size
;
155 for (i
= 0;i
< numm
;++i
) if (!m
[i
].flagdeleted
) total
+= m
[i
].size
;
157 put(strnum
,fmt_uint(strnum
,numm
));
159 put(strnum
,fmt_ulong(strnum
,total
));
167 for (i
= 0;i
< numm
;++i
) m
[i
].flagdeleted
= 0;
175 put(strnum
,fmt_uint(strnum
,last
));
183 for (i
= 0;i
< numm
;++i
)
184 if (m
[i
].flagdeleted
) {
185 if (unlink(m
[i
].fn
) == -1) err_nounlink();
188 if (str_start(m
[i
].fn
,"new/")) {
189 if (!stralloc_copys(&line
,"cur/")) die_nomem();
190 if (!stralloc_cats(&line
,m
[i
].fn
+ 4)) die_nomem();
191 if (!stralloc_cats(&line
,":2,")) die_nomem();
192 if (!stralloc_0(&line
)) die_nomem();
193 rename(m
[i
].fn
,line
.s
); /* if it fails, bummer */
199 int msgno(arg
) char *arg
;
202 if (!scan_ulong(arg
,&u
)) { err_syntax(); return -1; }
203 if (!u
) { err_nozero(); return -1; }
205 if (u
>= numm
) { err_toobig(); return -1; }
206 if (m
[u
].flagdeleted
) { err_deleted(); return -1; }
210 void pop3_dele(arg
) char *arg
;
215 m
[i
].flagdeleted
= 1;
216 if (i
+ 1 > last
) last
= i
+ 1;
220 void list(i
,flaguidl
)
224 put(strnum
,fmt_uint(strnum
,i
+ 1));
226 if (flaguidl
) printfn(m
[i
].fn
);
227 else put(strnum
,fmt_ulong(strnum
,m
[i
].size
));
231 void dolisting(arg
,flaguidl
) char *arg
; int flaguidl
;
242 for (i
= 0;i
< numm
;++i
)
243 if (!m
[i
].flagdeleted
)
250 void pop3_uidl(arg
) char *arg
; { dolisting(arg
,1); }
251 void pop3_list(arg
) char *arg
; { dolisting(arg
,0); }
253 substdio ssmsg
; char ssmsgbuf
[1024];
255 void pop3_top(arg
) char *arg
;
264 arg
+= scan_ulong(arg
,&limit
);
265 while (*arg
== ' ') ++arg
;
266 if (scan_ulong(arg
,&limit
)) ++limit
; else limit
= 0;
268 fd
= open_read(m
[i
].fn
);
269 if (fd
== -1) { err_nosuch(); return; }
271 substdio_fdbuf(&ssmsg
,read
,fd
,ssmsgbuf
,sizeof(ssmsgbuf
));
276 struct commands pop3commands
[] = {
277 { "quit", pop3_quit
, 0 }
278 , { "stat", pop3_stat
, 0 }
279 , { "list", pop3_list
, 0 }
280 , { "uidl", pop3_uidl
, 0 }
281 , { "dele", pop3_dele
, 0 }
282 , { "retr", pop3_top
, 0 }
283 , { "rset", pop3_rset
, 0 }
284 , { "last", pop3_last
, 0 }
285 , { "top", pop3_top
, 0 }
286 , { "noop", okay
, 0 }
287 , { 0, err_unimpl
, 0 }
297 if (!argv
[1]) die_nomaildir();
298 if (chdir(argv
[1]) == -1) die_nomaildir();
303 commands(&ssin
,pop3commands
);