1 #include "process.h"
2 #include "lock_maildrop.h"
3 #include "rw.h"
4 #include "md5.h"
5 #include <stdio.h>
6 #include <syslog.h>
7 #include <string.h>
8 #include <stdlib.h>
9 #include <errno.h>
10 #include <ctype.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <unistd.h>
14 #include <time.h>
15
16
17
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 static struct mail * mails;
23 static int number_mails;
24
25 extern const char * tmp_dir;
26
27
get_stats(long * msg,long * size)28 void get_stats(long * msg, long * size) {
29 long s = 0, m = 0;
30 int i;
31 for (i=0;i<number_mails;i++) {
32 if (!mails[i].deleted) {
33 m++;
34 s+= mails[i].adjsize;
35 }
36 }
37 *msg = m;
38 *size = s;
39 }
40
list_all(int fd)41 static void list_all(int fd) {
42 char line[MAXLINE+1];
43 int i;
44 write_line(fd,"+OK\r\n");
45 for (i=0;i<number_mails;i++) {
46 if (!mails[i].deleted) {
47 snprintf(line,MAXLINE,"%u %lu\r\n",i+1,mails[i].adjsize);
48 write_line(fd,line);
49 }
50 }
51 write_line(fd,".\r\n");
52 }
53
list_msg(int fd,unsigned int num)54 static void list_msg(int fd, unsigned int num) {
55 char line[MAXLINE+1];
56 if (num<1 || (num-1) >= number_mails || mails[num-1].deleted==1) {
57 write_line(fd,"-ERR no such message\r\n");
58 return;
59 }
60 snprintf(line,sizeof(line),"+OK %u %ld\r\n",num,mails[num-1].adjsize);
61 write_line(fd,line);
62 }
63
do_list(int fd,char * line)64 void do_list(int fd, char * line) {
65 unsigned int msg_num = 0;
66 if (sscanf(line+5,"%u",&msg_num)!=1) {
67 list_all(fd);
68 } else {
69 list_msg(fd,msg_num);
70 }
71 }
72
print_msg(int fd,unsigned int msg_num)73 static void print_msg(int fd, unsigned int msg_num) {
74 char line[MAXLINE+1];
75 int done = 0;
76 char * ptr;
77 FILE * f = fopen( mails[msg_num].filename, "a+b" );
78 if (!f) {
79 /* print some kind of warning */
80 syslog( LOG_ERR, "Failed to open tmp file `%s': %s", mails[msg_num].filename, strerror(errno));
81 return;
82 }
83 rewind(f);
84
85 line[0] = 0;
86 fgets(line,MAXLINE,f);
87
88 while (!feof(f)) {
89 if ((line[0]=='\n' || line[0]=='\r') && !done) {
90 write_line(fd,"\r\n");
91 done = 1;
92 } else {
93 ptr = strchr(line, '\r');
94 if (ptr == NULL) ptr = strchr(line, '\n');
95 if (ptr != NULL) ptr[0] = 0;
96 if (line[0] == '.') write_line(fd, ".");
97 write_line(fd, line);
98 write_line(fd, "\r\n");
99 }
100 fgets(line,MAXLINE,f);
101 }
102 fclose( f );
103 }
104
retrieve_msg(int fd,char * line)105 void retrieve_msg(int fd, char * line) {
106 unsigned int msg_num;
107 if (sscanf(line+5,"%u",&msg_num)!=1) {
108 write_line(fd,"-ERR invalid arguments\r\n");
109 return;
110 }
111 if (msg_num<1 || (msg_num-1) >= number_mails || mails[msg_num-1].deleted==1) {
112 write_line(fd,"-ERR no such message\r\n");
113 return;
114 }
115 write_line(fd,"+OK\r\n");
116 print_msg(fd,msg_num-1);
117 write_line(fd,".\r\n");
118 }
119
show_top_msg(int fd,char * l)120 void show_top_msg(int fd, char * l) {
121 unsigned int msg_num, lines, i;
122 char line[MAXLINE+1];
123 char * ptr;
124 FILE *f;
125
126 if (sscanf(l+4,"%u %u",&msg_num,&lines)!=2) {
127 write_line(fd,"-ERR invalid arguments\r\n");
128 return;
129 }
130 if (msg_num<1 ||
131 (msg_num-1) >= number_mails ||
132 mails[msg_num-1].deleted==1) {
133 write_line(fd,"-ERR no such message\r\n");
134 return;
135 }
136 write_line(fd,"+OK\r\n");
137 f = fopen( mails[msg_num-1].filename, "a+b" );
138 if (!f) {
139 /* throw some kind of warning */
140 syslog( LOG_ERR, "Failed to open tmp file `%s': %s", mails[msg_num].filename, strerror(errno));
141 return;
142 }
143
144 rewind( f );
145 line[0] = 0;
146 fgets(line,MAXLINE,f);
147
148 while ((line[0]!='\n' && line[0]!='\r') && !feof(f)) {
149 ptr = strchr(line, '\r');
150 if (ptr == NULL) ptr = strchr(line, '\n');
151 if (ptr != NULL) ptr[0] = 0;
152 if (line[0] == '.') write_line(fd, ".");
153 write_line(fd, line);
154 write_line(fd, "\r\n");
155 fgets(line,MAXLINE,f);
156 }
157 if (!feof(f)) {
158 write_line(fd,"\r\n");
159 fgets(line,MAXLINE,f);
160 for (i=0;i<lines && !feof(f);i++) {
161 ptr = strchr(line, '\r');
162 if (ptr == NULL) ptr = strchr(line, '\n');
163 if (ptr != NULL) ptr[0] = 0;
164 if (line[0] == '.') write_line(fd, ".");
165 write_line(fd, line);
166 write_line(fd, "\r\n");
167 fgets(line,MAXLINE,f);
168 }
169 }
170 write_line(fd,".\r\n");
171 fclose( f );
172 }
173
174
delete_msg(int fd,char * line)175 void delete_msg(int fd, char * line) {
176 unsigned int msg_num;
177 if (sscanf(line+5,"%u",&msg_num)!=1) {
178 write_line(fd,"-ERR invalid arguments\r\n");
179 return;
180 }
181 if (msg_num<1 || (msg_num-1) >= number_mails) {
182 write_line(fd,"-ERR no such message\r\n");
183 return;
184 }
185 mails[msg_num-1].deleted = 1;
186 write_line(fd,"+OK\r\n");
187 }
188
reset_msg(void)189 void reset_msg(void) {
190 int i;
191 for (i=0;i<number_mails;i++) {
192 mails[i].deleted = 0;
193 }
194 }
195
process_mails(char * maildrop)196 int process_mails(char * maildrop) {
197 FILE * f;
198 char line[MAXLINE+1];
199 int had_cr_or_nl;
200 long adj;
201 FILE *fTmp = NULL;
202 int iTmpFile;
203
204 f = fopen(maildrop,"a+"); /* open for reading and writing, create if doesn't exists */
205 if (f==NULL)
206 return 0;
207
208 srand(time(NULL));
209
210 /* fseek to the beginning */
211 rewind(f);
212 /* correct the permission */
213 chmod(maildrop, 0600);
214
215 lock_fd(fileno(f));
216 mails = NULL;
217 number_mails = 0;
218 fgets(line,MAXLINE,f);
219 if (strncmp(line,"From ",5)!=0) {
220 if (feof(f))
221 return 1;
222 else
223 return 0;
224 }
225 had_cr_or_nl = 1;
226 adj = 0;
227 while (!feof(f)) {
228 if (strncmp(line,"From ",5)==0 && had_cr_or_nl) {
229 if (number_mails>0) {
230 mails[number_mails-1].size = ftell(fTmp);
231 mails[number_mails-1].adjsize = mails[number_mails-1].size + adj;
232 fclose( fTmp );
233 }
234 adj = 0;
235 number_mails++;
236 mails = realloc(mails,number_mails*sizeof(struct mail));
237 if (mails==NULL) {
238 return 0;
239 }
240 memset( mails[number_mails-1].filename, '\0', sizeof(mails[number_mails-1].filename));
241 snprintf( mails[number_mails-1].filename, sizeof(mails[number_mails-1].filename), "%s/.akpop3d_%u_%u_XXXXXX", tmp_dir, getpid(), rand());
242 iTmpFile = mkstemp( mails[number_mails-1].filename );
243 if (iTmpFile == -1) {
244 syslog(LOG_ERR, "Failed to open tmp file `%s': %s", mails[number_mails-1].filename, strerror(errno));
245 return(0);
246 }
247 close( iTmpFile );
248 fTmp = fopen( mails[number_mails-1].filename, "w+b" );
249 if ( !fTmp )
250 {
251 syslog( LOG_ERR, "Failed to open tmp file `%s': %s", mails[number_mails-1].filename, strerror(errno));
252 return( 0 );
253 }
254 mails[number_mails-1].deleted = 0;
255 }
256 fputs(line,fTmp);
257 fgets(line,MAXLINE,f);
258 if (strchr(line, '\r') != NULL) {
259 had_cr_or_nl = 1;
260 } else if (strchr(line, '\n') != NULL) {
261 had_cr_or_nl = 1;
262 adj++;
263 } else {
264 had_cr_or_nl = 0;
265 }
266 }
267 unlock_fd(fileno(f));
268 fclose(f);
269 fputs(line,fTmp);
270 mails[number_mails-1].size = ftell(fTmp);
271 mails[number_mails-1].adjsize = mails[number_mails-1].size + adj;
272 fclose( fTmp );
273 return 1;
274 }
275
fcopy(FILE * f1,FILE * f2)276 static void fcopy(FILE * f1, FILE * f2) {
277 char line[MAXLINE+1];
278 fgets(line,MAXLINE,f2);
279 while (!feof(f2)) {
280 fputs(line,f1);
281 fgets(line,MAXLINE,f2);
282 }
283 }
284
do_update(char * maildrop)285 void do_update(char * maildrop) {
286 int i;
287 FILE * f = fopen(maildrop,"w");
288 if (f==NULL) {
289 syslog(LOG_ERR,"%s: %s: %s","failed to write to maildrop",maildrop,strerror(errno));
290 return;
291 }
292 lock_fd(fileno(f));
293 for (i=0;i<number_mails;i++) {
294 if (!mails[i].deleted) {
295 FILE *fTmp = fopen( mails[i].filename, "a+b" );
296 if ( fTmp ) {
297 rewind( fTmp );
298 fcopy(f,fTmp);
299 fclose( fTmp );
300 } else {
301 syslog( LOG_ERR, "Failed to open tmp file `%s': %s", mails[i].filename, strerror(errno) );
302 /* throw in some kind of warning */
303 }
304 }
305 }
306 unlock_fd(fileno(f));
307 fclose(f);
308 free(mails);
309 }
310
do_cleanup()311 void do_cleanup()
312 {
313 int i;
314 for ( i = 0; i < number_mails; i++ )
315 unlink( mails[i].filename );
316 }
317
output_uidl(int fd,int msgnum)318 void output_uidl(int fd, int msgnum) {
319 char linebuf[128];
320 unsigned char h[17];
321 FILE * f;
322 char buf[256];
323
324 f = fopen( mails[msgnum].filename, "a+b" );
325 if ( !f )
326 {
327 syslog( LOG_ERR, "Failed to open tmp file `%s': %s", mails[msgnum].filename, strerror(errno));
328 return;
329 }
330
331 rewind(f);
332 fread(buf,255,1,f);
333 fclose(f);
334 md5_buffer(buf, 255, h);
335
336 snprintf(linebuf, sizeof(linebuf), "%u %08lx%08lx%08lx%08lx\r\n", msgnum+1,
337 (unsigned long) h[0] + (h[1]<<8) + (h[2]<<16) + (h[3]<<24),
338 (unsigned long) h[4] + (h[5]<<8) + (h[6]<<16) + (h[7]<<24),
339 (unsigned long) h[8] + (h[9]<<8) + (h[10]<<16) + (h[11]<<24),
340 (unsigned long) h[12] + (h[13]<<8) + (h[14]<<16) + (h[15]<<24)
341 );
342
343 write_line(fd,linebuf);
344 }
345
show_uidl(int fd,char * line)346 void show_uidl(int fd, char * line) {
347 int msgnum;
348
349 while (line[0] == ' ') line ++;
350 if (isdigit(line[0])) {
351 msgnum = atoi(line);
352 if ((msgnum < 1) || (msgnum > number_mails) || (mails[msgnum-1].deleted)) {
353 write_line(fd, "-ERR no such message\r\n");
354 return;
355 }
356 write_line(fd, "+OK ");
357 output_uidl(fd, msgnum-1);
358 } else {
359 write_line(fd, "+OK\r\n");
360 for (msgnum=0;msgnum<number_mails;msgnum++) {
361 if (mails[msgnum].deleted) continue;
362 output_uidl(fd, msgnum);
363 }
364 write_line(fd, ".\r\n");
365 }
366 }
367