updatemanager.cpp
字号:
/*____________________________________________________________________________
FreeAmp - The Free MP3 Player
Portions Copyright (C) 1999 EMusic.com
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: updatemanager.cpp,v 1.12 1999/12/14 19:10:11 elrod Exp $
____________________________________________________________________________*/
// The debugger can't handle symbols more than 255 characters long.
// STL often creates symbols longer than that.
// When symbols are longer than 255 characters, the warning is disabled.
#ifdef WIN32
#pragma warning(disable:4786)
#endif
#include <assert.h>
#ifdef WIN32
#include <io.h>
#else
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#endif
#if defined(unix) || defined(__BEOS__)
#define SOCKET int
#endif
#if defined(unix)
#include <arpa/inet.h>
#define closesocket(x) close(x)
#define O_BINARY 0
#endif
#if !defined(WIN32)
#include <strstream>
typedef ostrstream ostringstream;
#else
#include <sstream>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <fcntl.h>
#include <errno.h>
#include <iostream>
#include <algorithm>
#include "config.h"
#include "facontext.h"
#include "errors.h"
#include "updatemanager.h"
#include "utility.h"
#include "event.h"
#include "eventdata.h"
#include "zlib.h"
#include "mutex.h"
#include "semaphore.h"
const char* kUpdateServer = BRANDING_UPDATE_SERVER;
const char* kUpdatePath = BRANDING_UPDATE_PATH;
const char* kUpdateFile = BRANDING_UPDATE_PATH"/version_info.xml";
const char* kUpdateRequest = "GET %s HTTP/1.0\n"
"Host: %s\n"
"User-Agent: FreeAmp/%s\n" // we do not want to change this for branding
"\n";
const uint8 kUpdatePort = 80;
UpdateManager::UpdateManager(FAContext* context)
{
m_runUpdateThread = true;
m_context = context;
m_currentPlatform = "UNKNOWN";
m_currentArchitecture = "UNKNOWN";
}
UpdateManager::~UpdateManager()
{
uint32 index = 0;
uint32 size = 0;
UpdateItem* item = NULL;
m_runUpdateThread = false;
m_quitMutex.Acquire();
size = m_itemList.size();
for(index = 0; index < size; index++)
{
item = m_itemList[index];
if(item)
{
delete item;
}
}
}
// Functions for adding items to Update Manager
Error UpdateManager::AddItem(UpdateItem* item)
{
Error result = kError_InvalidParam;
m_mutex.Acquire();
assert(item);
if(item)
{
m_itemList.push_back(item);
//SendItemAddedMessage(item);
result = kError_NoErr;
}
m_mutex.Release();
return result;
}
Error UpdateManager::RetrieveLatestVersionInfo(UMCallBackFunction function,
void* cookie)
{
Error result = kError_AlreadyUpdating;
if(m_mutex.Acquire(0))
{
result = InternalRetrieveLatestVersionInfo(function, cookie);
if(IsntError(result))
{
if(function)
{
UMEvent event;
memset(&event, 0x00, sizeof(UMEvent));
event.type = kUMEvent_Done;
event.eventString = "Received latest version info from server.";
function(&event, cookie);
}
}
else if(result != kError_UserCancel)
{
if(function)
{
UMEvent event;
memset(&event, 0x00, sizeof(UMEvent));
event.type = kUMEvent_Error;
event.data.errorData.errorCode = result;
function(&event, cookie);
}
}
m_mutex.Release();
}
return result;
}
Error UpdateManager::InternalRetrieveLatestVersionInfo(
UMCallBackFunction function,
void* cookie)
{
Error result;
string info;
if(function)
{
UMEvent event;
memset(&event, 0x00, sizeof(UMEvent));
event.type = kUMEvent_Status;
event.eventString = "Retrieving latest version info from server...";
function(&event, cookie);
}
result = DownloadInfo(info, function, cookie);
if(IsntError(result))
{
result = ParseString(info);
}
return result;
}
bool UpdateManager::IsUpdateAvailable()
{
bool result = false;
if(m_mutex.Acquire(0))
{
UpdateItem* item;
vector<UpdateItem*>::iterator i = m_itemList.begin();
for (; i != m_itemList.end(); i++)
{
uint32 localMajorVersion, currentMajorVersion;
uint32 localMinorVersion, currentMinorVersion;
uint32 localRevisionVersion, currentRevisionVersion;
uint32 localFileVersion, currentFileVersion;
int32 numFields;
item = *i;
numFields = sscanf(item->GetLocalFileVersion().c_str(),
"%lu.%lu.%lu.%lu",
&localMajorVersion,&localMinorVersion,
&localRevisionVersion, &localFileVersion);
if(numFields < 4)
localFileVersion = 0;
if(numFields < 3)
localRevisionVersion = 0;
if(numFields < 2)
localMinorVersion = 0;
if(numFields < 1)
localMajorVersion = 0;
numFields = sscanf(item->GetCurrentFileVersion().c_str(),
"%lu.%lu.%lu.%lu",
¤tMajorVersion,¤tMinorVersion,
¤tRevisionVersion, ¤tFileVersion);
if(numFields < 4)
currentFileVersion = 0;
if(numFields < 3)
currentRevisionVersion = 0;
if(numFields < 2)
currentMinorVersion = 0;
if(numFields < 1)
currentMajorVersion = 0;
// is the version on the server more recent?
if( (currentMajorVersion > localMajorVersion) ||
(currentMajorVersion == localMajorVersion &&
currentMinorVersion > localMinorVersion) ||
(currentMajorVersion == localMajorVersion &&
currentMinorVersion == localMinorVersion &&
currentRevisionVersion > localRevisionVersion) ||
(currentMajorVersion == localMajorVersion &&
currentMinorVersion == localMinorVersion &&
currentRevisionVersion == localRevisionVersion &&
currentFileVersion > localFileVersion))
{
result = true;
break;
}
}
}
return result;
}
Error UpdateManager::UpdateComponents(UMCallBackFunction function,
void* cookie)
{
Error result = kError_AlreadyUpdating;
if(m_mutex.Acquire(0))
{
uint32 downloadCount = 0;
// make sure we have latest info
//result = InternalRetrieveLatestVersionInfo(function, cookie);
result = kError_NoErr;
if(IsntError(result))
{
UpdateItem* item;
vector<UpdateItem*>::iterator i = m_itemList.begin();
// go thru list of components and see if
// there are newer versions
for (; i != m_itemList.end(); i++)
{
uint32 localMajorVersion, currentMajorVersion;
uint32 localMinorVersion, currentMinorVersion;
uint32 localRevisionVersion, currentRevisionVersion;
uint32 localFileVersion, currentFileVersion;
int32 numFields;
item = *i;
numFields = sscanf(item->GetLocalFileVersion().c_str(),
"%lu.%lu.%lu.%lu",
&localMajorVersion,&localMinorVersion,
&localRevisionVersion, &localFileVersion);
if(numFields < 4)
localFileVersion = 0;
if(numFields < 3)
localRevisionVersion = 0;
if(numFields < 2)
localMinorVersion = 0;
if(numFields < 1)
localMajorVersion = 0;
numFields = sscanf(item->GetCurrentFileVersion().c_str(),
"%lu.%lu.%lu.%lu",
¤tMajorVersion,¤tMinorVersion,
¤tRevisionVersion, ¤tFileVersion);
if(numFields < 4)
currentFileVersion = 0;
if(numFields < 3)
currentRevisionVersion = 0;
if(numFields < 2)
currentMinorVersion = 0;
if(numFields < 1)
currentMajorVersion = 0;
// is the version on the server more recent?
if( (currentMajorVersion > localMajorVersion) ||
(currentMajorVersion == localMajorVersion &&
currentMinorVersion > localMinorVersion) ||
(currentMajorVersion == localMajorVersion &&
currentMinorVersion == localMinorVersion &&
currentRevisionVersion > localRevisionVersion) ||
(currentMajorVersion == localMajorVersion &&
currentMinorVersion == localMinorVersion &&
currentRevisionVersion == localRevisionVersion &&
currentFileVersion > localFileVersion))
{
result = DownloadItem(item, function, cookie);
if(IsntError(result))
{
downloadCount++;
}
else
{
break;
}
}
}
}
if(IsntError(result))
{
if(function)
{
UMEvent event;
memset(&event, 0x00, sizeof(UMEvent));
event.type = kUMEvent_Done;
if(downloadCount)
event.eventString = "Finished retrieving latest components.";
else
event.eventString = "There are no new versions available at this time.";
function(&event, cookie);
}
}
else if(result != kError_UserCancel)
{
if(function)
{
UMEvent event;
memset(&event, 0x00, sizeof(UMEvent));
event.type = kUMEvent_Error;
event.data.errorData.errorCode = result;
function(&event, cookie);
}
}
if(!downloadCount)
result = kError_NoItemsUpdated;
m_mutex.Release();
}
return result;
}
const uint8 kHttpPort = 80;
const uint32 kMaxHostNameLen = 64;
Error UpdateManager::DownloadInfo(string& info,
UMCallBackFunction function,
void* cookie)
{
Error result = kError_NoErr;
char hostname[kMaxHostNameLen + 1];
char localname[kMaxHostNameLen + 1];
char proxyname[kMaxHostNameLen + 1];
unsigned short port;
struct sockaddr_in addr;
struct hostent host;
SOCKET s = -1;
bool useProxy;
const char* file = NULL;
uint32 length;
m_context->prefs->GetUseProxyServer(&useProxy);
length = sizeof(proxyname);
m_context->prefs->GetProxyServerAddress(proxyname, &length);
if(useProxy)
{
int32 numFields;
numFields = sscanf(proxyname,
"http://%[^:/]:%hu", hostname, &port);
sprintf(proxyname, "http://%s%s", kUpdateServer, kUpdateFile);
file = proxyname;
if(numFields < 1)
result = kError_InvalidURL;
if(numFields < 2)
port = kHttpPort;
}
else
{
strcpy(hostname, kUpdateServer);
port = kUpdatePort;
file = kUpdateFile;
}
if(function)
{
UMEvent event;
memset(&event, 0x00, sizeof(UMEvent));
event.type = kUMEvent_Status;
event.eventString = "Looking up server address...";
bool ok = function(&event, cookie);
if(!ok)
result = kError_UserCancel;
}
// get hostname
if(IsntError(result))
{
struct hostent* hostByName;
struct hostent hostByIP;
hostByName = gethostbyname(hostname);
// On some stacks a numeric IP address
// will not parse with gethostbyname.
// If that didn't work try to convert it as a
// numeric address before giving up.
if(!hostByName)
{
static unsigned long ip;
static char *addr_ptr[2] = {(char*)&ip, NULL};
if((ip = inet_addr(hostname)) < 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -