/*
This program searches the syslogged file and updates popauth.db in order to carry out pop/imapd-before-smtp.
written by DT1649651@yahoo.com.
The idea is getting from the Perl script of http://www.sendmail.org/~ca/email/roaming.html#POPB4SMTP
version 0.01
*/
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <time.h>
#include <glob.h>
#include <string.h>
#include <unistd.h>
#include <utime.h>
#define _PID_FILE_	"/etc/mailwatch.pid"
//int errno;
char aripdir[256];
char * checkauthen( char * buffer );
void touch(char *);
int clearoldip( int timedelta );
void makehash();
void updatedb();

int main( int argc, char ** argv)
{
FILE *fp, *pidfp;
int fd;
char buffer[1024*2];
int age;
int lasttime, currenttime;
pid_t pid;
	if( argc != 4 )
	{
		printf("Usage: mailwatch logfile ipdirectory age\n");
		return -1;
	}
	age = atoi( argv[3] );
	if( age <= 0 )
	{
		printf( "Invalid age\n");
		return -1;
	}
	strcpy( aripdir, argv[2] );
	fd = open( argv[1], O_RDONLY );
	if( fd == -1 )
	{
		printf( "Can not open %s\n", argv[1] );
		perror("Err=");
		return -1;
	}
	printf( "MailWatch 0.1, for using with hack popauth\n");
	// to switch this program to work as a daemon
        if( (pid=fork())< 0 )
        {
                perror( "Error on fork:");
                return -1;
        }
        else if ( pid != 0 )    // step 1 : parent leaves.
        {
                printf("Parent leaves, child will become daemon\n");
                exit(0);
        }
        // child continues here
        setsid();               // becomes session leader
        umask(0);
        printf("I am session leader now\n");
	pidfp = fopen( _PID_FILE_, "w+b");
	if( pidfp != NULL )
	{
		pid = getpid();
		sprintf( buffer, "%ld\n", pid );
		fwrite( buffer, sizeof(char), strlen(buffer), pidfp );
		fclose(pidfp);
	}
 	// child now becomes daemon

 
	fp = fdopen( fd,"r" );
	fseek( fp, 0, SEEK_END );
	lasttime = 0;
	currenttime = time(NULL);
	while(1)
	{
		struct stat statbuf;
		if( fgets( buffer, sizeof(buffer), fp) != NULL )
		{
			char * p;
			if( (p = checkauthen( buffer )) != NULL )
			{
				printf("%s OK\n", p);
				touch( p );
				makehash();
				updatedb();
			}
		}
		else
		{
			if( errno )
			{
				perror("fgets err:");
				errno  = 0;
			}
		}
		if( fstat( fd, &statbuf ) == -1 )
		{
			perror("\nStat Err:");
			errno = 0;
		}
		currenttime = time(NULL);
		if( currenttime - lasttime >= 60 ) // check the timeout every minute
		{
			lasttime = currenttime;
			if( clearoldip(age) )
			{
				makehash(); 
				updatedb();
			}
		}
		// try to be a good citizen
		usleep(500);	
		errno = 0;	// to clear interrupt-error
	}
	return 0;
}

char * checkauthen( char * buffer )
{
static char arip[32];
	//check for qpopper
	if( strstr( buffer, "qpopper[" ) != NULL && 
		strstr( buffer, "POP login by user") != NULL  )
	{
		int length = strlen(buffer);
		int i;
		for( i = length-1; i >= 0; i-- )
			if( buffer[i] == 0x20 ) break;
		if( i >= 0 && (i++)< length)
		{
			strcpy( arip, buffer+i );
			for( i = 0; i < strlen(arip); i++ )
				if ( arip[i] == 0x0A || arip[i]== 0x0D )
				{
					arip[i] = 0;
					break;
				}
			return arip;
		}
	}
	// check for imapd ( ftp.cac.washington.edu )
	if( strstr( buffer, "imapd[") != NULL &&
		strstr( buffer, "Login user=") != NULL )
	{
		int length = strlen(buffer);
		int i;
		for( i = length -1; i>=0; i-- )
			if( buffer[i] == '[' ) break;
		if( i >= 0 && (i++)<length)
		{
			strcpy( arip, buffer+i);
			for( i = 0; i < strlen(arip); i++ )
				if( arip[i] == ']' || arip[i] == 0x0A ||
				    arip[i] == 0x0D )
				{
					arip[i] = 0;
					break;	
				}
			return arip;
		}
	
	}
	

	// check for ...
	return NULL;	
}
void touch(char * fname )
{
int fd;
char fullname[256];
	sprintf( fullname, "%s/%s", aripdir,fname );
	printf( "touch : %s\n", fullname );
	fd = open( fullname, O_CREAT, S_IFREG|S_IRWXO|S_IRWXG|S_IRWXU ); 
	if( fd != -1 )
	{
		close(fd);
		utime( fullname, NULL );
	}
	else perror("touch:");
	errno = 0;
}

void updatedb()
{
char *command1 = "cd /etc/mail; /usr/sbin/makemap hash pophash.junk < pophash.tmp";
char *command2 = "mv /etc/mail/pophash.junk.db /etc/mail/popauth.db";
	system( command1);
	system( command2);
	errno = 0;
}

int clearoldip( int timedelta )
{
time_t currenttime = time(NULL);
glob_t globdata;
char fullname[256];
struct stat statbuf;
int i;
int changed = 0;
	printf( "Current time = %d\n", currenttime );	
	sprintf( fullname, "%s/%s", aripdir, "*.*.*.*" );
	glob( fullname, GLOB_NOSORT, NULL, &globdata );
	printf( "Number of files: %d\n", globdata.gl_pathc );
	for( i = 0; i < globdata.gl_pathc; i++ )
	{
		printf( "glob: %s\n", globdata.gl_pathv[i]);
		stat( globdata.gl_pathv[i], &statbuf ); 
		printf( "current = %d, file = %d\n", currenttime, statbuf.st_atime);
		if( currenttime - statbuf.st_atime > timedelta )
		{
			printf("File %s is too old\n", globdata.gl_pathv[i] );
			unlink( globdata.gl_pathv[i] );
			changed = 1;
		}
	}
	globfree( &globdata);
	return changed;
}
void makehash()
{
glob_t globdata;
char fullname[256], buffer[128], arip[64];
FILE * fp;
int i;
char *p;
	fp = fopen( "/etc/mail/pophash.tmp", "w+b" );
	if( fp == NULL )
	{
		perror( "Can not create /etc/mail/pophash.tmp");
		return;
	}
	sprintf( fullname, "%s/%s", aripdir, "*.*.*.*");
	glob( fullname, GLOB_NOSORT, NULL, &globdata );
	for( i = 0; i < globdata.gl_pathc; i++ )
	{
		p = globdata.gl_pathv[i] + strlen( globdata.gl_pathv[i] ) -1;
		while( *p != '/' ) p--;
		strcpy( arip, p+1 );	
		sprintf( buffer, "%s OK\n", arip );
		fwrite( buffer, sizeof(char), strlen(buffer), fp );
		printf( "append to .tmp: %s\n", buffer );
	}
	fclose(fp);
	globfree( &globdata );
	errno = 0;
}
