//
// VersionChecker.h
//
// Copyright (c) Shareaza Development Team, 2002-2005.
// This file is part of SHAREAZA (www.shareaza.com)
//
// Shareaza 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.
//
// Shareaza 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 Shareaza; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#if !defined(AFX_VERSIONCHECKER_H__EB5F6233_9917_44C3_BE67_CACB43D929CA__INCLUDED_)
#define AFX_VERSIONCHECKER_H__EB5F6233_9917_44C3_BE67_CACB43D929CA__INCLUDED_
#pragma once
#include "HttpRequest.h"
class CVersionChecker
{
// Construction
public:
CVersionChecker();
virtual ~CVersionChecker();
// Attributes
public:
CString m_sMessage;
CString m_sQuote;
BOOL m_bUpgrade;
CString m_sUpgradePrompt;
CString m_sUpgradeFile;
CString m_sUpgradeSHA1;
CString m_sUpgradeTiger;
CString m_sUpgradeSize;
CString m_sUpgradeSources;
CString m_sUpgradePath;
CString m_sUpgradeVersion;
protected:
HANDLE m_hThread;
CHttpRequest m_pRequest;
CMapStringToString m_pResponse;
HWND m_hWndNotify;
// Operations
public:
BOOL NeedToCheck();
BOOL Start(HWND hWndNotify);
void Stop();
void SetNextCheck(int nDays);
BOOL CheckUpgradeHash(const SHA1* pHash, LPCTSTR pszPath);
protected:
static UINT ThreadStart(LPVOID pParam);
void OnRun();
void BuildRequest(CString& strRequest);
BOOL UndertakeRequest(CString& strPost);
void ProcessResponse();
};
extern CVersionChecker VersionChecker;
#endif // !defined(AFX_VERSIONCHECKER_H__EB5F6233_9917_44C3_BE67_CACB43D929CA__INCLUDED_)
//
// VersionChecker.cpp
//
// Copyright (c) Shareaza Development Team, 2002-2005.
// This file is part of SHAREAZA (www.shareaza.com)
//
// Shareaza 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.
//
// Shareaza 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 Shareaza; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#include "StdAfx.h"
#include "Shareaza.h"
#include "Settings.h"
#include "VersionChecker.h"
#include "Transfer.h"
#include "Network.h"
#include "GProfile.h"
#include "DiscoveryServices.h"
#include "SHA.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
CVersionChecker VersionChecker;
//默认每隔七天升级一次
#define VERSIONCHECKER_FREQUENCY 7
//
// CVersionChecker construction
CVersionChecker::CVersionChecker()
{
m_bUpgrade = FALSE;
m_hThread = NULL;
m_hWndNotify = NULL;
}
CVersionChecker::~CVersionChecker()
{
Stop();
}
//
// CVersionChecker time check
/*
从注册表中读取出各个属性的值,填充到当前对象,
如果是用户手动升级,则将各个变量清空。
如果当前时间超过了下一次升级的时间,则需要升级,否则不需要升级
*/
BOOL CVersionChecker::NeedToCheck()
{
m_sUpgradeVersion =
theApp.GetProfileString( _T("VersionCheck"),
_T("UpgradeVersion"), _T("") );
DWORD nNextCheck = theApp.GetProfileInt( _T("VersionCheck"),
_T("NextCheck"), 0 );
if ( theApp.m_sVersion.Compare( m_sUpgradeVersion ) >= 0 ) // user manually upgraded
{
//用户手动升级,将各个变量清空,然后返回
theApp.WriteProfileString( _T("VersionCheck"),
_T("UpgradePrompt"), NULL );
theApp.WriteProfileString( _T("VersionCheck"),
_T("UpgradeFile"), NULL );
theApp.WriteProfileString( _T("VersionCheck"),
_T("UpgradeSHA1"), NULL );
theApp.WriteProfileString( _T("VersionCheck"),
_T("UpgradeTiger"), NULL);
theApp.WriteProfileString( _T("VersionCheck"),
_T("UpgradeSize"), NULL );
theApp.WriteProfileString( _T("VersionCheck"),
_T("UpgradeSources"), NULL );
theApp.WriteProfileString( _T("VersionCheck"),
_T("UpgradeVersion"), NULL );
//如果当前时间超过了需要升级的时间,则需要升级,返回true
return (DWORD)CTime::GetCurrentTime().GetTime() >= nNextCheck;
}
if ( !Settings.General.UpdateCheck )//没有设置,返回false
{
return FALSE;
}
//从注册表中读取出各个属性的值,填充到各个属性中
m_sQuote = theApp.GetProfileString( _T("VersionCheck"),
_T("Quote"), _T("") );
m_sUpgradePrompt =
theApp.GetProfileString( _T("VersionCheck"),
_T("UpgradePrompt"), _T("") );
m_sUpgradeFile =
theApp.GetProfileString( _T("VersionCheck"),
_T("UpgradeFile"), _T("") );
m_sUpgradeSHA1 =
theApp.GetProfileString( _T("VersionCheck"),
_T("UpgradeSHA1"), _T("") );
m_sUpgradeTiger =
theApp.GetProfileString( _T("VersionCheck"),
_T("UpgradeTiger"), _T("") );
m_sUpgradeSize =
theApp.GetProfileString( _T("VersionCheck"),
_T("UpgradeSize"), _T("") );
m_sUpgradeSources =
theApp.GetProfileString( _T("VersionCheck"),
_T("UpgradeSources"), _T("") );
m_bUpgrade = ( m_sUpgradePrompt.GetLength() > 0 );
//如果nNextCheck为0,则需要升级,如果为0XFFFFFFFF则不需要升级
if ( ! nNextCheck )
{
return TRUE;
}
if ( nNextCheck == 0xFFFFFFFF )
{
return FALSE;
}
//如果当前时间超过了下一次升级的时间,则需要升级,否则不需要升级
return (DWORD)CTime::GetCurrentTime().GetTime() >= nNextCheck;
}
//
// CVersionChecker start
BOOL CVersionChecker::Start(HWND hWndNotify)
{
//首先停止原来的线程,取消http请求,然后开一个线程开始升级
Stop();
m_pRequest.Clear();
//m_hWndNotify指向需要通知的窗口
m_hWndNotify = hWndNotify;
m_bUpgrade = FALSE;
//创建一个线程,启动之,开始升级过程
CWinThread* pThread = AfxBeginThread( ThreadStart,
this, THREAD_PRIORITY_IDLE );
m_hThread = pThread->m_hThread;
return TRUE;
}
//
// CVersionChecker stop
//首先取消httpRequest对象,然后关闭升级线程
void CVersionChecker::Stop()
{
m_pRequest.Cancel();
CHttpRequest::CloseThread( &m_hThread, _T("CVersionChecker") );
}
//
// CVersionChecker thread bootstrap
//执行OnRun函数完成升级过程
UINT CVersionChecker::ThreadStart(LPVOID pParam)
{
CVersionChecker* pClass = (CVersionChecker*)pParam;
pClass->OnRun();
return 0;
}
//
// CVersionChecker thread run
void CVersionChecker::OnRun()
{
CString strRequest;
//加入version字符串
BuildRequest( strRequest );
//访问指定的URI,获得返回结果,并设置m_pResponse各项的内容
BOOL bRequest = UndertakeRequest( strRequest );
if ( bRequest ) // 成功了,调用PrcessResponse处理响应
{
//根据m_pResponse的内容写入注册表,同时向notify窗口发送VERSIONCHECK消息
ProcessResponse();
m_pResponse.RemoveAll(); // 检查结束了,释放m_pResponse占用的空间
}
else // 失败了,设置下一次升级的事件
{
SetNextCheck( VERSIONCHECKER_FREQUENCY );
}
}
//
// CVersionChecker build request
//在参数strRequest的后面加入version=3.0字符串
void CVersionChecker::BuildRequest(CString& strRequest)
{
strRequest += _T("Version=");
strRequest += theApp.m_sVersion;
}
//
// CVersionChecker undertake request
/*
访问_T("http://update.trillinux.org/version/beta.php?") + strPost网址
然后根据返回的响应字符串设置m_pResponse的各项内容
*/
BOOL CVersionChecker::UndertakeRequest(CString& strPost)
{
m_pRequest.SetURL( _T("http://update.trillinux.org/version/beta.php?") + strPost );
//Remember to set the update server for final releases.
//连接到上面设置的uri地址
if ( ! m_pRequest.Execute( FALSE ) )
{
return FALSE;
}
//检查返回状态
int nStatusCode = m_pRequest.GetStatusCode();
if ( nStatusCode < 200 || nStatusCode > 299 )//返回了错误码,则返回false
{
return FALSE;
}
//strResponse保存了返回的响应结果字符串
CString strResponse = m_pRequest.GetResponseString();
//如果VersionCheck下的TestResponse子键被设置了,则设置strResponse为strHack
CString strHack = theApp.GetProfileString( _T("VersionCheck"),
_T("TestResponse"), _T("") );
if ( strHack.GetLength() )
{
strResponse = strHack;
}
//根据返回的响应字符串设置m_pResponse各个项的内容
//reponse字符串的格式为“strkey=strItem&strkey1=strItem1”
//为了保证最后一个也处理,首先给strResponse加上一个&结尾
for ( strResponse += '&' ; strResponse.GetLength() ; )
{
//首先按照&切割字符串
CString strItem = strResponse.SpanExcluding( _T("&") );
strResponse = strResponse.Mid( strItem.GetLength() + 1 );
CString strKey = strItem.SpanExcluding( _T("=") );
if ( strKey.GetLength() == strItem.GetLength() )
{
continue;
}
//strItem是&后面的部分,调用CTransfer的URLDecode完成解码
strItem = CTransfer::URLDecode( strItem.Mid( strKey.GetLength() + 1 ) );
strItem.TrimLeft();
strItem.TrimRight();
m_pResponse.SetAt( strKey, strItem );
}
return TRUE;
}
//
// CVersionChecker process response
//根据reponse各项的内容来设置各项属性的值,并更新注册表,最后向notify窗口发送
//versioncheck消息
void CVersionChecker::ProcessResponse()
{
int nDays = VERSIONCHECKER_FREQUENCY;
CString strValue;
//如果m_pResponse中有Message或者MessageBox字符串,则设置m_sMessage
//为Response中字符串对应的CString值
if ( m_pResponse.Lookup( _T("Message"), strValue )
|| m_pResponse.Lookup( _T("MessageBox"), strValue ) )
{
m_sMessage = strValue;
}
//如果response中有quote,则设置m_sQuote为对应的值,同时写入
//注册表VersionCheck下的Quote子键
if ( m_pResponse.Lookup( _T("Quote"), strValue ) )
{
m_sQuote = strValue;
theApp.WriteProfileString( _T("VersionCheck"),
_T("Quote"), m_sQuote );
}
//Response中有SystemMsg,则执行之
if ( m_pResponse.Lookup( _T("SystemMsg"), strValue ) )
{
//各个系统消息使用/r/n来分隔,依次调用app类的Message方法
for ( strValue += '/n' ; strValue.GetLength() ; )
{
CString strLine = strValue.SpanExcluding( _T("/r/n") );
strValue = strValue.Mid( strLine.GetLength() + 1 );
if ( strLine.GetLength() )
{
theApp.Message( MSG_SYSTEM, strLine );
}
}
}
//response中有upgradeprompt属性,则将各个相关项的value
//保存到各个属性中,同时将新的属性值写入注册表
if ( m_pResponse.Lookup( _T("UpgradePrompt"), strValue ) )
{
m_sUpgradePrompt = strValue;
m_pResponse.Lookup( _T("UpgradeFile"), m_sUpgradeFile );
m_pResponse.Lookup( _T("UpgradeSHA1"), m_sUpgradeSHA1 );
m_pResponse.Lookup( _T("UpgradeTiger"), m_sUpgradeTiger );
m_pResponse.Lookup( _T("UpgradeSize"), m_sUpgradeSize );
m_pResponse.Lookup( _T("UpgradeSources"), m_sUpgradeSources );
m_pResponse.Lookup( _T("UpgradeVersion"), m_sUpgradeVersion );
// Old name
if ( ! m_sUpgradeSHA1.GetLength() )
{
m_pResponse.Lookup( _T("UpgradeHash"), m_sUpgradeSHA1 );
}
theApp.WriteProfileString( _T("VersionCheck"),
_T("UpgradePrompt"), m_sUpgradePrompt );
theApp.WriteProfileString( _T("VersionCheck"),
_T("UpgradeFile"), m_sUpgradeFile );
theApp.WriteProfileString( _T("VersionCheck"),
_T("UpgradeSHA1"), m_sUpgradeSHA1 );
theApp.WriteProfileString( _T("VersionCheck"),
_T("UpgradeTiger"), m_sUpgradeTiger);
theApp.WriteProfileString( _T("VersionCheck"),
_T("UpgradeSize"), m_sUpgradeSize );
theApp.WriteProfileString( _T("VersionCheck"),
_T("UpgradeSources"), m_sUpgradeSources );
theApp.WriteProfileString( _T("VersionCheck"),
_T("UpgradeVersion"), m_sUpgradeVersion );
m_bUpgrade = TRUE; // 升级成功了
}
else // 没有,则写入空值,没有升级成功
{
theApp.WriteProfileString( _T("VersionCheck"),
_T("UpgradePrompt"), _T("") );
m_bUpgrade = FALSE;
}
//如果设置了adddiscovery,则在DiscoveryServices中
//作为dsWebCache加入新的strValue
if ( m_pResponse.Lookup( _T("AddDiscovery"), strValue ) )
{
strValue.TrimLeft();
strValue.TrimRight();
DiscoveryServices.Add( strValue, CDiscoveryService::dsWebCache );
}
//如果response连下一次升级所隔的天数也设置了,则写入天数nDays
if ( m_pResponse.Lookup( _T("NextCheck"), strValue ) )
{
_stscanf( strValue, _T("%lu"), &nDays );
}
//根据天数算出下一次升级的时间,并写入注册表
SetNextCheck( nDays );
//向m_hWndNotify窗口发送WM_VERSIONCHECK消息,升级完毕了
PostMessage( m_hWndNotify, WM_VERSIONCHECK, 0, 0 );
}
//
// CVersionChecker NextCheck update
//设定下一次升级时的时间,写入注册表VersionCheck 的NextCheck子键下。
void CVersionChecker::SetNextCheck(int nDays)
{
//在nDays天后再次升级
CTimeSpan tPeriod( nDays, 0, 0, 0 );
//再次升级的时间,tNextCheck.GetTime()返回一个_time_64_t,转化为DWORD
CTime tNextCheck = CTime::GetCurrentTime() + tPeriod;
theApp.WriteProfileInt( _T("VersionCheck"),
_T("NextCheck"), (DWORD)tNextCheck.GetTime() );
}
//
// CVersionChecker check if a download is an upgrade
BOOL CVersionChecker::CheckUpgradeHash(const SHA1* pHash, LPCTSTR pszPath)
{
if ( ! m_bUpgrade ) // upgrade为false,直接返回
{
return FALSE;
}
//将参数pHash转化为字符串后和m_sUpgradeSHA1 不一样,返回false
if ( CSHA::HashToString( pHash ) != m_sUpgradeSHA1 )
{
return FALSE;
}
//参数pszPath不是exe文件,返回false
if ( _tcsstr( pszPath, _T(".exe") ) == NULL )
{
return FALSE;
}
//pszPath是exe文件,将m_sUpgradePath设置为参数pszPath
m_sUpgradePath = pszPath;
//向主窗口发送WM_VERSIONCHECK消息
AfxGetMainWnd()->PostMessage( WM_VERSIONCHECK, 2 );
return TRUE;
}