#include "process.h"
#include "lock_maildrop.h"
#include "rw.h"
#include "md5.h"
#include <stdio.h>
#include <syslog.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
static struct mail * mails;
static int number_mails;
extern const char * tmp_dir;
void get_stats(long * msg, long * size) {
long s = 0, m = 0;
int i;
for (i=0;i<number_mails;i++) {
if (!mails[i].deleted) {
m++;
s+= mails[i].adjsize;
}
}
*msg = m;
*size = s;
}
static void list_all(int fd) {
char line[MAXLINE+1];
int i;
write_line(fd,"+OK\r\n");
for (i=0;i<number_mails;i++) {
if (!mails[i].deleted) {
snprintf(line,MAXLINE,"%u %lu\r\n",i+1,mails[i].adjsize);
write_line(fd,line);
}
}
write_line(fd,".\r\n");
}
static void list_msg(int fd, unsigned int num) {
char line[MAXLINE+1];
if (num<1 || (num-1) >= number_mails || mails[num-1].deleted==1) {
write_line(fd,"-ERR no such message\r\n");
return;
}
snprintf(line,sizeof(line),"+OK %u %ld\r\n",num,mails[num-1].adjsize);
write_line(fd,line);
}
void do_list(int fd, char * line) {
unsigned int msg_num = 0;
if (sscanf(line+5,"%u",&msg_num)!=1) {
list_all(fd);
} else {
list_msg(fd,msg_num);
}
}
static void print_msg(int fd, unsigned int msg_num) {
char line[MAXLINE+1];
int done = 0;
char * ptr;
FILE * f = fopen( mails[msg_num].filename, "a+b" );
if (!f) {
/* print some kind of warning */
syslog( LOG_ERR, "Failed to open tmp file `%s': %s", mails[msg_num].filename, strerror(errno));
return;
}
rewind(f);
line[0] = 0;
fgets(line,MAXLINE,f);
while (!feof(f)) {
if ((line[0]=='\n' || line[0]=='\r') && !done) {
write_line(fd,"\r\n");
done = 1;
} else {
ptr = strchr(line, '\r');
if (ptr == NULL) ptr = strchr(line, '\n');
if (ptr != NULL) ptr[0] = 0;
if (line[0] == '.') write_line(fd, ".");
write_line(fd, line);
write_line(fd, "\r\n");
}
fgets(line,MAXLINE,f);
}
fclose( f );
}
void retrieve_msg(int fd, char * line) {
unsigned int msg_num;
if (sscanf(line+5,"%u",&msg_num)!=1) {
write_line(fd,"-ERR invalid arguments\r\n");
return;
}
if (msg_num<1 || (msg_num-1) >= number_mails || mails[msg_num-1].deleted==1) {
write_line(fd,"-ERR no such message\r\n");
return;
}
write_line(fd,"+OK\r\n");
print_msg(fd,msg_num-1);
write_line(fd,".\r\n");
}
void show_top_msg(int fd, char * l) {
unsigned int msg_num, lines, i;
char line[MAXLINE+1];
char * ptr;
FILE *f;
if (sscanf(l+4,"%u %u",&msg_num,&lines)!=2) {
write_line(fd,"-ERR invalid arguments\r\n");
return;
}
if (msg_num<1 ||
(msg_num-1) >= number_mails ||
mails[msg_num-1].deleted==1) {
write_line(fd,"-ERR no such message\r\n");
return;
}
write_line(fd,"+OK\r\n");
f = fopen( mails[msg_num-1].filename, "a+b" );
if (!f) {
/* throw some kind of warning */
syslog( LOG_ERR, "Failed to open tmp file `%s': %s", mails[msg_num].filename, strerror(errno));
return;
}
rewind( f );
line[0] = 0;
fgets(line,MAXLINE,f);
while ((line[0]!='\n' && line[0]!='\r') && !feof(f)) {
ptr = strchr(line, '\r');
if (ptr == NULL) ptr = strchr(line, '\n');
if (ptr != NULL) ptr[0] = 0;
if (line[0] == '.') write_line(fd, ".");
write_line(fd, line);
write_line(fd, "\r\n");
fgets(line,MAXLINE,f);
}
if (!feof(f)) {
write_line(fd,"\r\n");
fgets(line,MAXLINE,f);
for (i=0;i<lines && !feof(f);i++) {
ptr = strchr(line, '\r');
if (ptr == NULL) ptr = strchr(line, '\n');
if (ptr != NULL) ptr[0] = 0;
if (line[0] == '.') write_line(fd, ".");
write_line(fd, line);
write_line(fd, "\r\n");
fgets(line,MAXLINE,f);
}
}
write_line(fd,".\r\n");
fclose( f );
}
void delete_msg(int fd, char * line) {
unsigned int msg_num;
if (sscanf(line+5,"%u",&msg_num)!=1) {
write_line(fd,"-ERR invalid arguments\r\n");
return;
}
if (msg_num<1 || (msg_num-1) >= number_mails) {
write_line(fd,"-ERR no such message\r\n");
return;
}
mails[msg_num-1].deleted = 1;
write_line(fd,"+OK\r\n");
}
void reset_msg(void) {
int i;
for (i=0;i<number_mails;i++) {
mails[i].deleted = 0;
}
}
int process_mails(char * maildrop) {
FILE * f;
char line[MAXLINE+1];
int had_cr_or_nl;
long adj;
FILE *fTmp = NULL;
int iTmpFile;
f = fopen(maildrop,"a+"); /* open for reading and writing, create if doesn't exists */
if (f==NULL)
return 0;
srand(time(NULL));
/* fseek to the beginning */
rewind(f);
/* correct the permission */
chmod(maildrop, 0600);
lock_fd(fileno(f));
mails = NULL;
number_mails = 0;
fgets(line,MAXLINE,f);
if (strncmp(line,"From ",5)!=0) {
if (feof(f))
return 1;
else
return 0;
}
had_cr_or_nl = 1;
adj = 0;
while (!feof(f)) {
if (strncmp(line,"From ",5)==0 && had_cr_or_nl) {
if (number_mails>0) {
mails[number_mails-1].size = ftell(fTmp);
mails[number_mails-1].adjsize = mails[number_mails-1].size + adj;
fclose( fTmp );
}
adj = 0;
number_mails++;
mails = realloc(mails,number_mails*sizeof(struct mail));
if (mails==NULL) {
return 0;
}
memset( mails[number_mails-1].filename, '\0', sizeof(mails[number_mails-1].filename));
snprintf( mails[number_mails-1].filename, sizeof(mails[number_mails-1].filename), "%s/.akpop3d_%u_%u_XXXXXX", tmp_dir, getpid(), rand());
iTmpFile = mkstemp( mails[number_mails-1].filename );
if (iTmpFile == -1) {
syslog(LOG_ERR, "Failed to open tmp file `%s': %s", mails[number_mails-1].filename, strerror(errno));
return(0);
}
close( iTmpFile );
fTmp = fopen( mails[number_mails-1].filename, "w+b" );
if ( !fTmp )
{
syslog( LOG_ERR, "Failed to open tmp file `%s': %s", mails[number_mails-1].filename, strerror(errno));
return( 0 );
}
mails[number_mails-1].deleted = 0;
}
fputs(line,fTmp);
fgets(line,MAXLINE,f);
if (strchr(line, '\r') != NULL) {
had_cr_or_nl = 1;
} else if (strchr(line, '\n') != NULL) {
had_cr_or_nl = 1;
adj++;
} else {
had_cr_or_nl = 0;
}
}
unlock_fd(fileno(f));
fclose(f);
fputs(line,fTmp);
mails[number_mails-1].size = ftell(fTmp);
mails[number_mails-1].adjsize = mails[number_mails-1].size + adj;
fclose( fTmp );
return 1;
}
static void fcopy(FILE * f1, FILE * f2) {
char line[MAXLINE+1];
fgets(line,MAXLINE,f2);
while (!feof(f2)) {
fputs(line,f1);
fgets(line,MAXLINE,f2);
}
}
void do_update(char * maildrop) {
int i;
FILE * f = fopen(maildrop,"w");
if (f==NULL) {
syslog(LOG_ERR,"%s: %s: %s","failed to write to maildrop",maildrop,strerror(errno));
return;
}
lock_fd(fileno(f));
for (i=0;i<number_mails;i++) {
if (!mails[i].deleted) {
FILE *fTmp = fopen( mails[i].filename, "a+b" );
if ( fTmp ) {
rewind( fTmp );
fcopy(f,fTmp);
fclose( fTmp );
} else {
syslog( LOG_ERR, "Failed to open tmp file `%s': %s", mails[i].filename, strerror(errno) );
/* throw in some kind of warning */
}
}
}
unlock_fd(fileno(f));
fclose(f);
free(mails);
}
void do_cleanup()
{
int i;
for ( i = 0; i < number_mails; i++ )
unlink( mails[i].filename );
}
void output_uidl(int fd, int msgnum) {
char linebuf[128];
unsigned char h[17];
FILE * f;
char buf[256];
f = fopen( mails[msgnum].filename, "a+b" );
if ( !f )
{
syslog( LOG_ERR, "Failed to open tmp file `%s': %s", mails[msgnum].filename, strerror(errno));
return;
}
rewind(f);
fread(buf,255,1,f);
fclose(f);
md5_buffer(buf, 255, h);
snprintf(linebuf, sizeof(linebuf), "%u %08lx%08lx%08lx%08lx\r\n", msgnum+1,
(unsigned long) h[0] + (h[1]<<8) + (h[2]<<16) + (h[3]<<24),
(unsigned long) h[4] + (h[5]<<8) + (h[6]<<16) + (h[7]<<24),
(unsigned long) h[8] + (h[9]<<8) + (h[10]<<16) + (h[11]<<24),
(unsigned long) h[12] + (h[13]<<8) + (h[14]<<16) + (h[15]<<24)
);
write_line(fd,linebuf);
}
void show_uidl(int fd, char * line) {
int msgnum;
while (line[0] == ' ') line ++;
if (isdigit(line[0])) {
msgnum = atoi(line);
if ((msgnum < 1) || (msgnum > number_mails) || (mails[msgnum-1].deleted)) {
write_line(fd, "-ERR no such message\r\n");
return;
}
write_line(fd, "+OK ");
output_uidl(fd, msgnum-1);
} else {
write_line(fd, "+OK\r\n");
for (msgnum=0;msgnum<number_mails;msgnum++) {
if (mails[msgnum].deleted) continue;
output_uidl(fd, msgnum);
}
write_line(fd, ".\r\n");
}
}
syntax highlighted by Code2HTML, v. 0.9.1