mirror of
https://github.com/nzbget/nzbget.git
synced 2026-01-12 07:57:50 -05:00
706 lines
18 KiB
C++
706 lines
18 KiB
C++
/*
|
|
* This file if part of nzbget
|
|
*
|
|
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@sourceforge.net>
|
|
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
|
*
|
|
* 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.
|
|
*
|
|
* $Revision$
|
|
* $Date$
|
|
*
|
|
*/
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
#include "win32.h"
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#ifndef WIN32
|
|
#include <unistd.h>
|
|
#include <sys/socket.h>
|
|
#include <arpa/inet.h>
|
|
#include <netinet/in.h>
|
|
#endif
|
|
|
|
#include "nzbget.h"
|
|
#include "RemoteServer.h"
|
|
#include "Log.h"
|
|
#include "Options.h"
|
|
#include "QueueCoordinator.h"
|
|
#include "QueueEditor.h"
|
|
#include "PrePostProcessor.h"
|
|
#include "Util.h"
|
|
|
|
extern Options* g_pOptions;
|
|
extern QueueCoordinator* g_pQueueCoordinator;
|
|
extern PrePostProcessor* g_pPrePostProcessor;
|
|
extern void ExitProc();
|
|
|
|
const char* g_szMessageRequestNames[] =
|
|
{ "N/A", "Download", "Pause/Unpause", "List",
|
|
"Set download rate", "Dump debug", "Edit queue", "Log", "Quit"
|
|
};
|
|
|
|
const unsigned int g_iMessageRequestSizes[] =
|
|
{ 0,
|
|
sizeof(SNZBDownloadRequest),
|
|
sizeof(SNZBPauseUnpauseRequest),
|
|
sizeof(SNZBListRequest),
|
|
sizeof(SNZBSetDownloadRateRequest),
|
|
sizeof(SNZBDumpDebugRequest),
|
|
sizeof(SNZBEditQueueRequest),
|
|
sizeof(SNZBLogRequest),
|
|
sizeof(SNZBRequestBase)
|
|
};
|
|
|
|
//*****************************************************************
|
|
// RemoteServer
|
|
|
|
RemoteServer::RemoteServer()
|
|
{
|
|
debug("Creating RemoteServer");
|
|
|
|
m_pNetAddress = new NetAddress(g_pOptions->GetServerIP(), g_pOptions->GetServerPort());
|
|
m_pConnection = NULL;
|
|
}
|
|
|
|
RemoteServer::~RemoteServer()
|
|
{
|
|
debug("Destroying RemoteServer");
|
|
|
|
if (m_pConnection)
|
|
{
|
|
delete m_pConnection;
|
|
}
|
|
delete m_pNetAddress;
|
|
}
|
|
|
|
void RemoteServer::Run()
|
|
{
|
|
debug("Entering RemoteServer-loop");
|
|
|
|
while (!IsStopped())
|
|
{
|
|
bool bBind = true;
|
|
|
|
if (!m_pConnection)
|
|
{
|
|
m_pConnection = new Connection(m_pNetAddress);
|
|
m_pConnection->SetTimeout(g_pOptions->GetConnectionTimeout());
|
|
m_pConnection->SetSuppressErrors(false);
|
|
bBind = m_pConnection->Bind() == 0;
|
|
}
|
|
|
|
// Accept connections and store the "new" socket value
|
|
SOCKET iSocket = INVALID_SOCKET;
|
|
if (bBind)
|
|
{
|
|
iSocket = m_pConnection->Accept();
|
|
}
|
|
if (!bBind || iSocket == INVALID_SOCKET)
|
|
{
|
|
// Remote server could not bind or accept connection, waiting 1/2 sec and try again
|
|
if (IsStopped())
|
|
{
|
|
break;
|
|
}
|
|
usleep(500 * 1000);
|
|
delete m_pConnection;
|
|
m_pConnection = NULL;
|
|
continue;
|
|
}
|
|
|
|
RequestProcessor* commandThread = new RequestProcessor();
|
|
commandThread->SetAutoDestroy(true);
|
|
commandThread->SetSocket(iSocket);
|
|
commandThread->Start();
|
|
}
|
|
if (m_pConnection)
|
|
{
|
|
m_pConnection->Disconnect();
|
|
}
|
|
|
|
debug("Exiting RemoteServer-loop");
|
|
}
|
|
|
|
void RemoteServer::Stop()
|
|
{
|
|
Thread::Stop();
|
|
if (m_pConnection)
|
|
{
|
|
m_pConnection->SetSuppressErrors(true);
|
|
m_pConnection->Cancel();
|
|
#ifdef WIN32
|
|
m_pConnection->Disconnect();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
//*****************************************************************
|
|
// RequestProcessor
|
|
|
|
void RequestProcessor::Run()
|
|
{
|
|
int iBytesReceived = 0;
|
|
|
|
// Read the first package which needs to be a request
|
|
|
|
iBytesReceived = recv(m_iSocket, (char*) & m_MessageBase, sizeof(m_MessageBase), 0);
|
|
if (iBytesReceived < 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Make sure this is a nzbget request from a client
|
|
if ((int)ntohl(m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE)
|
|
{
|
|
warn("Non-nzbget request received on port %i", g_pOptions->GetServerPort());
|
|
|
|
if (m_iSocket > -1)
|
|
{
|
|
closesocket(m_iSocket);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (strcmp(m_MessageBase.m_szPassword, g_pOptions->GetServerPassword()))
|
|
{
|
|
warn("nzbget request received on port %i, but password invalid", g_pOptions->GetServerPort());
|
|
|
|
if (m_iSocket > -1)
|
|
{
|
|
closesocket(m_iSocket);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// Info - connection received
|
|
struct sockaddr_in PeerName;
|
|
int iPeerNameLength = sizeof(PeerName);
|
|
if (getpeername(m_iSocket, (struct sockaddr*)&PeerName, (socklen_t*) &iPeerNameLength) >= 0)
|
|
{
|
|
#ifdef WIN32
|
|
char* ip = inet_ntoa(PeerName.sin_addr);
|
|
#else
|
|
char ip[20];
|
|
inet_ntop(AF_INET, &PeerName.sin_addr, ip, sizeof(ip));
|
|
#endif
|
|
debug("%s request received from %s", g_szMessageRequestNames[ntohl(m_MessageBase.m_iType)], ip);
|
|
}
|
|
|
|
Dispatch();
|
|
|
|
// Close the socket
|
|
closesocket(m_iSocket);
|
|
}
|
|
|
|
void RequestProcessor::Dispatch()
|
|
{
|
|
if (ntohl(m_MessageBase.m_iType) >= (int)eRemoteRequestDownload &&
|
|
ntohl(m_MessageBase.m_iType) <= (int)eRemoteRequestShutdown &&
|
|
g_iMessageRequestSizes[ntohl(m_MessageBase.m_iType)] != ntohl(m_MessageBase.m_iStructSize))
|
|
{
|
|
error("Invalid size of request: needed %i Bytes, but received %i Bytes",
|
|
g_iMessageRequestSizes[ntohl(m_MessageBase.m_iType)], ntohl(m_MessageBase.m_iStructSize));
|
|
return;
|
|
}
|
|
|
|
MessageCommand* command = NULL;
|
|
|
|
switch (ntohl(m_MessageBase.m_iType))
|
|
{
|
|
case eRemoteRequestDownload:
|
|
{
|
|
command = new DownloadCommand();
|
|
break;
|
|
}
|
|
|
|
case eRemoteRequestList:
|
|
{
|
|
command = new ListCommand();
|
|
break;
|
|
}
|
|
|
|
case eRemoteRequestLog:
|
|
{
|
|
command = new LogCommand();
|
|
break;
|
|
}
|
|
|
|
case eRemoteRequestPauseUnpause:
|
|
{
|
|
command = new PauseUnpauseCommand();
|
|
break;
|
|
}
|
|
|
|
case eRemoteRequestEditQueue:
|
|
{
|
|
command = new EditQueueCommand();
|
|
break;
|
|
}
|
|
|
|
case eRemoteRequestSetDownloadRate:
|
|
{
|
|
command = new SetDownloadRateCommand();
|
|
break;
|
|
}
|
|
|
|
case eRemoteRequestDumpDebug:
|
|
{
|
|
command = new DumpDebugCommand();
|
|
break;
|
|
}
|
|
|
|
case eRemoteRequestShutdown:
|
|
{
|
|
command = new ShutdownCommand();
|
|
break;
|
|
}
|
|
|
|
case eRemoteRequestVersion:
|
|
{
|
|
command = new VersionCommand();
|
|
break;
|
|
}
|
|
|
|
default:
|
|
error("Received unsupported request %i", ntohl(m_MessageBase.m_iType));
|
|
break;
|
|
}
|
|
|
|
if (command)
|
|
{
|
|
command->SetSocket(m_iSocket);
|
|
command->SetMessageBase(&m_MessageBase);
|
|
command->Execute();
|
|
delete command;
|
|
}
|
|
}
|
|
|
|
//*****************************************************************
|
|
// Commands
|
|
|
|
void MessageCommand::SendBoolResponse(bool bSuccess, const char* szText)
|
|
{
|
|
// all bool-responses have the same format of structure, we use SNZBDownloadResponse here
|
|
SNZBDownloadResponse BoolResponse;
|
|
memset(&BoolResponse, 0, sizeof(BoolResponse));
|
|
BoolResponse.m_MessageBase.m_iSignature = htonl(NZBMESSAGE_SIGNATURE);
|
|
BoolResponse.m_MessageBase.m_iStructSize = htonl(sizeof(BoolResponse));
|
|
BoolResponse.m_bSuccess = htonl(bSuccess);
|
|
int iTextLen = strlen(szText) + 1;
|
|
BoolResponse.m_iTrailingDataLength = htonl(iTextLen);
|
|
|
|
// Send the request answer
|
|
send(m_iSocket, (char*) &BoolResponse, sizeof(BoolResponse), 0);
|
|
send(m_iSocket, (char*)szText, iTextLen, 0);
|
|
}
|
|
|
|
bool MessageCommand::ReceiveRequest(void* pBuffer, int iSize)
|
|
{
|
|
memcpy(pBuffer, m_pMessageBase, sizeof(SNZBRequestBase));
|
|
iSize -= sizeof(SNZBRequestBase);
|
|
if (iSize > 0)
|
|
{
|
|
int iBytesReceived = recv(m_iSocket, ((char*)pBuffer) + sizeof(SNZBRequestBase), iSize, 0);
|
|
if (iBytesReceived != iSize)
|
|
{
|
|
error("invalid request");
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void PauseUnpauseCommand::Execute()
|
|
{
|
|
SNZBPauseUnpauseRequest PauseUnpauseRequest;
|
|
if (!ReceiveRequest(&PauseUnpauseRequest, sizeof(PauseUnpauseRequest)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
g_pOptions->SetPause(ntohl(PauseUnpauseRequest.m_bPause));
|
|
SendBoolResponse(true, "Pause-/Unpause-Command completed successfully");
|
|
}
|
|
|
|
void SetDownloadRateCommand::Execute()
|
|
{
|
|
SNZBSetDownloadRateRequest SetDownloadRequest;
|
|
if (!ReceiveRequest(&SetDownloadRequest, sizeof(SetDownloadRequest)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
g_pOptions->SetDownloadRate(ntohl(SetDownloadRequest.m_iDownloadRate) / 1024.0);
|
|
SendBoolResponse(true, "Rate-Command completed successfully");
|
|
}
|
|
|
|
void DumpDebugCommand::Execute()
|
|
{
|
|
SNZBDumpDebugRequest DumpDebugRequest;
|
|
if (!ReceiveRequest(&DumpDebugRequest, sizeof(DumpDebugRequest)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
g_pQueueCoordinator->LogDebugInfo();
|
|
SendBoolResponse(true, "Debug-Command completed successfully");
|
|
}
|
|
|
|
void ShutdownCommand::Execute()
|
|
{
|
|
SNZBShutdownRequest ShutdownRequest;
|
|
if (!ReceiveRequest(&ShutdownRequest, sizeof(ShutdownRequest)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
SendBoolResponse(true, "Stopping server");
|
|
ExitProc();
|
|
}
|
|
|
|
void VersionCommand::Execute()
|
|
{
|
|
SNZBVersionRequest VersionRequest;
|
|
if (!ReceiveRequest(&VersionRequest, sizeof(VersionRequest)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
SendBoolResponse(true, VERSION);
|
|
}
|
|
|
|
void DownloadCommand::Execute()
|
|
{
|
|
SNZBDownloadRequest DownloadRequest;
|
|
if (!ReceiveRequest(&DownloadRequest, sizeof(DownloadRequest)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
char* pRecvBuffer = (char*)malloc(ntohl(DownloadRequest.m_iTrailingDataLength) + 1);
|
|
char* pBufPtr = pRecvBuffer;
|
|
|
|
// Read from the socket until nothing remains
|
|
int iResult = 0;
|
|
int NeedBytes = ntohl(DownloadRequest.m_iTrailingDataLength);
|
|
while (NeedBytes > 0)
|
|
{
|
|
iResult = recv(m_iSocket, pBufPtr, NeedBytes, 0);
|
|
// Did the recv succeed?
|
|
if (iResult <= 0)
|
|
{
|
|
error("invalid request");
|
|
break;
|
|
}
|
|
pBufPtr += iResult;
|
|
NeedBytes -= iResult;
|
|
}
|
|
|
|
if (NeedBytes == 0)
|
|
{
|
|
NZBFile* pNZBFile = NZBFile::CreateFromBuffer(DownloadRequest.m_szFilename, pRecvBuffer, ntohl(DownloadRequest.m_iTrailingDataLength));
|
|
|
|
if (pNZBFile)
|
|
{
|
|
info("Request: Queue collection %s", DownloadRequest.m_szFilename);
|
|
g_pQueueCoordinator->AddNZBFileToQueue(pNZBFile, ntohl(DownloadRequest.m_bAddFirst));
|
|
delete pNZBFile;
|
|
|
|
char tmp[1024];
|
|
snprintf(tmp, 1024, "Collection %s added to queue", BaseFileName(DownloadRequest.m_szFilename));
|
|
tmp[1024-1] = '\0';
|
|
SendBoolResponse(true, tmp);
|
|
}
|
|
else
|
|
{
|
|
char tmp[1024];
|
|
snprintf(tmp, 1024, "Download Request failed for %s", BaseFileName(DownloadRequest.m_szFilename));
|
|
tmp[1024-1] = '\0';
|
|
SendBoolResponse(false, tmp);
|
|
}
|
|
}
|
|
|
|
free(pRecvBuffer);
|
|
}
|
|
|
|
void ListCommand::Execute()
|
|
{
|
|
SNZBListRequest ListRequest;
|
|
if (!ReceiveRequest(&ListRequest, sizeof(ListRequest)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
SNZBListResponse ListResponse;
|
|
memset(&ListResponse, 0, sizeof(ListResponse));
|
|
ListResponse.m_MessageBase.m_iSignature = htonl(NZBMESSAGE_SIGNATURE);
|
|
ListResponse.m_MessageBase.m_iStructSize = htonl(sizeof(ListResponse));
|
|
ListResponse.m_iEntrySize = htonl(sizeof(SNZBListResponseEntry));
|
|
|
|
char* buf = NULL;
|
|
int bufsize = 0;
|
|
|
|
if (ntohl(ListRequest.m_bFileList))
|
|
{
|
|
// Make a data structure and copy all the elements of the list into it
|
|
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
|
|
|
|
int NrEntries = pDownloadQueue->size();
|
|
|
|
// calculate required buffer size
|
|
bufsize = NrEntries * sizeof(SNZBListResponseEntry);
|
|
for (DownloadQueue::iterator it = pDownloadQueue->begin(); it != pDownloadQueue->end(); it++)
|
|
{
|
|
FileInfo* pFileInfo = *it;
|
|
bufsize += strlen(pFileInfo->GetNZBFilename()) + 1;
|
|
bufsize += strlen(pFileInfo->GetSubject()) + 1;
|
|
bufsize += strlen(pFileInfo->GetFilename()) + 1;
|
|
bufsize += strlen(pFileInfo->GetDestDir()) + 1;
|
|
}
|
|
|
|
buf = (char*) malloc(bufsize);
|
|
char* bufptr = buf;
|
|
for (DownloadQueue::iterator it = pDownloadQueue->begin(); it != pDownloadQueue->end(); it++)
|
|
{
|
|
unsigned int iSizeHi, iSizeLo;
|
|
FileInfo* pFileInfo = *it;
|
|
SNZBListResponseEntry* pListAnswer = (SNZBListResponseEntry*) bufptr;
|
|
pListAnswer->m_iID = htonl(pFileInfo->GetID());
|
|
SplitInt64(pFileInfo->GetSize(), &iSizeHi, &iSizeLo);
|
|
pListAnswer->m_iFileSizeLo = htonl(iSizeLo);
|
|
pListAnswer->m_iFileSizeHi = htonl(iSizeHi);
|
|
SplitInt64(pFileInfo->GetRemainingSize(), &iSizeHi, &iSizeLo);
|
|
pListAnswer->m_iRemainingSizeLo = htonl(iSizeLo);
|
|
pListAnswer->m_iRemainingSizeHi = htonl(iSizeHi);
|
|
pListAnswer->m_bFilenameConfirmed = htonl(pFileInfo->GetFilenameConfirmed());
|
|
pListAnswer->m_bPaused = htonl(pFileInfo->GetPaused());
|
|
pListAnswer->m_iNZBFilenameLen = htonl(strlen(pFileInfo->GetNZBFilename()) + 1);
|
|
pListAnswer->m_iSubjectLen = htonl(strlen(pFileInfo->GetSubject()) + 1);
|
|
pListAnswer->m_iFilenameLen = htonl(strlen(pFileInfo->GetFilename()) + 1);
|
|
pListAnswer->m_iDestDirLen = htonl(strlen(pFileInfo->GetDestDir()) + 1);
|
|
bufptr += sizeof(SNZBListResponseEntry);
|
|
strcpy(bufptr, pFileInfo->GetNZBFilename());
|
|
bufptr += ntohl(pListAnswer->m_iNZBFilenameLen);
|
|
strcpy(bufptr, pFileInfo->GetSubject());
|
|
bufptr += ntohl(pListAnswer->m_iSubjectLen);
|
|
strcpy(bufptr, pFileInfo->GetFilename());
|
|
bufptr += ntohl(pListAnswer->m_iFilenameLen);
|
|
strcpy(bufptr, pFileInfo->GetDestDir());
|
|
bufptr += ntohl(pListAnswer->m_iDestDirLen);
|
|
}
|
|
|
|
g_pQueueCoordinator->UnlockQueue();
|
|
|
|
ListResponse.m_iNrTrailingEntries = htonl(NrEntries);
|
|
ListResponse.m_iTrailingDataLength = htonl(bufsize);
|
|
}
|
|
|
|
if (htonl(ListRequest.m_bServerState))
|
|
{
|
|
unsigned int iSizeHi, iSizeLo;
|
|
ListResponse.m_iDownloadRate = htonl((int)(g_pQueueCoordinator->CalcCurrentDownloadSpeed() * 1024));
|
|
SplitInt64(g_pQueueCoordinator->CalcRemainingSize(), &iSizeHi, &iSizeLo);
|
|
ListResponse.m_iRemainingSizeHi = htonl(iSizeHi);
|
|
ListResponse.m_iRemainingSizeLo = htonl(iSizeLo);
|
|
ListResponse.m_iDownloadLimit = htonl((int)(g_pOptions->GetDownloadRate() * 1024));
|
|
ListResponse.m_bServerPaused = htonl(g_pOptions->GetPause());
|
|
ListResponse.m_iThreadCount = htonl(Thread::GetThreadCount() - 1); // not counting itself
|
|
PrePostProcessor::ParQueue* pParQueue = g_pPrePostProcessor->LockParQueue();
|
|
ListResponse.m_iParJobCount = htonl(pParQueue->size());
|
|
g_pPrePostProcessor->UnlockParQueue();
|
|
|
|
int iUpTimeSec, iDnTimeSec;
|
|
long long iAllBytes;
|
|
bool bStandBy;
|
|
g_pQueueCoordinator->CalcStat(&iUpTimeSec, &iDnTimeSec, &iAllBytes, &bStandBy);
|
|
ListResponse.m_iUpTimeSec = htonl(iUpTimeSec);
|
|
ListResponse.m_iDownloadTimeSec = htonl(iDnTimeSec);
|
|
ListResponse.m_bServerStandBy = htonl(bStandBy);
|
|
SplitInt64(iAllBytes, &iSizeHi, &iSizeLo);
|
|
ListResponse.m_iDownloadedBytesHi = htonl(iSizeHi);
|
|
ListResponse.m_iDownloadedBytesLo = htonl(iSizeLo);
|
|
}
|
|
|
|
// Send the request answer
|
|
send(m_iSocket, (char*) &ListResponse, sizeof(ListResponse), 0);
|
|
|
|
// Send the data
|
|
if (bufsize > 0)
|
|
{
|
|
send(m_iSocket, buf, bufsize, 0);
|
|
}
|
|
|
|
if (buf)
|
|
{
|
|
free(buf);
|
|
}
|
|
}
|
|
|
|
void LogCommand::Execute()
|
|
{
|
|
SNZBLogRequest LogRequest;
|
|
if (!ReceiveRequest(&LogRequest, sizeof(LogRequest)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
Log::Messages* pMessages = g_pLog->LockMessages();
|
|
|
|
int iNrEntries = ntohl(LogRequest.m_iLines);
|
|
unsigned int iIDFrom = ntohl(LogRequest.m_iIDFrom);
|
|
int iStart = pMessages->size();
|
|
if (iNrEntries > 0)
|
|
{
|
|
if (iNrEntries > (int)pMessages->size())
|
|
{
|
|
iNrEntries = pMessages->size();
|
|
}
|
|
iStart = pMessages->size() - iNrEntries;
|
|
}
|
|
if (iIDFrom > 0 && !pMessages->empty())
|
|
{
|
|
iStart = iIDFrom - pMessages->front()->GetID();
|
|
if (iStart < 0)
|
|
{
|
|
iStart = 0;
|
|
}
|
|
iNrEntries = pMessages->size() - iStart;
|
|
if (iNrEntries < 0)
|
|
{
|
|
iNrEntries = 0;
|
|
}
|
|
}
|
|
|
|
// calculate required buffer size
|
|
int bufsize = iNrEntries * sizeof(SNZBLogResponseEntry);
|
|
for (unsigned int i = (unsigned int)iStart; i < pMessages->size(); i++)
|
|
{
|
|
Message* pMessage = (*pMessages)[i];
|
|
bufsize += strlen(pMessage->GetText()) + 1;
|
|
}
|
|
|
|
char* buf = (char*) malloc(bufsize);
|
|
char* bufptr = buf;
|
|
for (unsigned int i = (unsigned int)iStart; i < pMessages->size(); i++)
|
|
{
|
|
Message* pMessage = (*pMessages)[i];
|
|
SNZBLogResponseEntry* pLogAnswer = (SNZBLogResponseEntry*) bufptr;
|
|
pLogAnswer->m_iID = htonl(pMessage->GetID());
|
|
pLogAnswer->m_iKind = htonl(pMessage->GetKind());
|
|
pLogAnswer->m_tTime = htonl(pMessage->GetTime());
|
|
pLogAnswer->m_iTextLen = htonl(strlen(pMessage->GetText()) + 1);
|
|
bufptr += sizeof(SNZBLogResponseEntry);
|
|
strcpy(bufptr, pMessage->GetText());
|
|
bufptr += ntohl(pLogAnswer->m_iTextLen);
|
|
}
|
|
|
|
g_pLog->UnlockMessages();
|
|
|
|
SNZBLogResponse LogResponse;
|
|
LogResponse.m_MessageBase.m_iSignature = htonl(NZBMESSAGE_SIGNATURE);
|
|
LogResponse.m_MessageBase.m_iStructSize = htonl(sizeof(LogResponse));
|
|
LogResponse.m_iEntrySize = htonl(sizeof(SNZBLogResponseEntry));
|
|
LogResponse.m_iNrTrailingEntries = htonl(iNrEntries);
|
|
LogResponse.m_iTrailingDataLength = htonl(bufsize);
|
|
|
|
// Send the request answer
|
|
send(m_iSocket, (char*) &LogResponse, sizeof(LogResponse), 0);
|
|
|
|
// Send the data
|
|
if (bufsize > 0)
|
|
{
|
|
send(m_iSocket, buf, bufsize, 0);
|
|
}
|
|
|
|
free(buf);
|
|
}
|
|
|
|
void EditQueueCommand::Execute()
|
|
{
|
|
SNZBEditQueueRequest EditQueueRequest;
|
|
if (!ReceiveRequest(&EditQueueRequest, sizeof(EditQueueRequest)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
int iNrEntries = ntohl(EditQueueRequest.m_iNrTrailingEntries);
|
|
int iAction = ntohl(EditQueueRequest.m_iAction);
|
|
int iOffset = ntohl(EditQueueRequest.m_iOffset);
|
|
bool bSmartOrder = ntohl(EditQueueRequest.m_bSmartOrder);
|
|
unsigned int iBufLength = ntohl(EditQueueRequest.m_iTrailingDataLength);
|
|
|
|
if (iNrEntries * sizeof(int32_t) != iBufLength)
|
|
{
|
|
error("Invalid struct size");
|
|
return;
|
|
}
|
|
|
|
if (iNrEntries <= 0)
|
|
{
|
|
SendBoolResponse(false, "Edit-Command failed: no IDs specified");
|
|
return;
|
|
}
|
|
|
|
int32_t* pIDs = (int32_t*)malloc(iBufLength);
|
|
|
|
// Read from the socket until nothing remains
|
|
char* pBufPtr = (char*)pIDs;
|
|
int NeedBytes = iBufLength;
|
|
int iResult = 0;
|
|
while (NeedBytes > 0)
|
|
{
|
|
iResult = recv(m_iSocket, pBufPtr, NeedBytes, 0);
|
|
// Did the recv succeed?
|
|
if (iResult <= 0)
|
|
{
|
|
error("invalid request");
|
|
break;
|
|
}
|
|
pBufPtr += iResult;
|
|
NeedBytes -= iResult;
|
|
}
|
|
|
|
QueueEditor::IDList cIDList;
|
|
cIDList.reserve(iNrEntries);
|
|
for (int i = 0; i < iNrEntries; i++)
|
|
{
|
|
cIDList.push_back(ntohl(pIDs[i]));
|
|
}
|
|
|
|
bool bOK = g_pQueueCoordinator->GetQueueEditor()->EditList(&cIDList, bSmartOrder, (QueueEditor::EEditAction)iAction, iOffset);
|
|
|
|
free(pIDs);
|
|
|
|
if (bOK)
|
|
{
|
|
SendBoolResponse(true, "Edit-Command completed successfully");
|
|
}
|
|
else
|
|
{
|
|
SendBoolResponse(false, "Edit-Command failed");
|
|
}
|
|
}
|