📄 excerpt.cpp
字号:
// 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 + -