UINT HeaderThread(LPVOID pParam)
{
	// a bit dated and not up to date, but you'll get the idea
	CHeaderThreadInfo* pThreadInfo = (CHeaderThreadInfo*)pParam;

	HWND	hView = pThreadInfo->m_hView;
	HANDLE	hIsRetrieving = pThreadInfo->m_hIsRetrieving;
	CString	strNewsgroup = pThreadInfo->m_strNewsgroup;

	CAccount*	pAccount = pThreadInfo->m_pAccount;
	CPreferences*	pPreferences = pThreadInfo->m_pPreferences;
	
	delete pThreadInfo;


	char strPassword[64];
	char strUsername[64];
	DWORD	dwAccessType;
	CString	strProxyAddress = "";
	LPCTSTR pstrProxyAddress = NULL;
	
	pPreferences->m_cs.Lock();
	if (pPreferences->m_bUseProxy){
		
		if (pPreferences->m_nProxySetting == 0){
			dwAccessType = INTERNET_OPEN_TYPE_PRECONFIG;
		}
		else{
			dwAccessType = INTERNET_OPEN_TYPE_PROXY;
			
			strProxyAddress.Format("%s:%d", pPreferences->m_strProxyAddress,
							pPreferences->m_nProxyPort);
			pstrProxyAddress = strProxyAddress;
		}

		if (pPreferences->m_bProxyAuthentication){
			
			strcpy(strUsername, pPreferences->m_strProxyUsername);
			strcpy(strPassword, pPreferences->m_strProxyPassword);

		}
		else{
			pAccount->m_cs.Lock();
			strcpy(strUsername, pAccount->m_strNPUsername);
			strcpy(strPassword, pAccount->m_strNPPassword);
			pAccount->m_cs.Unlock();
		}

	}
	else{
		dwAccessType = INTERNET_OPEN_TYPE_DIRECT;
		pAccount->m_cs.Lock();
		strcpy(strUsername, pAccount->m_strNPUsername);
		strcpy(strPassword, pAccount->m_strNPPassword);
		pAccount->m_cs.Unlock();
	}
	pPreferences->m_cs.Unlock();

	CString	strURL, strDomain, strNewsProvider, strDRNDir;
	
	pAccount->m_cs.Lock();

	CString strRetrieveBy;
	switch(pAccount->m_nRetrieveBy){

	case SORTAUTHOR:
		strRetrieveBy = "b";
		break;
	case SORTOLDEST:
		strRetrieveBy = "f";
		break;
	case SORTCURRENT:
		strRetrieveBy = "g";
		break;
	case SORTSUBJECT:
		strRetrieveBy = "z";
		break;
	default:
		strRetrieveBy = "z";
		break;
	}

	switch(pAccount->m_nNewsProvider){

	case NEWSGUY:
		strNewsProvider = "NewsGuy";
		strDomain = "drn.newsguy.com";
		strNewsgroup = "news-bin/wwwnews?-s" + strRetrieveBy + ",b1,n100000,B+" + strNewsgroup;
		break;
	case NEWSGUYEXTRA:
		strNewsProvider = "NewsGuy Extra";
		strDomain = "edrn.newsguy.com";
		strNewsgroup = "news-bin/wwwnews?-s" + strRetrieveBy + ",b1,n100000,B+" + strNewsgroup;
		break;
	case WEBUSENET:
		strNewsProvider = "WebUseNet";
		strDomain = "www.webusenet.com";
		strNewsgroup = "drn-bin/wwwnews?-s" + strRetrieveBy + ",b1,n100000,B+" + strNewsgroup;
		break;
	case WEBUSENETMEMBER:
		strNewsProvider = "WebUseNet";
		strDomain = "members.webusenet.com";
		strNewsgroup = "drn-bin/wwwnews?-s" + strRetrieveBy + ",b1,n100000,B+" + strNewsgroup;
		break;
	default:
		strNewsProvider = "NewsGuy Extra";
		strDomain = "edrn.newsguy.com";
		strNewsgroup = "news-bin/wwwnews?-s" + strRetrieveBy + ",b1,n100000,B+" + strNewsgroup;
		break;
	}
	pAccount->m_cs.Unlock();

	LPCTSTR strProgress = "Retreiving Headers...";
	::PostMessage(hView, WM_DOWNLOAD_PROGRESS, 0, (LPARAM)strProgress);

	DWORD dwFlags = INTERNET_FLAG_DONT_CACHE;
	
	CInternetSession session(NULL, 1, dwAccessType, pstrProxyAddress, NULL, dwFlags);
	CHttpConnection*	pConnection = NULL;
	CHttpFile*			pHttpFile = NULL;
	
	strProgress = "Open InternetSession...";
	::PostMessage(hView, WM_DOWNLOAD_PROGRESS, 0, (LPARAM)strProgress);

	try {
		pAccount->m_cs.Lock();
		pConnection = session.GetHttpConnection(strDomain,
							INTERNET_INVALID_PORT_NUMBER,
							pAccount->m_strNPUsername,
							pAccount->m_strNPPassword);
		pAccount->m_cs.Unlock();
		pHttpFile = pConnection->OpenRequest(1,strNewsgroup, NULL, 1, NULL, NULL, INTERNET_FLAG_RELOAD |
							INTERNET_FLAG_EXISTING_CONNECT | INTERNET_FLAG_KEEP_CONNECTION);
		strProgress = "Open Request...";
		::PostMessage(hView, WM_DOWNLOAD_PROGRESS, 0, (LPARAM)strProgress);

		DWORD dwStatus;

resend:
		pHttpFile->SendRequest();
		pHttpFile->QueryInfoStatusCode(dwStatus);

		switch (dwStatus)
		{
			case HTTP_STATUS_PROXY_AUTH_REQ:    //Proxy Authentication Required

				strProgress = "Sending Proxy Password...";
				::PostMessage(hView, WM_DOWNLOAD_PROGRESS, 0, (LPARAM)strProgress);

				pPreferences->m_cs.Lock();
				strcpy(strUsername, pPreferences->m_strProxyUsername);
				strcpy(strPassword, pPreferences->m_strProxyPassword);
				pPreferences->m_cs.Unlock();

				pConnection->SetOption(INTERNET_OPTION_PROXY_USERNAME, 
								  strUsername, strlen(strUsername)+1);
				pConnection->SetOption(INTERNET_OPTION_PROXY_PASSWORD, 
								  strPassword, strlen(strPassword)+1);
				//AfxMessageBox("ProxyAuthentication\r\n" + strProxyUsername + "\r\n" + strProxyPassword);
				goto resend;
				break;
			case HTTP_STATUS_DENIED:     //Server Authentication Required

				strProgress = "Sending " + strNewsProvider + " Password...";
				::PostMessage(hView, WM_DOWNLOAD_PROGRESS, 0, (LPARAM)strProgress);

				pAccount->m_cs.Lock();
				strcpy(strUsername, pAccount->m_strNPUsername);
				strcpy(strPassword, pAccount->m_strNPPassword);
				pAccount->m_cs.Unlock();

				pConnection->SetOption(INTERNET_OPTION_USERNAME, 
								  strUsername, strlen(strUsername)+1);
				pConnection->SetOption(INTERNET_OPTION_PASSWORD, 
								  strPassword, strlen(strPassword)+1);
//				AfxMessageBox("NewsGuyAuthentication\r\n" + strNGUsername + "\r\n" + strNGPassword);
				goto resend;
				break;
		}

		CString	strQueryInfo;
		BOOL bQueryInfo = pHttpFile->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF, strQueryInfo);
		
		strProgress = strQueryInfo;
		::PostMessage(hView, WM_DOWNLOAD_PROGRESS, 0, (LPARAM)strProgress);

		CString strLine;
		CArticle* pArticle;
		int nTag, nStart, nEnd;
		BOOL bComplete, bPart;

		while(::WaitForSingleObject(hIsRetrieving,0) == WAIT_OBJECT_0) {
			//retrieve one line at a time
			if(pHttpFile->ReadString(strLine) == FALSE) //retrieve one line at a time
				break;								 //break if no more lines left

			//if (strLine.Find("/news-bin/wwwdecode?") != -1){//is this a 'messageheader' or a comment line?
				//if ((strLine.Find("/icons/drncheck.gif") != -1) || (strLine.Find("/icons/drnblank.gif") != -1)) {		
			if (strLine.Find("-bin/wwwdecode?") != -1){//is this a 'messageheader' or a comment line?
				
				//if ((strLine.Find("/drncheck.gif") != -1) || (strLine.Find("/drnblank.gif") != -1)
				//	|| strLine.Find() {
				
				bComplete = (strLine.Find("/drncheck.gif") != -1) || (strLine.Find("/drnblank.gif") != -1);
				bPart = (strLine.Find("/drnpart.gif"));

				if ((bComplete) || (bPart)){
					try	{
						pArticle = new CArticle;
					}
						catch(CMemoryException* me) {
						me->Delete();
						return FALSE;
					}

					if (bComplete){
						pArticle->m_nStatus = ARTICLE_NOTQUEUED;
					}
					else{
						pArticle->m_nStatus = ARTICLE_INCOMPLETE;
					}
					pArticle->m_nCanBeDeleted = LISTCTRLARTICLES;
					pArticle->m_nAttempts = 0;
					pArticle->m_strPath = "";
					pArticle->m_nNewsProvider = pAccount->m_nNewsProvider;
					//Date
					pArticle->m_strDate = strLine.Left(5);
					//Author
					nTag = strLine.Find('<');
					pArticle->m_strAuthor = strLine.Mid(5, (nTag - 5));
					pArticle->m_strAuthor.TrimLeft(); pArticle->m_strAuthor.TrimRight();
					//URL
					nStart = strLine.Find('?',nTag) + 1; //0 based index, hence add 1
					nEnd = strLine.Find('"',nStart);
					pArticle->m_strURL = strLine.Mid(nStart, (nEnd - nStart));
					//Size
					nStart = strLine.Find('>', nEnd) + 1;
					nEnd = strLine.Find('<', nStart);
					
					CString strTemp = strLine.Mid(nStart, (nEnd - nStart));

					int nIndex;
					int nMultiplier = 1;
					CString	strBegin, strEnd;

					if (strTemp.Find("K") != -1){
						nMultiplier = 100;

					}

					if (strTemp.Find("M") != -1){
						nMultiplier = 100000;
							
					}
					
					strTemp = strTemp.SpanExcluding("BKM");

					nIndex = strTemp.Find('.');
					int nSize;
					if (nIndex != -1){
						
						strBegin = strTemp.Left(nIndex);
						strEnd = strTemp.Right(strTemp.GetLength() - nIndex - 1);
						strTemp = strBegin + strEnd;
						nSize = atoi(strTemp);
						pArticle->m_nSize = nSize * nMultiplier;

						//pArticle->m_strSize.Format("%d", nSize);
					}
					else //pArticle->m_strSize = strTemp;
						pArticle->m_nSize = nSize;
										
					//pArticle->m_strSize = strLine.Mid(nStart, (nEnd - nStart));
					//Subject
					nStart = strLine.ReverseFind('"')+2; //Description start after ">
					nEnd = strLine.ReverseFind('<');
					pArticle->m_strSubject = strLine.Mid(nStart, (nEnd - nStart));
					//Clean-up HTML code
					pArticle->m_strAuthor.Replace("&amp;","&");
					pArticle->m_strAuthor.Replace("&lt;","<");
					pArticle->m_strSubject.Replace("&amp;","&");
					pArticle->m_strSubject.Replace("&lt;","<");
					
					nStart = pArticle->m_strSubject.ReverseFind('-');
					if (nStart != -1){
						pArticle->m_strPossibleFilename = pArticle->m_strSubject.Mid(nStart+1);
						pArticle->m_strPossibleFilename.TrimLeft();
					}

					::PostMessage(hView, WM_HEADER_DL_COMPLETE, 0, (LPARAM)pArticle);
				}
			}
		}
	}
	
	catch(CInternetException* e) {
		e->Delete();
	}

	if (pHttpFile != NULL){
		pHttpFile->Close();
		delete pHttpFile; // closes the file -- prints a warning
	}

	ResetEvent(hIsRetrieving);
	::PostMessage(hView, WM_HEADER_DL_COMPLETE, 1, 0);

	return 0;
}

UINT EasyNewsHeaderThread(LPVOID pParam)
{
	CHeaderThreadInfo* pThreadInfo = (CHeaderThreadInfo*)pParam;

	HWND	hView = pThreadInfo->m_hView;
	HANDLE	hIsRetrieving = pThreadInfo->m_hIsRetrieving;
	CString	strNewsgroup = "group.cgi?group=" + pThreadInfo->m_strNewsgroup;

	CAccount*	pAccount = pThreadInfo->m_pAccount;
	CPreferences*	pPreferences = pThreadInfo->m_pPreferences;
	BOOL	bUsePort81 = pThreadInfo->m_bUsePort81;

	delete pThreadInfo;


	char strPassword[64];
	char strUsername[64];
	DWORD	dwAccessType;
	CString	strProxyAddress = "";
	LPCTSTR pstrProxyAddress = NULL;
	
	pPreferences->m_cs.Lock();
	if (pPreferences->m_bUseProxy){
		
		if (pPreferences->m_nProxySetting == 0){
			dwAccessType = INTERNET_OPEN_TYPE_PRECONFIG;
		}
		else{
			dwAccessType = INTERNET_OPEN_TYPE_PROXY;
			
			strProxyAddress.Format("%s:%d", pPreferences->m_strProxyAddress,
							pPreferences->m_nProxyPort);
			pstrProxyAddress = strProxyAddress;
		}

		if (pPreferences->m_bProxyAuthentication){
			
			strcpy(strUsername, pPreferences->m_strProxyUsername);
			strcpy(strPassword, pPreferences->m_strProxyPassword);

		}
		else{
			pAccount->m_cs.Lock();
			strcpy(strUsername, pAccount->m_strNPUsername);
			strcpy(strPassword, pAccount->m_strNPPassword);
			pAccount->m_cs.Unlock();
		}

	}
	else{
		dwAccessType = INTERNET_OPEN_TYPE_DIRECT;
		pAccount->m_cs.Lock();
		strcpy(strUsername, pAccount->m_strNPUsername);
		strcpy(strPassword, pAccount->m_strNPPassword);
		pAccount->m_cs.Unlock();
	}
	pPreferences->m_cs.Unlock();

	CString	strURL, strDRNDir;
	CString strNewsProvider = "EasyNews";
	CString strDomain = "members.easynews.com";
	//TCHAR cDay = '0';
	int nDay = 0;

	LPCTSTR strProgress = "Retreiving Headers...";
	::PostMessage(hView, WM_DOWNLOAD_PROGRESS, 0, (LPARAM)strProgress);

	DWORD dwFlags = INTERNET_FLAG_DONT_CACHE;

start:	
	CInternetSession session(NULL, 1, dwAccessType, pstrProxyAddress, NULL, dwFlags);
	CHttpConnection*	pConnection = NULL;
	CHttpFile*			pHttpFile = NULL;
	
	strProgress = "Open InternetSession...";
	::PostMessage(hView, WM_DOWNLOAD_PROGRESS, 0, (LPARAM)strProgress);

	try {
		pAccount->m_cs.Lock();
		if (bUsePort81)
			pConnection = session.GetHttpConnection(strDomain,
								(INTERNET_PORT)81 ,
								pAccount->m_strNPUsername,
								pAccount->m_strNPPassword);

		else
			pConnection = session.GetHttpConnection(strDomain,
								INTERNET_INVALID_PORT_NUMBER,
								pAccount->m_strNPUsername,
								pAccount->m_strNPPassword);
		pAccount->m_cs.Unlock();
		pHttpFile = pConnection->OpenRequest(1,strNewsgroup, NULL, 1, NULL, NULL, INTERNET_FLAG_RELOAD |
							INTERNET_FLAG_EXISTING_CONNECT | INTERNET_FLAG_KEEP_CONNECTION);
		strProgress = "Open Request...";
		::PostMessage(hView, WM_DOWNLOAD_PROGRESS, 0, (LPARAM)strProgress);

		DWORD dwStatus;

resend:
		pHttpFile->SendRequest();
		pHttpFile->QueryInfoStatusCode(dwStatus);

		switch (dwStatus)
		{
			case HTTP_STATUS_PROXY_AUTH_REQ:    //Proxy Authentication Required

				strProgress = "Sending Proxy Password...";
				::PostMessage(hView, WM_DOWNLOAD_PROGRESS, 0, (LPARAM)strProgress);
				
				pPreferences->m_cs.Lock();
				strcpy(strUsername, pPreferences->m_strProxyUsername);
				strcpy(strPassword, pPreferences->m_strProxyPassword);
				pPreferences->m_cs.Unlock();

				pConnection->SetOption(INTERNET_OPTION_PROXY_USERNAME, 
								  strUsername, strlen(strUsername)+1);
				pConnection->SetOption(INTERNET_OPTION_PROXY_PASSWORD, 
								  strPassword, strlen(strPassword)+1);
				//AfxMessageBox("ProxyAuthentication\r\n" + strProxyUsername + "\r\n" + strProxyPassword);
				goto resend;
				break;
			case HTTP_STATUS_DENIED:     //Server Authentication Required

				strProgress = "Sending " + strNewsProvider + " Password...";
				::PostMessage(hView, WM_DOWNLOAD_PROGRESS, 0, (LPARAM)strProgress);

				pAccount->m_cs.Lock();
				strcpy(strUsername, pAccount->m_strNPUsername);
				strcpy(strPassword, pAccount->m_strNPPassword);
				pAccount->m_cs.Unlock();

				pConnection->SetOption(INTERNET_OPTION_USERNAME, 
								  strUsername, strlen(strUsername)+1);
				pConnection->SetOption(INTERNET_OPTION_PASSWORD, 
								  strPassword, strlen(strPassword)+1);
//				AfxMessageBox("NewsGuyAuthentication\r\n" + strNGUsername + "\r\n" + strNGPassword);
				goto resend;
				break;

			case 404:
				
				ResetEvent(hIsRetrieving);
				break;
		}

		CString	strQueryInfo;
		BOOL bQueryInfo = pHttpFile->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF, strQueryInfo);
		
		strProgress = strQueryInfo;
		::PostMessage(hView, WM_DOWNLOAD_PROGRESS, 0, (LPARAM)strProgress);

		bQueryInfo = pHttpFile->QueryOption(INTERNET_OPTION_URL, strNewsgroup);
		
		if (bUsePort81) strNewsgroup = strNewsgroup.Right(strNewsgroup.GetLength() - 30);
		else strNewsgroup = strNewsgroup.Right(strNewsgroup.GetLength() - 27); //strip http://members.easynews.com
		
		CString strTemp, strLine, strAuthor = "";
		CArticle* pArticle;
		int nTag, nStart, nEnd;

		while(::WaitForSingleObject(hIsRetrieving,0) == WAIT_OBJECT_0) {
			//retrieve one line at a time
			if(pHttpFile->ReadString(strLine) == FALSE) //retrieve one line at a time
				break;								 //break if no more lines left

			if ((strLine.Find("<input type") != -1) && (strLine.Find("checkbox") != -1)){//is this a 'messageheader' or a comment line?
				
				try	{
					pArticle = new CArticle;
				}
					catch(CMemoryException* me) {
					me->Delete();
					return FALSE;
				}

				pArticle->m_nCanBeDeleted = LISTCTRLARTICLES;
				pArticle->m_nStatus = ARTICLE_NOTQUEUED;
				pArticle->m_nAttempts = 0;
				pArticle->m_strPath = "";
				pArticle->m_nNewsProvider = EASYNEWS;
				
				//Date
				pArticle->m_strDate.Format("%d", nDay);
				
				//URL
				nTag = strLine.Find("<a href=", strLine.Find("<input type"));
				
				int nAuthor = strLine.Find("<br>");
				if (nAuthor != -1){
					if (nAuthor < nTag)
						strAuthor = strLine.Left(nAuthor);
				}

				pArticle->m_strAuthor = strAuthor;

				nStart = nTag + 9;
				nEnd = strLine.Find(">", nStart) - 1;
				pArticle->m_strURL = strLine.Mid(nStart, (nEnd-nStart)); 
				
				nStart = nEnd + 2;
				nEnd = strLine.Find('<', nStart);
				
				strTemp = strLine.Mid(nStart, (nEnd-nStart));
				
				pArticle->m_strSubject = strTemp;

				nStart = strTemp.ReverseFind('-');
				nEnd = strTemp.GetLength() - 2;

				strTemp = strTemp.Right(nEnd - nStart);

				int nIndex;
				int nMultiplier = 1;
				CString	strBegin, strEnd;

				if (strTemp.Find("K") != -1){
					nMultiplier = 1000;

				}

				if (strTemp.Find("M") != -1){
					nMultiplier = 100000;
						
				}
				pArticle->m_strPossibleFilename = strTemp;
				strTemp = strTemp.SpanExcluding("BKM");
				
				nIndex = strTemp.Find('.');
				int nSize;
				if (nIndex != -1){
					
					strBegin = strTemp.Left(nIndex);
					strEnd = strTemp.Right(strTemp.GetLength() - nIndex - 1);
					strTemp = strBegin + strEnd;
					nSize = atoi(strTemp);
					pArticle->m_nSize = nSize * nMultiplier;
				}
				else{
					nSize = atoi(strTemp);
					if (nSize == 0) nSize = 1;
					pArticle->m_nSize = nSize * nMultiplier;
				}

				pArticle->m_strSubject = pArticle->m_strSubject.Left(pArticle->m_strSubject.ReverseFind('-'));
				
				nStart = pArticle->m_strSubject.ReverseFind('-');
				nEnd = pArticle->m_strSubject.GetLength() - 1;
				if (nStart != -1){

					pArticle->m_strPossibleFilename = pArticle->m_strSubject.Right(nEnd - nStart);
					pArticle->m_strPossibleFilename.TrimLeft();
					pArticle->m_strPossibleFilename.TrimRight();
				}

				//Clean-up HTML code
				pArticle->m_strAuthor.Replace("&amp;","&");
				pArticle->m_strAuthor.Replace("&lt;","<");
				pArticle->m_strSubject.Replace("&amp;","&");
				pArticle->m_strSubject.Replace("&lt;","<");

				::PostMessage(hView, WM_HEADER_DL_COMPLETE, 0, (LPARAM)pArticle);
			}
		}
	}
	
	catch(CInternetException* e) {
		e->Delete();
	}

	if (pHttpFile != NULL){
		pHttpFile->Close();
		delete pHttpFile; // closes the file -- prints a warning
	}

	nDay++;
	if 	(::WaitForSingleObject(hIsRetrieving,0) == WAIT_OBJECT_0){
		
		CString strStart, strEnd, strTemp;
		int nStart, nEnd, nDash;

		nStart = strNewsgroup.ReverseFind('/') + 1; // include the slash
		nDash = strNewsgroup.ReverseFind('-') - 1; // include the dash
		if (nStart > nDash) nDash = nStart;
		nEnd = strNewsgroup.GetLength() - 1;

		strStart = strNewsgroup.Left(nStart);
		strEnd = strNewsgroup.Right(nEnd - nDash);

		strNewsgroup.Format("%s%d%s", strStart, nDay, strEnd);

		goto start;
	}

	ResetEvent(hIsRetrieving);
	::PostMessage(hView, WM_HEADER_DL_COMPLETE, 1, 0);

	return 0;
}