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