#include "pop.h"

#define ASYNCBUFSIZE 8192

/* Variables global to this file */

struct Library *SockBase ;
int havemail;

/* Functions */

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

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

	if((SockBase = OpenLibrary( SOCKLIBNAME, SOCKLIBVERSION )) == NULL)
	{
		doreq("Error opening socket.library\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);
	sprintf(title,"Got Connection");
	settitle();

	sendgreet(s);

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

	count=havemail=sendstat(s);

	while (count && okay)
	{
		sprintf(title,"Retrieving %lu",count);
		settitle();

		okay=retrieve(s,count);

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

			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)
{
	sprintf(buf,"HELLO\r\n");
	trans(s);

	return(0);
}

int senduser(int s)
{
	int t;

	sprintf(title,"Sending Username");
	settitle();

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

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

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

/* Password */

	sprintf(title,"Sending Password");
	settitle();

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

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

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

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

	return(0);
}

int sendquit(int s)
{
	int t;

	sprintf(title,"Sending QUIT");
	settitle();

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

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

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

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

	sprintf(title,"Quit Acknowledged");
	settitle();

	return(0);
}

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

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

	if ( !trans(s) ) 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;
	BOOL begin=TRUE;
	struct AsyncFile *ofp;

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

        if ( ofp == NULL)
		{
			doreq("Open() failed\n",bum);
			FreeVec(havefrom);
			return(0);
		}

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

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

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

		if (strstr(buf,"\r\n"))
		{
			WriteAsync(ofp,strstr(buf,"\r\n")+2,strlen(strstr(buf,"\r\n")+2));
		}

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

			goon=lastblock(buf);

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

			/* Magic to add "From " header */
			if (begin && goon)
			{
				if (buf[0] != 'F')
				{
					struct DateTime dt;
					char day[20]="";
					char date[20]="";
					char time[20]="";
					char *newtemp;

					if (newtemp=AllocVec(2*BUFSIZE,MEMF_CLEAR))
					{
						DateStamp(&dt.dat_Stamp);

						dt.dat_Format = FORMAT_USA;
						dt.dat_Flags = 0;
						dt.dat_StrDay = day;
						dt.dat_StrDate = date;
						dt.dat_StrTime = time;

						DateToStr(&dt);

						sprintf(newtemp,"From %s@%s %s %s %s\n", username,pophost, day, date, time);
						WriteAsync(ofp,newtemp,strlen(newtemp));
						FreeVec(newtemp);
					}
				}
			}
			begin=FALSE;

			strip();

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

			if (c == -1)
			{
				doreq("FPuts() failed!",bum);
				goon=0;
			}
		}

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

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

}

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

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

	return(1);
}

int valcheck(int t, char *localtemp)
{
	if (t == 0)
	{
		doreq("scanf() failed\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 )
{
	ULONG foo;

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

	foo=recv(s,buf,BUFSIZE-1,0);
	buf[foo]='\0';

	if ( !foo )
	{
		return(0);
	}

	return (1);
}

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

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

	len=strlen(buf);

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

	strcpy(buf,out);
}

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

	if ( (found=strstr(segment,"\r\n.\r\n")))
	{
		buf[(found-segment)-1]='\n';
		buf[found-segment]='\0'; /* Kill '.' at end of message */
		return(0);
	}

	if ( (len==2) && (found=strstr(segment,"\r\n")) )
	{
		return(0);
	}

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

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

	return(1);
}