⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 excerpt.cpp

📁 一个邮件客户端源代码,包括收发邮件,安排日程等很多内容
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// Copyright (C) 1997-2002 Valeriy Ovechkin
// 
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// Excerpt.cpp : implementation file
//
/////////////////////////////////////////////////////////////////////
//
//   File : Excerpt.cpp
//   Description : message entity
//
//   Modification history ( date, name, description ) : 
//		1.	15.12.2002	Igor Green, mmm3@grigsoft.com
//		  1.1	Extracting ReplyTo field, KOI8 and UTF8 subjects
//		  1.2	QuickLoad, fixed bug with QuickView if file was deleted
//		2.	17.12.2002	Igor Green, mmm3@grigsoft.com
//			Added partial load support
//
//HISTORY_ENTRY_END:2!17.12.2002
/////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Magic.h"
#include "Excerpt.h"
#include "Mailbox.h"
#include "MagicDoc.h"
#include "MagicFrame.h"
#include "MIME.h"
#include "tools.h"
#include "base64.h"
#include "cregexp.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

static const char FROM[] = "from:";
static const char SUBJECT[] = "subject:";
static const char DATE[] = "date:";
static const char REPLYTO[] = "reply-to:";
static const char PRIORITY[] = "x-priority:";
static const char S_TO[] = "to:";
static const char S_CONTENT[] = "content-type:";

static
const char months[][4] = {	"Jan", "Feb", "Mar", "Apr", 
							"May", "Jun", "Jul", "Aug", 
							"Sep", "Oct", "Nov", "Dec" };


CTimeSpan CExcerpt::tsLocalTimeAdjustment;
int CExcerpt::intLocalTimeAdjustmentSign;

/////////////////////////////////////////////////////////////////////////////
// CExcerpt

IMPLEMENT_DYNAMIC( CExcerpt, CObject );

CExcerpt::CExcerpt( CMailbox *pMailbox )
:	m_hDataFile( INVALID_HANDLE_VALUE ),
	m_hViewer(0),
	m_intSize(0),
	m_intOrder(0),
	m_bitWasReported(0),
	m_bitFilled(0),
	m_bitDownloadData(0),
	m_bitDownloaded(0),
	m_bitQuickView(0),
	m_bitViewText(0),
	m_bitRemoveFromServer(0),
	m_bitCreated(1),
	m_bitDeleted(0),
	m_bitPreviewData(0),
	m_bitPreviewLoaded(0),
	m_pMailbox( pMailbox ),
	m_intChanged(-1),
	m_tmDate( 1971, 1, 1, 1, 1, 1 ),
	m_nIsParsingColumn( 0 )
{
	m_strSubject = m_strFrom = m_strFromName = _T("...");
	m_asRawHeader.SetSize(0, 20);
	m_nPreviewLines = 0;
	m_nPreviewSize = 0;
	m_nLoadedSize = 0;
	m_nPriority = 0;
	
	if (theApp.intMarkRead == READ_ALWAYS)
		m_bitWasRead = 1;
	else
		m_bitWasRead = 0;


	static bool bStaticInitialize = true;
	if( bStaticInitialize )
	{
		bStaticInitialize = false;
		// figure out the local time adjustment
		TIME_ZONE_INFORMATION tz = {0};

		DWORD dwResult = GetTimeZoneInformation( &tz );

		if( dwResult == TIME_ZONE_ID_STANDARD )
		{
			tz.Bias += tz.StandardBias;
		}
		else if( dwResult == TIME_ZONE_ID_DAYLIGHT )
		{
			tz.Bias += tz.DaylightBias;
		}

		if( 0 != tz.Bias )
		{
			intLocalTimeAdjustmentSign = -tz.Bias;

			if( tz.Bias < 0 ) 
			{
				tz.Bias = -tz.Bias;
			}

			tsLocalTimeAdjustment = CTimeSpan( 0, tz.Bias / 60, tz.Bias % 60, 0 );
		}
	}
	m_dwFiltered = 0;
	m_Color = 0;
}

CExcerpt::~CExcerpt()
{
	m_bitDeleted = 1;
	Change( COLUMN_MBOX );

	CWnd *wnd = (CWnd*) AfxGetMainWnd();
	if( wnd ) wnd->SendMessage( VM_UPDATEITEM, (WPARAM) this );

	if( INVALID_HANDLE_VALUE != m_hDataFile ) CloseHandle( m_hDataFile );
	if( !m_strDataFileName.IsEmpty() ) DeleteFile( m_strDataFileName );
}

//BEGIN_MESSAGE_MAP(CExcerpt, CObject)
	//{{AFX_MSG_MAP(CExcerpt)
		// NOTE - the ClassWizard will add and remove mapping macros here.
	//}}AFX_MSG_MAP
//END_MESSAGE_MAP()

void CExcerpt::ParseTopLine( const char *str )
{
	m_asRawHeader.Add(str);

	if( !strnicmp( str, FROM, sizeof( FROM )-1 ) && 
		(m_strFrom.IsEmpty() || m_strFrom==_T("...")))
	{
		m_nIsParsingColumn = 0;

		str += sizeof( FROM );

		m_strFrom = str;
		m_strFrom.TrimLeft();
		m_strFrom.TrimRight();

		char *szTmp = strdup( str );

		TCHAR *left = 0, *right = 0;
		while( 
			( left = _tcschr( szTmp, _T('<') ) )!=0 && 
			( right = _tcschr( left, _T('>') ) )!=0 
			)
		{
			++right;
			while (( *(left++) = *(right++) )!=0);
		}

		while (( left = _tcschr( szTmp, _T('\"') ) )!=0)
		{
			*left = _T(' ');
		}

		m_strFromName = szTmp;
		free( szTmp );

		m_strFromName = MIMEStringDecode( m_strFromName );

		if( m_strFromName.IsEmpty() ) m_strFromName = m_strFrom;
		Change( COLUMN_FROM );
	}
	else if( !strnicmp( str, SUBJECT, sizeof( SUBJECT )-1 ) )
	{
		str += sizeof( SUBJECT );
		m_strSubject = str;
		
		m_nIsParsingColumn = COLUMN_SUBJ;
	}
	else if( !strnicmp( str, S_CONTENT, sizeof( S_CONTENT )-1 ) && m_strContent.IsEmpty())
	{
		str += sizeof( S_CONTENT );
		m_strContent = str;

		m_nIsParsingColumn = 0;
	}
	else if( !strnicmp( str, S_TO, sizeof( S_TO )-1 ) )
	{
		m_nIsParsingColumn = COLUMN_TO;

		str += sizeof( S_TO );
		m_strToName = str;
		m_strToName.TrimLeft();
		m_strToName.TrimRight();
		Change( COLUMN_TO );
	}
	else if( !strnicmp( str, PRIORITY, sizeof( PRIORITY)-1 ) )
	{
		str += sizeof( PRIORITY );
		m_nPriority = _ttoi(str);
	}
	else if( !strnicmp( str, REPLYTO, sizeof( REPLYTO )-1 ) )
	{
		str += sizeof( REPLYTO );
		m_sReplyTo = str;
		m_sReplyTo.TrimLeft();
		m_sReplyTo.TrimRight();
	}
	else if( ( *str == '\t' || *str == ' ') && m_nIsParsingColumn == COLUMN_SUBJ)
	{
		if (*str == '\t')
			str++;
		m_strSubject += str;
	}
	else if( ( *str == '\t' || *str == ' ') && m_nIsParsingColumn == COLUMN_TO)
	{
		if (*str == '\t')
			str++;
		m_strToName += str;
	}
	else if( !strnicmp( str, DATE, sizeof( DATE )-1 ) )
	{
		m_nIsParsingColumn = 0;

		str += sizeof( DATE );
		while( ' ' == *str || '\t' == *str ) ++str;
		if( 5 < strlen( str ) && ( str[3] == ',' ) ) str += 5;

		char szMonth[4] = "";
		char szTimeZone[6] = "";
		int intYear = 1970, intDay = 1, intHour = 0, intMin = 0, intSec = 0;
		if( 6 > sscanf( str, "%d %3s %d %d:%d:%d %5s", &intDay, szMonth, &intYear, &intHour, &intMin, &intSec, szTimeZone ) ) 
			return;

		// figure out the pivot point
		if( intYear < 50 )
		{
			intYear += 2000;
		}
		else if( intYear < 100 )
		{
			intYear += 1900;
		}
		else if( intYear == 100 )
		{
			// fix the Y2K glitch
			intYear = 2000;
		}
		
		// time correction. Could be ["AM"|"PM"] or ["+"|"-","XXXX"]
		if( 0 == stricmp( szTimeZone, "PM" ) )
		{
			intHour += 12;
		}

		CTimeSpan oTimeCorrection;
		if( szTimeZone[0] == '+' || szTimeZone[0] == '-' )
		{	
			char szHour[3] = { szTimeZone[1], szTimeZone[2] };
			char szMin[3] = { szTimeZone[3], szTimeZone[4] };
			
			oTimeCorrection = CTimeSpan( 0, atoi(szHour), atoi(szMin), 0 );
		}

//		ASSERT( szMonth[0] );
		int intMonth = sizeof( months ) / sizeof( months[0] ); 
		while( intMonth )
		{
			if( !strnicmp( szMonth, months[ --intMonth ], 3 ) ) break;
		}
		++intMonth;

		m_tmDate = CTime( intYear, intMonth, intDay, intHour, intMin, intSec );
		if( szTimeZone[0] == '+' )
		{
			m_tmDate -= oTimeCorrection;
		}
		else if( szTimeZone[0] == '-' )
		{
			m_tmDate += oTimeCorrection;
		}

		//
		// adjust from UTC/GMT to local time
		//
		if(	0 != intLocalTimeAdjustmentSign )
		{
			if( 0 < intLocalTimeAdjustmentSign )
			{
				m_tmDate += tsLocalTimeAdjustment;
			}
			else
			{
				m_tmDate -= tsLocalTimeAdjustment;
			}
		}

		Change( COLUMN_DATE );
	}
	else
	{
		m_nIsParsingColumn = 0;
	}

	Change( COLUMN_SIZE );
}

void CExcerpt::NoMoreTopLines()
{
	m_bitFilled = 1;

	m_strSubject = MIMEStringDecode( m_strSubject );
	m_strToName = MIMEStringDecode( m_strToName );
	
	// process encoding as separate header field, without ?=koi8
	PostProcessMessage();

	if (theApp.intEnableFilters)
		CheckByFilters();

	Change( COLUMN_MBOX );
	Change( COLUMN_SUBJ );
	Change( COLUMN_TO);
}
BOOL SearchForText(CStringArray& ar, LPCTSTR sText)
{
	for (int i=0; i<ar.GetSize(); i++)
	{
		if (FindIgnoreCase(ar[i], sText))
			return TRUE;
	}
	return FALSE;
}

void CExcerpt::PostProcessMessage()
{
	CStringArray asValues;
	ExtractHeaderData("content-type:", asValues);
	if (!SearchForText(asValues, "koi8-r"))
		return;
	// check if fields have encoding within text
	asValues.RemoveAll();
	ExtractHeaderData("subject:", asValues);
	if (!SearchForText(asValues, "=?koi8-r?"))
	{
		KOI8ToWin(m_strSubject);
	}
	asValues.RemoveAll();
	ExtractHeaderData("from:", asValues);
	if (!SearchForText(asValues, "=?koi8-r?"))
	{
		KOI8ToWin(m_strFromName);
	}
	ExtractHeaderData("to:", asValues);
	if (!SearchForText(asValues, "=?koi8-r?"))
	{
		KOI8ToWin(m_strToName);
	}
}

void CExcerpt::RecheckByFilters()
{
	m_sFilters.Empty();
	m_dwFiltered = 0;
	m_bitRemoveFromServer = 0;

	CheckByFilters();

	Change( COLUMN_MBOX);
	Change( COLUMN_SUBJ);
}

void CExcerpt::ApplyFilterAction(const CMailFilter& mf)
{
	if (mf.m_dwAction & MFA_READ)
	{
		m_bitWasRead = 1;
		m_bitWasReported = 1;	// avoid reporting such mail
	}
	if (mf.m_dwAction & MFA_COLOR)
	{
		m_dwFiltered |= MFA_COLOR;
		m_Color = mf.m_Color;
	}
	if (mf.m_dwAction & MFA_SPAM)
	{
		m_dwFiltered |= MFA_SPAM;
	}
	if (mf.m_dwAction & MFA_DELETE)
	{
		m_bitRemoveFromServer = 1;
		LogDeleted(mf);
	}
	m_sFilters += mf.m_sName;
	m_sFilters += _T("; ");
}

void CExcerpt::LogDeleted(const CMailFilter& mf)
{
	if ((theApp.m_dwFlags & MMF_LOG_DELETED) == 0)
		return;
	CLog log(DELLOG_FILE, theApp.m_nMaxLogSize*1024);
	log.Log("\n---\nFrom:%s\nTo:%s\nSubject:%s\n", 
		m_strFrom.Left(100), m_strToName.Left(100), m_strSubject.Left(100));
	CTime time = CTime::GetCurrentTime();
	log.Log("Date:%s\nDeleted on: %s from <%s>\nFilter:%s\n---\n", 
		m_tmDate.Format("%B %d, %Y, %H:%M:%S"), time.Format("%B %d, %Y, %H:%M:%S"),
		m_pMailbox ? m_pMailbox->m_strAlias:"?", mf.m_sName);
}

BOOL CExcerpt::IsFromFriend()
{
	CStringArray asData;
	if (!LoadTextFile(FRIENDS_FILE, asData, ';'))
		return FALSE;
	// extract address from 'From'
	CString s;
	GetAddressFrom(m_strFrom, s);
	s.MakeLower();
	for (int i=0; i<asData.GetSize(); i++)
	{
		if (IsStringMatch(s, asData[i]))
			return TRUE;
	}
	return FALSE;
}
void CExcerpt::CheckByFilters()
{
	if (IsFromFriend())
	{
		m_sFilters = _T("From friend!");
		m_dwFiltered = MFA_FRIEND;
		return;
	}

	int nFilters = theApp.m_Filters.GetSize();
	for (int i=0; i<nFilters; i++)
	{
		CMailFilter& mf = theApp.m_Filters.ElementAt(i);
		if ((mf.m_dwAction & MFA_ENABLED)==0)
			continue;
		if ( !CheckByFilter(mf) )
			continue;
		ApplyFilterAction(mf);
		if ((mf.m_dwAction & MFA_OTHER)==0)
			break;
	}
}
void CExcerpt::ExtractHeaderData(LPCTSTR sField, CStringArray& ar)
{
	CString sSearch(sField);
	sSearch.MakeLower();
	for (int i=0; i<m_asRawHeader.GetSize(); i++)
	{
		CString s = m_asRawHeader[i];
		s.MakeLower();
		if (s.Find(sSearch)!=0)
			continue;
		ar.Add((LPCTSTR)s + sSearch.GetLength());
		for (int j=i+1; j<m_asRawHeader.GetSize(); j++)
		{
			s = m_asRawHeader[j];
			s.MakeLower();
			if (s.IsEmpty() || s[0]!='\t')
				break;
			ar.Add(s);
		}
		break;
	}
}

void PrepareValues(CStringArray& asValues, BOOL bCase)
{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -