#include "pop.h"

/* Stuff for "From " Header */
/* Courtesy Michael B. Smith */


struct mytm	{
				int year;
				int month;
				int day;
				int dow;
				int hour;
				int min;
				int sec;
			};

/* DaysInMonth */
static const int	dim [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
static const char	*months [] = {	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
		       						"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
static const char	*days [] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };

static void DateStampToMyTm (struct DateStamp *date, struct mytm *da)
{
	int days, years, leap  = 0, month = 0;

	days = date->ds_Days + 731;		/*  1976	*/
	years = days / (365*3+366);		/*  #quad yrs	*/
	days -= years * (365*3+366);
	years = 1976 + 4 * years;

	if (days <= 365)
	{
		leap = 1;
	}
	else
	{
		days -= 366;
		++years;
		years += days / 365;
		days %= 365;
	}

	month = 0;
	while (1)
	{
		if (month == 1)
		{
			if (days < (28 + leap)) break;
			days -= 28 + leap;
		}
		else
		{
			if (days < dim [month]) break;
			days -= dim [month];
		}
		++month;
	}

	da->hour   = date->ds_Minute / 60;
	da->min    = date->ds_Minute % 60;
	da->sec    = date->ds_Tick / 50;

	da->day    = days + 1;
	da->month  = month + 1;
	da->dow    = date->ds_Days % 7;    /*  0 = sunday   */
	da->year   = years;

	return;
}

char * datestr (char *buf)
{
	/*
	**  datestr
	**
	**	Build ARPA date-time as specified in RFC-822:
	**
	**	    Wed, 13 Oct 93 18:52:04 EST
	**	    123456789012345678901234567890
	**
	**	buf must be 24 characters, plus space for TimeZone and NUL.
	**
	**	As TimeZone may be "(+23:30)" or similar, 33 chars should
	**	do it.
	*/
	struct mytm da;
	struct DateStamp ds;

	DateStampToMyTm (DateStamp (&ds), &da);

	DoFmt (buf, "%s, %ld %s %ld %02ld:%02ld:%02ld",
				days [da.dow], da.day,
				months [da.month - 1], da.year % 100,
				da.hour, da.min, da.sec);

	return buf;
}

char * time_stamp (char *buf)
{
	/*
	**  time_stamp
	**
	**	Put a time/date stamp into buf (for logging)
	**
	**	13 Nov 93 13:14:45
	*/
	struct DateStamp ds;
	struct mytm da;

	DateStampToMyTm (DateStamp (&ds), &da);

	DoFmt (buf, "%ld %s %ld %02ld:%02ld:%02ld",
				da.day,
				months [da.month - 1], da.year % 100,
				da.hour, da.min, da.sec);

	return buf;
}

/*  End stuff for "From " header */


#define ASYNCBUFSIZE 8192

BOOL needfrom ( char * , struct AsyncFile *);

/* Variables global to this file */

struct Library *SockBase ;
int havemail;

/* Functions */

int dopop(void)
{
	int s;
	int count=1;
	int okay=1;
	struct hostent *hp;
	struct sockaddr_in sa;

	DoFmt(title,"Connecting to %s",pophost);
	settitle(title);

	if((SockBase = OpenLibrary( SOCKLIBNAME, SOCKLIBVERSION )) == NULL)
	{
		doreq("Error opening "SOCKLIBNAME"\n",bum);
		return(1);
	}
#ifdef AMITCP
	SetErrnoPtr(&errno, sizeof errno);
#else
	setup_sockets( MAXSOCKS, &errno );
#endif

	if((hp=gethostbyname(pophost))==NULL)
	{
#ifndef AMITCP
		cleanup_sockets();
#endif
		CloseLibrary( SockBase ) ;
		doreq("Connection Refused.",bum);
		return(1);
	}

	bzero(&sa, sizeof(sa));
	bcopy(hp->h_addr, (char *)&sa.sin_addr, hp->h_length);
	sa.sin_family = hp->h_addrtype;
	sa.sin_port = htons((u_short)port);
	if ((s=socket(hp->h_addrtype,SOCK_STREAM,0)) < 0)
	{
#ifndef AMITCP
		cleanup_sockets();
#endif
		CloseLibrary( SockBase ) ;
		doreq("Something bad\nhas happened.",bum);
		return(1);
	}

	if (connect(s,(struct sockaddr *) &sa,sizeof(sa))< 0)
	{
		doreq("No POP3 daemon\nrunning on this\nmachine or port.",bum);
		s_close(s);
#ifndef AMITCP
		cleanup_sockets();
#endif
		CloseLibrary( SockBase ) ;
		return(1);
	}

/* Put actual code here */

	recv(s,buf,BUFSIZE-1,0);
	settitle("Got Connection");

/*	sendgreet(s);*/

	if (senduser(s))
	{
#ifndef AMITCP
		cleanup_sockets();
#endif
		CloseLibrary( SockBase ) ;
		return(1);
	}

	havemail=sendstat(s);

	while ((okay) && ((havemail > count) || (havemail == count)))
	{
		DoFmt(title,"Retrieving %lu",count);
		settitle(title);

		okay=retrieve(s,count);

		if (delmail && okay)
		{
			DoFmt(title,"Deleting %lu",count);
			settitle(title);

			okay=delmessage(s,count);
		}
		++count;
	}

	if(sendquit(s))
	{
#ifndef AMITCP
		cleanup_sockets();
#endif
		CloseLibrary( SockBase ) ;
		return(1);
	}

	if (Project0Wnd)
	{
		SetWindowTitles(Project0Wnd,Project0Wdt, (UBYTE *) ~0);
	}

	if (havemail && notify) /* removed sendstat() after Nofify */
	{
		doreq("You have new mail.","Cool");
	}

/* End actual code */

    s_close(s);
#ifndef AMITCP
	cleanup_sockets();
#endif
	CloseLibrary( SockBase ) ;
	return(0);
}

/*int sendgreet(int s)
{
	DoFmt(buf,"HELLO\r\n");
	trans(s,buf);

	return(0);
}*/

int senduser(int s)
{
	int t;

	settitle("Sending Username");

	DoFmt(buf,"USER %s\r\n",username);

	if ( !trans(s,buf) ) return(1);

	t=sscanf(buf,"%s",temp);
	if ( valcheck(t,temp) ) return(1);

/* Password */

	settitle("Sending Password");

	DoFmt(buf,"PASS %s\r\n",password);

	if ( !trans(s,buf) ) return(1);

	t=sscanf(buf,"%s",temp);

	if ( valcheck(t,temp) ) return(1);

	return(0);
}

int sendquit(int s)
{
	int t;

	settitle("Sending QUIT");

	DoFmt(buf,"QUIT\r\n");

	if ( !trans(s,buf) ) return(1);

	t=sscanf(buf,"%s",temp);

	if ( valcheck(t,temp) ) return(1);

	settitle("Quit Acknowledged");

	return(0);
}

int sendstat( int s )
{
	int t;
	int count=0;

	DoFmt(buf,"STAT\r\n");

	if ( !trans(s,buf) ) return(0);

	t=sscanf(buf,"%s %lu",temp,&count);

	if ( valcheck(t,temp) ) return(0);

	return(count);
}

int retrieve(int s,int count)
{
	int foo;
	int c;
	int goon=1;

	char *havefrom;
	char *buf2;
	char *buf3;

	BOOL begin=TRUE;
	struct AsyncFile *ofp;

	if (havefrom=AllocVec(512,MEMF_CLEAR))
	{
		if ( (count == 1) && (!appfile) )
		{
			ofp = OpenAsync(maildir, MODE_WRITE,ASYNCBUFSIZE);
        }
		else
		{
			ofp = OpenAsync(maildir, MODE_APPEND,ASYNCBUFSIZE);
		}

        if ( ofp == NULL)
		{
			doreq("Unable to lock mailbox.\n",bum);
			FreeVec(havefrom);
			return(0);
		}

		DoFmt(buf,"RETR %lu\r\n",count);

		if ( !trans(s,buf) )
		{
			CloseAsync(ofp);
			FreeVec(havefrom);
			return(0);
		}

		if ( valcheck(1,buf) )
		{
			CloseAsync(ofp);
			FreeVec(havefrom);
			return(0);
		}

		/*buf3=strstr(buf,".\r\n");

		if ( (buf3) && (buf3+3) )
		{
			char *buf4;

			if (needfrom(buf3,ofp))
			{
				begin=FALSE;
			}

			buf4=strip(buf3);
			buf3=stpchrn(buf4,0x20);
			if (buf3)
			{
				WriteAsync(ofp,buf3,strlen(buf3));
			}
		}*/

		/* Hack this up once more 11/5/94 */

		{
			buf3=strstr(buf,".\r\n");

			if ( (buf3) && (buf3+3) )
			{
				char *buf4;

				if (needfrom(buf3+2,ofp))
				{
					begin=FALSE;
				}

				buf4=strip(buf3+2);
				/*buf3=stpchrn(buf4,0x20);*/

				if (buf4)
				{
					WriteAsync(ofp,buf4,strlen(buf4));
				}
			}

		}

		while ( goon )
		{
			foo=recv(s,buf,BUFSIZE-1,0);

			if (foo < 1)
			{
				goon=0;
			}

			buf[foo]='\0';

			goon=lastblock(buf);

			/* Magic to add "From " header */

			if (begin && goon)
			{
				needfrom(buf,ofp);
			}

			begin=FALSE;

			buf2=strip(buf);

			c=WriteAsync(ofp,buf2,strlen(buf2));

			if (c == -1)
			{
				doreq("Error during write to mailbox.",bum);
				goon=0;
			}
		}

		WriteAsync(ofp,"\n",1);
		CloseAsync(ofp);

		FreeVec(havefrom);
		return(1);
	}
	else
	{
		return(0);
	}

}

int delmessage( int s, int count )
{
	DoFmt(buf,"DELE %lu\r\n",count);
	trans(s,buf);

	if ( valcheck(1,buf) ) return(0);

	return(1);
}

int valcheck(int t, char *localtemp)
{
	if (t == 0)
	{
		doreq("Got a bogus return string.\n",bum);
		return(1);
	}

	if ( !strstr(localtemp,"+OK") )
	{
		doreq("Didn't get +OK",bum);

		if (localtemp[0] != '\0')
		{
			doreq(localtemp,bum);
		}
		return(1);
	}
	return(0);
}

int trans( int s, char *mybuf )
{
	int foo;

	send(s,mybuf,strlen(mybuf),0);

	foo=recv(s,buf,BUFSIZE-1,0);

	if ( foo < 1 )
	{
		return(0);
	}

	buf[foo]='\0';

	return (1);
}

void settitle( char *newtitle )
{
	if (winop)
	{
		SetWindowTitles(Project0Wnd,newtitle, (UBYTE *) ~0);
	}
}

char *strip( char *mybuf )
{
	char out[BUFSIZE]="";
	ULONG x1=0;
	ULONG x2=0;
	ULONG len;

	len=strlen(mybuf);

	while (mybuf[x1] != '\0' )
	{
		while (mybuf[x1] == '\r')
		{
			++x1;
		}
		out[x2]=mybuf[x1];
		++x2;
		if (x1 < len)
		{
			++x1;
		}
	}
	out[x2]='\0';

	strcpy(mybuf,out);

	return(mybuf);
}

int lastblock (char *segment)
{
	char *found;
	int len = strlen(segment);

	if ( (found=strstr(segment,"\r\n.\r\n")))
	{
		/*buf[found-segment]='\n';*/
		buf[found-segment]='\0'; /* used to be found-segment+2 */
		return(0);
	}

	if ( (len==2) && (found=strstr(segment,"\r\n")) )
	{
		buf[found-segment]='\0'; /* Added recently */
		return(0);
	}

	if ( len==1 ) /* Kludge of the century */
	{
		return(0);
	}

	if ( (len <= 4) && (found=strstr(segment,".\r\n")) )
	{
		/*buf[found-segment]='\n';*/
		buf[found-segment]='\0';
		return(0);
	}

	return(1);
}

BOOL needfrom(char *mybuf,struct AsyncFile *ofp)
{
	if ( !strstr(mybuf,"From ") )
	{
		char *newtemp;

		if (newtemp=AllocVec(BIGSTRING,MEMF_CLEAR))
		{
			int tempsize=0;

			DoFmt(newtemp,"From %s@%s ", username,pophost);
			tempsize=strlen(newtemp);
			DoFmt((newtemp+tempsize),"%s\n",datestr((newtemp+tempsize)));
			WriteAsync(ofp,newtemp,strlen(newtemp));
			FreeVec(newtemp);
		}

		return(TRUE);
	}
	return(FALSE);
}