Bug Summary

File:rootdir/src/webserver/src/WebServer.cpp
Warning:line 347, column 9
This statement is never executed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name WebServer.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/rootdir/src/webserver/src -fcoverage-compilation-dir=/rootdir/src/webserver/src -resource-dir /usr/lib/llvm-19/lib/clang/19 -D HAVE_CONFIG_H -I . -I ../../.. -I ../.. -I ../../../src -I ../../../src/libs -I ../../../src/include -D USE_WX_EXTENSIONS -D WITH_LIBPNG -D HAVE_BFD -I /usr/lib/x86_64-linux-gnu/wx/include/gtk3-unicode-3.2 -I /usr/include/wx-3.2 -D _FILE_OFFSET_BITS=64 -D WXUSINGDLL -D __WXGTK__ -D wxUSE_GUI=0 -D WEBSERVERDIR="/usr/share/amule/webserver" -D YY_NO_INPUT -I /usr/include/upnp -D ENABLE_UPNP=1 -I /usr/include/libpng16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-register -fdeprecated-macro -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2025-01-17-082348-14898-1 -x c++ WebServer.cpp
1//
2// This file is part of the aMule Project.
3//
4// Copyright (c) 2003-2011 Angel Vidal ( kry@amule.org )
5// Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
6// Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net )
7//
8// Any parts of this program derived from the xMule, lMule or eMule project,
9// or contributed by third-party developers are copyrighted by their
10// respective authors.
11//
12// This program is free software; you can redistribute it and/or modify
13// it under the terms of the GNU General Public License as published by
14// the Free Software Foundation; either version 2 of the License, or
15// (at your option) any later version.
16//
17// This program is distributed in the hope that it will be useful,
18// but WITHOUT ANY WARRANTY; without even the implied warranty of
19// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20// GNU General Public License for more details.
21//
22// You should have received a copy of the GNU General Public License
23// along with this program; if not, write to the Free Software
24// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25//
26
27
28#include <cctype> // Needed for std::toupper()
29#include <wx/math.h> // Needed for cos, M_PI
30#include <string> // Do_not_auto_remove (g++-4.0.1)
31
32#include <wx/datetime.h>
33
34//-------------------------------------------------------------------
35
36#include <wx/tokenzr.h> // for wxTokenizer
37#include <wx/wfstream.h>
38
39#include <ec/cpp/ECFileConfig.h> // Needed for CECFileConfig
40#include <ec/cpp/ECSpecialTags.h>
41#include <common/MD5Sum.h>
42#include <common/Format.h> // Needed for CFormat
43
44#include <protocol/ed2k/Constants.h> // Needed for PARTSIZE
45#include "Constants.h" // Needed for PR_*
46
47//-------------------------------------------------------------------
48
49#include "WebSocket.h" // Needed for StopSockets()
50#include <amuleIPV4Address.h>
51
52#include "php_syntree.h"
53#include "php_core_lib.h"
54
55//-------------------------------------------------------------------
56typedef uint32_t COLORTYPE;
57
58#ifdef RGB
59#undef RGB
60#endif
61
62inline unsigned long RGB(int r, int g, int b)
63{
64 return ((b & 0xff) << 16) | ((g & 0xff) << 8) | (r & 0xff);
65}
66
67inline void set_rgb_color_val(unsigned char *start, uint32 val, unsigned char mod)
68{
69 unsigned char r = val, g = val >> 8, b = val >> 16;
70 start[0] = ( r > mod ) ? (r - mod) : 1;
71 start[1] = ( g > mod ) ? (g - mod) : 1;
72 start[2] = ( b > mod ) ? (b - mod) : 1;
73}
74
75wxString _SpecialChars(wxString str) {
76 str.Replace(wxT("&")L"&",wxT("&amp;")L"&amp;");
77 str.Replace(wxT("<")L"<",wxT("&lt;")L"&lt;");
78 str.Replace(wxT(">")L">",wxT("&gt;")L"&gt;");
79 str.Replace(wxT("\"")L"\"",wxT("&quot;")L"&quot;");
80 return str;
81}
82
83static uint8 GetHigherPrio(uint32 prio, bool autoprio)
84{
85 if (autoprio) {
86 return PR_LOW0;
87 } else {
88 switch (prio) {
89 case PR_LOW0: return PR_NORMAL1;
90 case PR_NORMAL1: return PR_HIGH2;
91 case PR_HIGH2: return PR_AUTO5;
92 case PR_AUTO5: return PR_LOW0;
93 default: return PR_AUTO5;
94 }
95 }
96}
97
98static uint8 GetHigherPrioShared(uint32 prio, bool autoprio)
99{
100 if (autoprio) {
101 return PR_VERYLOW4;
102 } else {
103 switch (prio) {
104 case PR_VERYLOW4: return PR_LOW0;
105 case PR_LOW0: return PR_NORMAL1;
106 case PR_NORMAL1: return PR_HIGH2;
107 case PR_HIGH2: return PR_VERYHIGH3;
108 case PR_VERYHIGH3: return PR_POWERSHARE6;
109 case PR_POWERSHARE6: return PR_AUTO5;
110 case PR_AUTO5: return PR_VERYLOW4;
111 default: return PR_AUTO5;
112 }
113 }
114}
115
116
117static uint8 GetLowerPrio(uint32 prio, bool autoprio)
118{
119 if (autoprio) {
120 return PR_HIGH2;
121 } else {
122 switch (prio) {
123 case PR_LOW0: return PR_AUTO5;
124 case PR_NORMAL1: return PR_LOW0;
125 case PR_HIGH2: return PR_NORMAL1;
126 case PR_AUTO5: return PR_HIGH2;
127 default: return PR_AUTO5;
128 }
129 }
130}
131
132static uint8 GetLowerPrioShared(uint32 prio, bool autoprio)
133{
134 if (autoprio) {
135 return PR_POWERSHARE6;
136 } else {
137 switch (prio) {
138 case PR_VERYLOW4: return PR_AUTO5;
139 case PR_LOW0: return PR_VERYLOW4;
140 case PR_NORMAL1: return PR_LOW0;
141 case PR_HIGH2: return PR_NORMAL1;
142 case PR_VERYHIGH3: return PR_HIGH2;
143 case PR_POWERSHARE6: return PR_VERYHIGH3;
144 case PR_AUTO5: return PR_POWERSHARE6;
145 default: return PR_AUTO5;
146 }
147 }
148}
149
150/*
151 * Url string decoder
152 */
153wxString CURLDecoder::Decode(const wxString& url)
154{
155 size_t n = url.length();
156 std::vector<char> buffer(n + 1);
157 size_t i, j;
158
159 for (i = 0, j = 0; i < n; i++, j++) {
160 if (url[i] == wxT('+')L'+') {
161 buffer[j] = ' ';
162 } else if (url[i] == wxT('%')L'%' && i < n - 2) {
163 char ch1 = std::toupper(url[i+1]);
164 char ch2 = std::toupper(url[i+2]);
165 if (((ch1 >= '0' && ch1 <= '9') || (ch1 >= 'A' && ch1 <= 'F')) &&
166 ((ch2 >= '0' && ch2 <= '9') || (ch2 >= 'A' && ch2 <= 'F'))) {
167 i += 2;
168 buffer[j] = ((ch1 > '9' ? ch1 - 'A' + 10 : ch1 - '0') << 4) | (ch2 > '9' ? ch2 - 'A' + 10 : ch2 - '0');
169 } else {
170 // Invalid %-escape sequence
171 buffer[j] = url[i];
172 }
173 } else {
174 buffer[j] = url[i];
175 }
176 }
177 buffer[j] = '\0';
178
179 return UTF82unicode(&buffer[0]);
180}
181
182CParsedUrl::CParsedUrl(const wxString &url)
183{
184 if ( url.Find('/') != -1 ) {
185 m_path = url.BeforeFirst('/');
186 m_file = url.AfterFirst('/');
187 }
188
189 if ( url.Find('?') != -1 ) {
190 m_file.Truncate(m_file.Find('?'));
191
192 wxString params = url.AfterFirst('?');
193
194 wxStringTokenizer tkz(params, wxT("&")L"&");
195 while ( tkz.HasMoreTokens() ) {
196 wxString param_val = tkz.GetNextToken();
197 wxString key = param_val.BeforeFirst('=');
198 wxString val = param_val.AfterFirst('=');
199 val = CURLDecoder::Decode(val);
200 if ( m_params.count(key) ) {
201 m_params[key] = m_params[key] + wxT("|")L"|" + val;
202 } else {
203 m_params[key] = val;
204 }
205 }
206 }
207}
208
209void CParsedUrl::ConvertParams(std::map<std::string, std::string> &dst)
210{
211 for(std::map<wxString, wxString>::iterator i = m_params.begin(); i != m_params.end(); ++i) {
212 std::string key(unicode2char(i->first)), value(unicode2char(i->second));
213 dst[key] = value;
214 }
215}
216
217#ifndef ASIO_SOCKETS
218BEGIN_EVENT_TABLE(CWebServerBase, wxEvtHandler)const wxEventTable CWebServerBase::sm_eventTable = { &wxEvtHandler
::sm_eventTable, &CWebServerBase::sm_eventTableEntries[0]
}; const wxEventTable *CWebServerBase::GetEventTable() const
{ return &CWebServerBase::sm_eventTable; } wxEventHashTable
CWebServerBase::sm_eventHashTable(CWebServerBase::sm_eventTable
); wxEventHashTable &CWebServerBase::GetEventHashTable() const
{ return CWebServerBase::sm_eventHashTable; } const wxEventTableEntry
CWebServerBase::sm_eventTableEntries[] = {
219 EVT_SOCKET(ID_WEBLISTENSOCKET_EVENT, CWebServerBase::OnWebSocketServerEvent)wxEventTableEntry(wxEVT_SOCKET, ID_WEBLISTENSOCKET_EVENT, wxID_ANY
, wxNewEventTableFunctor(wxEVT_SOCKET, wxEventFunctionCast(wxPrivate
::DoCast<wxPrivate::EventArgOf<wxSocketEventFunction>
::type>(&CWebServerBase::OnWebSocketServerEvent))), __null
),
220 EVT_SOCKET(ID_WEBCLIENTSOCKET_EVENT, CWebServerBase::OnWebSocketEvent)wxEventTableEntry(wxEVT_SOCKET, ID_WEBCLIENTSOCKET_EVENT, wxID_ANY
, wxNewEventTableFunctor(wxEVT_SOCKET, wxEventFunctionCast(wxPrivate
::DoCast<wxPrivate::EventArgOf<wxSocketEventFunction>
::type>(&CWebServerBase::OnWebSocketEvent))), __null),
221END_EVENT_TABLE()wxEventTableEntry(wxEVT_NULL, 0, 0, __null, __null) };
222#endif
223
224CWebServerBase::CWebServerBase(CamulewebApp *webApp, const wxString& templateDir) :
225 m_ServersInfo(webApp), m_SharedFileInfo(webApp), m_DownloadFileInfo(webApp, &m_ImageLib),
226 m_UploadsInfo(webApp), m_SearchInfo(webApp), m_Stats(500, webApp),
227 m_ImageLib(templateDir)
228{
229 webInterface = webApp;
230
231 //
232 // Init stat graphs
233#ifdef WITH_LIBPNG1
234 m_ImageLib.AddImage(new CDynStatisticImage(200, true, m_Stats.DownloadSpeed()),
235 wxT("/amule_stats_download.png")L"/amule_stats_download.png");
236 m_ImageLib.AddImage(new CDynStatisticImage(200, true, m_Stats.UploadSpeed()),
237 wxT("/amule_stats_upload.png")L"/amule_stats_upload.png");
238 m_ImageLib.AddImage(new CDynStatisticImage(200, false, m_Stats.ConnCount()),
239 wxT("/amule_stats_conncount.png")L"/amule_stats_conncount.png");
240 m_ImageLib.AddImage(new CDynStatisticImage(200, false, m_Stats.KadCount()),
241 wxT("/amule_stats_kad.png")L"/amule_stats_kad.png");
242#endif
243
244 m_upnpEnabled = webInterface->m_UPnPWebServerEnabled;
245 m_upnpTCPPort = webInterface->m_UPnPTCPPort;
246
247#ifdef ASIO_SOCKETS
248 m_AsioService = new CAsioService;
249#endif
250}
251
252
253// Probably always terminated by Ctrl-C or kill, but make a clean shutdown of the service anyway
254CWebServerBase::~CWebServerBase()
255{
256#ifdef ASIO_SOCKETS
257 m_AsioService->Stop();
258 delete m_AsioService;
259#endif
260}
261
262
263//sends output to web interface
264void CWebServerBase::Print(const wxString &s)
265{
266 webInterface->Show(s);
267}
268
269
270void CWebServerBase::StartServer()
271{
272#ifdef ENABLE_UPNP1
273 if (m_upnpEnabled) {
274 m_upnpMappings.resize(1);
275 m_upnpMappings[0] = CUPnPPortMapping(
276 webInterface->m_WebserverPort,
277 "TCP",
278 true,
279 "aMule TCP Webserver Socket");
280 m_upnp = new CUPnPControlPoint(m_upnpTCPPort);
281 m_upnp->AddPortMappings(m_upnpMappings);
282 }
283#endif
284
285 amuleIPV4Address addr;
286 addr.AnyAddress();
287 addr.Service(webInterface->m_WebserverPort);
288
289 m_webserver_socket = new CWebLibSocketServer(addr, MULE_SOCKET_REUSEADDRwxSOCKET_REUSEADDR, this);
290#ifndef ASIO_SOCKETS
291 m_webserver_socket->SetEventHandler(*this, ID_WEBLISTENSOCKET_EVENT);
292 m_webserver_socket->SetNotify(wxSOCKET_CONNECTION_FLAG);
293#endif
294 m_webserver_socket->Notify(true);
295 if (!m_webserver_socket->IsOk()) {
296 delete m_webserver_socket;
297 m_webserver_socket = 0;
298 }
299
300}
301
302void CWebServerBase::StopServer()
303{
304 if ( m_webserver_socket ) {
305 delete m_webserver_socket;
306 }
307#ifdef ENABLE_UPNP1
308 if (m_upnpEnabled) {
309 m_upnp->DeletePortMappings(m_upnpMappings);
310 delete m_upnp;
311 }
312#endif
313}
314
315#ifndef ASIO_SOCKETS
316void CWebServerBase::OnWebSocketServerEvent(wxSocketEvent& WXUNUSED(event))
317{
318 m_webserver_socket->OnAccept();
319}
320#endif
321
322CWebLibSocketServer::CWebLibSocketServer(const class amuleIPV4Address& adr, int flags, CWebServerBase * webServerBase)
323 : CLibSocketServer(adr, flags),
324 m_webServerBase(webServerBase)
325{
326}
327
328void CWebLibSocketServer::OnAccept()
329{
330 CWebSocket *client = new CWebSocket(m_webServerBase);
331
332 if (AcceptWith(*client, false) ) {
333 m_webServerBase->webInterface->Show(_("web client connection accepted\n")wxGetTranslation(("web client connection accepted\n")));
334 } else {
335 delete client;
336 m_webServerBase->webInterface->Show(_("ERROR: cannot accept web client connection\n")wxGetTranslation(("ERROR: cannot accept web client connection\n"
))
);
337 }
338}
339
340#ifndef ASIO_SOCKETS
341void CWebServerBase::OnWebSocketEvent(wxSocketEvent& event)
342{
343 CWebSocket *socket = dynamic_cast<CWebSocket *>(event.GetSocket());
344 wxCHECK_RET(socket, wxT("Socket event with a NULL socket!"))if ( socket ) {} else { do { if ( wxTheAssertHandler &&
(wxOnAssert("WebServer.cpp", 344, __FUNCTION__, "\"socket\""
, L"Socket event with a NULL socket!"), wxTrapInAssert) ) { wxTrapInAssert
= false; asm volatile ("int $3"); } } while ( (void)0, 0 ); return
; } struct wxDummyCheckStruct344
;
345 switch(event.GetSocketEvent()) {
346 case wxSOCKET_LOST:
347 socket->OnLost();
This statement is never executed
348 break;
349 case wxSOCKET_INPUT:
350 socket->OnReceive(0);
351 break;
352 case wxSOCKET_OUTPUT:
353 socket->OnSend(0);
354 break;
355 case wxSOCKET_CONNECTION:
356 break;
357 default:
358 wxFAILdo { if ( wxTheAssertHandler && (wxOnAssert("WebServer.cpp"
, 358, __FUNCTION__, "\"Assert failure\"", (const char*)__null
), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile (
"int $3"); } } while ( (void)0, 0 )
;
359 break;
360 }
361}
362#endif
363
364void CScriptWebServer::ProcessImgFileReq(ThreadData Data)
365{
366 webInterface->DebugShow(wxT("**** imgrequest: ")L"**** imgrequest: " + Data.sURL + wxT("\n")L"\n");
367
368 const CSession* session = CheckLoggedin(Data);
369
370 // To prevent access to non-template images, we disallow use of paths in filenames.
371 wxString imgName = wxT("/")L"/" + wxFileName(Data.parsedURL.File()).GetFullName();
372 CAnyImage *img = m_ImageLib.GetImage(imgName);
373
374 // Only static images are available to visitors, in order to prevent
375 // information leakage, but still allowing images on the login page.
376 if (img && (session->m_loggedin || dynamic_cast<CFileImage*>(img))) {
377 int img_size = 0;
378 unsigned char* img_data = img->RequestData(img_size);
379 // This unicode2char is ok.
380 Data.pSocket->SendContent(unicode2char(img->GetHTTP()), img_data, img_size);
381 } else if (!session->m_loggedin) {
382 webInterface->DebugShow(wxT("**** imgrequest: failed, not logged in\n")L"**** imgrequest: failed, not logged in\n");
383 ProcessURL(Data);
384 } else {
385 webInterface->DebugShow(wxT("**** imgrequest: failed\n")L"**** imgrequest: failed\n");
386 }
387}
388
389// send EC request and discard output
390void CWebServerBase::Send_Discard_V2_Request(CECPacket *request)
391{
392 const CECPacket *reply = webInterface->SendRecvMsg_v2(request);
393 const CECTag *tag = NULL__null;
394 if (reply) {
395 if ( reply->GetOpCode() == EC_OP_STRINGS ) {
396 for (CECPacket::const_iterator it = reply->begin(); it != reply->end(); ++it) {
397 tag = & *it;
398 if (tag->GetTagName() == EC_TAG_STRING) {
399 webInterface->Show(tag->GetStringData());
400 }
401 }
402 } else if (reply->GetOpCode() == EC_OP_FAILED) {
403 tag = reply->GetFirstTagSafe();
404 if (tag->IsString()) {
405 webInterface->Show(
406 CFormat(_("Request failed with the following error: %s.")wxGetTranslation(("Request failed with the following error: %s."
))
) %
407 wxString(wxGetTranslation(tag->GetStringData())));
408 } else {
409 webInterface->Show(_("Request failed with an unknown error.")wxGetTranslation(("Request failed with an unknown error.")));
410 }
411 }
412 delete reply;
413 }
414}
415
416//
417// Command interface
418//
419void CWebServerBase::Send_SharedFile_Cmd(wxString file_hash, wxString cmd, uint32 opt_arg)
420{
421 CECPacket *ec_cmd = 0;
422 CMD4Hash fileHash;
423 wxCHECK2(fileHash.Decode(file_hash), /* Do nothing. */ )if ( fileHash.Decode(file_hash) ) {} else { do { if ( wxTheAssertHandler
&& (wxOnAssert("WebServer.cpp", 423, __FUNCTION__, "\"fileHash.Decode(file_hash)\""
, (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false
; asm volatile ("int $3"); } } while ( (void)0, 0 ); ; } struct
wxDummyCheckStruct423
;
424
425 CECTag hashtag(EC_TAG_KNOWNFILE, fileHash);
426 if (cmd == wxT("prio")L"prio") {
427 ec_cmd = new CECPacket(EC_OP_SHARED_SET_PRIO);
428 hashtag.AddTag(CECTag(EC_TAG_PARTFILE_PRIO, (uint8)opt_arg));
429 } else if ( cmd == wxT("prioup")L"prioup" ) {
430 SharedFile *file = m_SharedFileInfo.GetByHash(fileHash);
431 if ( file ) {
432 ec_cmd = new CECPacket(EC_OP_SHARED_SET_PRIO);
433 hashtag.AddTag(CECTag(EC_TAG_PARTFILE_PRIO,
434 GetHigherPrioShared(file->nFilePriority, file->bFileAutoPriority)));
435 }
436 } else if ( cmd == wxT("priodown")L"priodown" ) {
437 SharedFile *file = m_SharedFileInfo.GetByHash(fileHash);
438 if ( file ) {
439 ec_cmd = new CECPacket(EC_OP_SHARED_SET_PRIO);
440 hashtag.AddTag(CECTag(EC_TAG_PARTFILE_PRIO,
441 GetLowerPrioShared(file->nFilePriority, file->bFileAutoPriority)));
442 }
443 }
444
445 if ( ec_cmd ) {
446 ec_cmd->AddTag(hashtag);
447 Send_Discard_V2_Request(ec_cmd);
448 delete ec_cmd;
449 }
450}
451
452void CWebServerBase::Send_ReloadSharedFile_Cmd()
453{
454 CECPacket ec_cmd(EC_OP_SHAREDFILES_RELOAD);
455 Send_Discard_V2_Request(&ec_cmd);
456}
457
458void CWebServerBase::Send_DownloadFile_Cmd(wxString file_hash, wxString cmd, uint32 opt_arg)
459{
460 CECPacket *ec_cmd = 0;
461 CMD4Hash fileHash;
462 wxCHECK2(fileHash.Decode(file_hash), /* Do nothing. */ )if ( fileHash.Decode(file_hash) ) {} else { do { if ( wxTheAssertHandler
&& (wxOnAssert("WebServer.cpp", 462, __FUNCTION__, "\"fileHash.Decode(file_hash)\""
, (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false
; asm volatile ("int $3"); } } while ( (void)0, 0 ); ; } struct
wxDummyCheckStruct462
;
463
464 CECTag hashtag(EC_TAG_PARTFILE, fileHash);
465 if (cmd == wxT("pause")L"pause") {
466 ec_cmd = new CECPacket(EC_OP_PARTFILE_PAUSE);
467 } else if (cmd == wxT("resume")L"resume") {
468 ec_cmd = new CECPacket(EC_OP_PARTFILE_RESUME);
469 } else if (cmd == wxT("cancel")L"cancel") {
470 ec_cmd = new CECPacket(EC_OP_PARTFILE_DELETE);
471 } else if (cmd == wxT("prio")L"prio") {
472 ec_cmd = new CECPacket(EC_OP_PARTFILE_PRIO_SET);
473 hashtag.AddTag(CECTag(EC_TAG_PARTFILE_PRIO, (uint8)opt_arg));
474 } else if (cmd == wxT("prioup")L"prioup") {
475 DownloadFile *file = m_DownloadFileInfo.GetByHash(fileHash);
476 if ( file ) {
477 ec_cmd = new CECPacket(EC_OP_PARTFILE_PRIO_SET);
478 hashtag.AddTag(CECTag(EC_TAG_PARTFILE_PRIO,
479 GetHigherPrio(file->lFilePrio, file->bFileAutoPriority)));
480 }
481 } else if (cmd == wxT("priodown")L"priodown") {
482 DownloadFile *file = m_DownloadFileInfo.GetByHash(fileHash);
483 if ( file ) {
484 ec_cmd = new CECPacket(EC_OP_PARTFILE_PRIO_SET);
485 hashtag.AddTag(CECTag(EC_TAG_PARTFILE_PRIO,
486 GetLowerPrio(file->lFilePrio, file->bFileAutoPriority)));
487 }
488 }
489
490 if ( ec_cmd ) {
491 ec_cmd->AddTag(hashtag);
492 Send_Discard_V2_Request(ec_cmd);
493 delete ec_cmd;
494 }
495}
496
497void CWebServerBase::Send_DownloadSearchFile_Cmd(wxString file_hash, uint8 cat)
498{
499 CMD4Hash fileHash;
500 wxCHECK2(fileHash.Decode(file_hash), /* Do nothing. */ )if ( fileHash.Decode(file_hash) ) {} else { do { if ( wxTheAssertHandler
&& (wxOnAssert("WebServer.cpp", 500, __FUNCTION__, "\"fileHash.Decode(file_hash)\""
, (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false
; asm volatile ("int $3"); } } while ( (void)0, 0 ); ; } struct
wxDummyCheckStruct500
;
501
502 CECPacket ec_cmd(EC_OP_DOWNLOAD_SEARCH_RESULT);
503 CECTag link_tag(EC_TAG_KNOWNFILE, fileHash);
504
505 link_tag.AddTag(CECTag(EC_TAG_PARTFILE_CAT, cat));
506 ec_cmd.AddTag(link_tag);
507 Send_Discard_V2_Request(&ec_cmd);
508}
509
510void CWebServerBase::Send_AddServer_Cmd(wxString addr, wxString port, wxString name)
511{
512 CECPacket ec_cmd(EC_OP_SERVER_ADD);
513
514 ec_cmd.AddTag(CECTag(EC_TAG_SERVER_ADDRESS, addr.Trim() + wxT(":")L":" + port.Trim()));
515 ec_cmd.AddTag(CECTag(EC_TAG_SERVER_NAME, name));
516
517 Send_Discard_V2_Request(&ec_cmd);
518}
519
520void CWebServerBase::Send_Server_Cmd(uint32 ip, uint16 port, wxString cmd)
521{
522 if ( !ip ) {
523 return;
524 }
525
526 CECPacket *ec_cmd = 0;
527 if ( cmd == wxT("connect")L"connect" ) {
528 ec_cmd = new CECPacket(EC_OP_SERVER_CONNECT);
529 } else if ( cmd == wxT("remove")L"remove" ) {
530 ec_cmd = new CECPacket(EC_OP_SERVER_REMOVE);
531 } else if ( cmd == wxT("disconnect")L"disconnect" ) {
532 ec_cmd = new CECPacket(EC_OP_SERVER_DISCONNECT);
533 }
534 if ( ec_cmd ) {
535 ec_cmd->AddTag(CECTag(EC_TAG_SERVER, EC_IPv4_t(ip, port)));
536 Send_Discard_V2_Request(ec_cmd);
537 delete ec_cmd;
538 }
539}
540
541void CWebServerBase::Send_Search_Cmd(wxString search, wxString extention, wxString type,
542 EC_SEARCH_TYPE search_type, uint32 avail, uint32 min_size, uint32 max_size)
543{
544 CECPacket search_req(EC_OP_SEARCH_START);
545 search_req.AddTag(CEC_Search_Tag (search, search_type,
546 type, extention, avail, min_size, max_size));
547 Send_Discard_V2_Request(&search_req);
548}
549
550bool CWebServerBase::Send_DownloadEd2k_Cmd(wxString link, uint8 cat)
551{
552 CECPacket req(EC_OP_ADD_LINK);
553 CECTag link_tag(EC_TAG_STRING, link);
554 link_tag.AddTag(CECTag(EC_TAG_PARTFILE_CAT, cat));
555 req.AddTag(link_tag);
556 const CECPacket *response = webInterface->SendRecvMsg_v2(&req);
557 bool result = (response->GetOpCode() == EC_OP_FAILED);
558 delete response;
559 return result;
560}
561
562// We have to add gz-header and some other stuff
563// to standard zlib functions in order to use gzip in web pages
564int CWebServerBase::GzipCompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level)
565{
566 static const int gz_magic[2] = {0x1f, 0x8b}; // gzip magic header
567 z_stream stream = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
568 stream.zalloc = (alloc_func)0;
569 stream.zfree = (free_func)0;
570 stream.opaque = (voidpf)0;
571 uLong crc = crc32(0L, Z_NULL0, 0);
572 // init Zlib stream
573 // NOTE windowBits is passed < 0 to suppress zlib header
574 int err = deflateInit2(&stream, level, Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY)deflateInit2_((&stream),(level),(8),(-15),(9), (0), "1.3.1"
, (int)sizeof(z_stream))
;
575 if (err != Z_OK0) {
576 return err;
577 }
578
579 snprintf((char*)dest, *destLen, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
580 Z_DEFLATED8, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, 255);
581
582 // wire buffers
583 stream.next_in = const_cast<Bytef*>(source);
584 stream.avail_in = (uInt)sourceLen;
585 stream.next_out = ((Bytef*) dest) + 10;
586 stream.avail_out = *destLen - 18;
587 // doit
588 err = deflate(&stream, Z_FINISH4);
589 if (err != Z_STREAM_END1) {
590 deflateEnd(&stream);
591 return err;
592 }
593 err = deflateEnd(&stream);
594 crc = crc32(crc, (const Bytef *) source , sourceLen );
595 //CRC
596 *(((Bytef*) dest)+10+stream.total_out) = (Bytef)(crc & 0xFF);
597 *(((Bytef*) dest)+10+stream.total_out+1) = (Bytef)((crc>>8) & 0xFF);
598 *(((Bytef*) dest)+10+stream.total_out+2) = (Bytef)((crc>>16) & 0xFF);
599 *(((Bytef*) dest)+10+stream.total_out+3) = (Bytef)((crc>>24) & 0xFF);
600 // Length
601 *(((Bytef*) dest)+10+stream.total_out+4) = (Bytef)( sourceLen & 0xFF);
602 *(((Bytef*) dest)+10+stream.total_out+5) = (Bytef)(( sourceLen >>8) & 0xFF);
603 *(((Bytef*) dest)+10+stream.total_out+6) = (Bytef)(( sourceLen >>16) & 0xFF);
604 *(((Bytef*) dest)+10+stream.total_out+7) = (Bytef)(( sourceLen >>24) & 0xFF);
605 // return destLength
606 *destLen = 10 + stream.total_out + 8;
607
608 return err;
609}
610
611
612
613/*
614 * Item container implementation
615 */
616
617ServersInfo *ServerEntry::GetContainerInstance()
618{
619 return ServersInfo::m_This;
620}
621
622ServersInfo *ServersInfo::m_This = 0;
623
624ServersInfo::ServersInfo(CamulewebApp *webApp) : ItemsContainer<ServerEntry>(webApp)
625{
626 m_This = this;
627
628}
629
630bool ServersInfo::ReQuery()
631{
632 CECPacket srv_req(EC_OP_GET_SERVER_LIST);
633 const CECPacket *srv_reply = m_webApp->SendRecvMsg_v2(&srv_req);
634 if (!srv_reply) {
635 return false;
636 }
637 //
638 // query succeeded - flush existing values and refill
639 EraseAll();
640 for (CECPacket::const_iterator it = srv_reply->begin(); it != srv_reply->end(); ++it) {
641 const CECTag *tag = & *it;
642
643 ServerEntry Entry;
644 Entry.sServerName =
645 _SpecialChars(tag->GetTagByNameSafe(EC_TAG_SERVER_NAME)->GetStringData());
646 Entry.sServerDescription =
647 _SpecialChars(tag->GetTagByNameSafe(EC_TAG_SERVER_DESC)->GetStringData());
648 Entry.sServerIP = tag->GetIPv4Data().StringIP(false);
649 Entry.nServerIP = tag->GetIPv4Data().IP();
650 Entry.nServerPort = tag->GetIPv4Data().m_port;
651 Entry.nServerUsers =
652 tag->GetTagByNameSafe(EC_TAG_SERVER_USERS)->GetInt();
653 Entry.nServerMaxUsers =
654 tag->GetTagByNameSafe(EC_TAG_SERVER_USERS_MAX)->GetInt();
655 Entry.nServerFiles =
656 tag->GetTagByNameSafe(EC_TAG_SERVER_FILES)->GetInt();
657 AddItem(Entry);
658 }
659 delete srv_reply;
660
661 return true;
662}
663
664
665SharedFile::SharedFile(CEC_SharedFile_Tag *tag) : CECID(tag->ID())
666{
667 sFileName = _SpecialChars(tag->FileName());
668 lFileSize = tag->SizeFull();
669 sED2kLink = _SpecialChars(tag->FileEd2kLink());
670 nHash = tag->FileHash();
671
672 ProcessUpdate(tag);
673}
674
675void SharedFile::ProcessUpdate(CEC_SharedFile_Tag *tag)
676{
677 nFileTransferred = tag->GetXferred();
678 nFileAllTimeTransferred = tag->GetAllXferred();
679 nFileRequests = tag->GetRequests();
680 nFileAllTimeRequests = tag->GetAllRequests();
681 nFileAccepts = tag->GetAccepts();
682 nFileAllTimeAccepts = tag->GetAllAccepts();
683 sFileHash = nHash.Encode();
684 nFilePriority = tag->UpPrio();
685 if ( nFilePriority >= 10 ) {
686 bFileAutoPriority = true;
687 nFilePriority -= 10;
688 } else {
689 bFileAutoPriority = false;
690 }
691}
692
693SharedFileInfo *SharedFile::GetContainerInstance()
694{
695 return SharedFileInfo::m_This;
696}
697
698SharedFileInfo *SharedFileInfo::m_This = 0;
699
700SharedFileInfo::SharedFileInfo(CamulewebApp *webApp) :
701 UpdatableItemsContainer<SharedFile, CEC_SharedFile_Tag, uint32>(webApp)
702{
703 m_This = this;
704}
705
706
707bool SharedFileInfo::ReQuery()
708{
709 DoRequery(EC_OP_GET_SHARED_FILES, EC_TAG_KNOWNFILE);
710
711 return true;
712}
713
714
715DownloadFile::DownloadFile(CEC_PartFile_Tag *tag) : CECID(tag->ID())
716{
717 nHash = tag->FileHash();
718 sFileName = _SpecialChars(tag->FileName());
719 lFileSize = tag->SizeFull();
720 sFileHash = nHash.Encode();
721 sED2kLink = _SpecialChars(tag->FileEd2kLink());
722 lFileCompleted = tag->SizeDone();
723 lFileTransferred = tag->SizeXfer();
724 lFileSpeed = tag->Speed();
725 fCompleted = (100.0*lFileCompleted) / lFileSize;
726 wxtLastSeenComplete = wxDateTime( tag->LastSeenComplete() );
727
728 ProcessUpdate(tag);
729}
730
731void DownloadFile::ProcessUpdate(CEC_PartFile_Tag *tag)
732{
733 if (!tag) {
734 return;
735 }
736
737 lFilePrio = tag->DownPrio();
738 if ( lFilePrio >= 10 ) {
739 lFilePrio -= 10;
740 bFileAutoPriority = true;
741 } else {
742 bFileAutoPriority = false;
743 }
744 nCat = tag->FileCat();
745
746 nFileStatus = tag->FileStatus();
747 lSourceCount = tag->SourceCount();
748 lNotCurrentSourceCount = tag->SourceNotCurrCount();
749 lTransferringSourceCount = tag->SourceXferCount();
750 lSourceCountA4AF = tag->SourceCountA4AF();
751 if ( lTransferringSourceCount > 0 ) {
752 lFileCompleted = tag->SizeDone();
753 lFileTransferred = tag->SizeXfer();
754 lFileSpeed = tag->Speed();
755 fCompleted = (100.0*lFileCompleted) / lFileSize;
756 } else {
757 lFileSpeed = 0;
758 }
759 CECTag *gaptag = tag->GetTagByName(EC_TAG_PARTFILE_GAP_STATUS);
760 CECTag *parttag = tag->GetTagByName(EC_TAG_PARTFILE_PART_STATUS);
761 CECTag *reqtag = tag->GetTagByName(EC_TAG_PARTFILE_REQ_STATUS);
762
763 if (gaptag) {
764 m_Encoder.DecodeGaps(gaptag, m_Gaps);
765 }
766 if (parttag) {
767 m_Encoder.DecodeParts(parttag, m_PartInfo);
768 }
769 if (reqtag) {
770 ArrayOfUInts64 reqs;
771 m_Encoder.DecodeReqs(reqtag, reqs);
772 int reqcount = reqs.size() / 2;
773 m_ReqParts.resize(reqcount);
774 for (int i = 0; i < reqcount;i++) {
775 m_ReqParts[i].start = reqs[2*i];
776 m_ReqParts[i].end = reqs[2*i+1];
777 }
778 }
779}
780
781DownloadFileInfo *DownloadFile::GetContainerInstance()
782{
783 return DownloadFileInfo::m_This;
784}
785
786DownloadFileInfo *DownloadFileInfo::m_This = 0;
787
788DownloadFileInfo::DownloadFileInfo(CamulewebApp *webApp, CImageLib *imlib) :
789 UpdatableItemsContainer<DownloadFile, CEC_PartFile_Tag, uint32>(webApp)
790{
791 m_This = this;
792 m_ImageLib = imlib;
793}
794
795void DownloadFileInfo::LoadImageParams(wxString &tpl, int width, int height)
796{
797 m_Template = tpl;
798 m_width = width;
799 m_height = height;
800}
801
802void DownloadFileInfo::ItemInserted(DownloadFile *item)
803{
804 item->m_Image = new CDynProgressImage(m_width, m_height, m_Template, item);
805
806#ifdef WITH_LIBPNG1
807 m_ImageLib->AddImage(item->m_Image, wxT("/")L"/" + item->m_Image->Name());
808#endif
809}
810
811void DownloadFileInfo::ItemDeleted(DownloadFile *item)
812{
813#ifdef WITH_LIBPNG1
814 m_ImageLib->RemoveImage(wxT("/")L"/" + item->m_Image->Name());
815#else
816 delete item->m_Image;
817#endif
818}
819
820bool DownloadFileInfo::ReQuery()
821{
822 DoRequery(EC_OP_GET_DLOAD_QUEUE, EC_TAG_PARTFILE);
823
824 return true;
825}
826
827
828UploadFile::UploadFile(CEC_UpDownClient_Tag *tag) : CECID(tag->ID())
829{
830 sUserName = _SpecialChars(tag->ClientName());
831 nSpeed = tag->SpeedUp();
832 nTransferredUp = tag->XferUp();
833 nTransferredDown = tag->XferDown();
834 nUploadFile = 0;
835 tag->UploadFile(nUploadFile);
836}
837
838UploadsInfo *UploadFile::GetContainerInstance()
839{
840 return UploadsInfo::m_This;
841}
842
843UploadsInfo *UploadsInfo::m_This = 0;
844
845UploadsInfo::UploadsInfo(CamulewebApp *webApp) : ItemsContainer<UploadFile>(webApp)
846{
847 m_This = this;
848}
849
850bool UploadsInfo::ReQuery()
851{
852 CECPacket up_req(EC_OP_GET_ULOAD_QUEUE);
853 const CECPacket *up_reply = m_webApp->SendRecvMsg_v2(&up_req);
854 if (!up_reply) {
855 return false;
856 }
857 //
858 // query succeeded - flush existing values and refill
859 EraseAll();
860 for (CECPacket::const_iterator it = up_reply->begin(); it != up_reply->end(); ++it) {
861
862 UploadFile curr((CEC_UpDownClient_Tag *) & *it);
863
864 AddItem(curr);
865 }
866 delete up_reply;
867
868 return true;
869}
870
871SearchFile::SearchFile(CEC_SearchFile_Tag *tag)
872{
873 nHash = tag->FileHash();
874 sHash = nHash.Encode();
875 sFileName = _SpecialChars(tag->FileName());
876 lFileSize = tag->SizeFull();
877 lSourceCount = tag->SourceCount();
878 bPresent = tag->AlreadyHave();
879}
880
881void SearchFile::ProcessUpdate(CEC_SearchFile_Tag *tag)
882{
883 lSourceCount = tag->SourceCount();
884}
885
886SearchInfo *SearchFile::GetContainerInstance()
887{
888 return SearchInfo::m_This;
889}
890
891SearchInfo *SearchInfo::m_This = 0;
892
893SearchInfo::SearchInfo(CamulewebApp *webApp) :
894 UpdatableItemsContainer<SearchFile, CEC_SearchFile_Tag, uint32>(webApp)
895{
896 m_This = this;
897}
898
899bool SearchInfo::ReQuery()
900{
901 DoRequery(EC_OP_SEARCH_RESULTS, EC_TAG_SEARCHFILE);
902
903 return true;
904}
905
906
907/*!
908 * Image classes:
909 *
910 * CFileImage: simply represent local file
911 * CDynProgressImage: dynamically generated from gap info
912 */
913
914CAnyImage::CAnyImage(int size)
915{
916 m_size = 0;
917 m_alloc_size = size;
918 if ( m_alloc_size ) {
919 m_data = new unsigned char[m_alloc_size];
920 } else {
921 m_data = 0;
922 }
923}
924
925CAnyImage::CAnyImage(int width, int height) : m_width(width), m_height(height)
926{
927 m_size = 0;
928 // allocate considering image header
929 m_alloc_size = width * height * sizeof(uint32) + 0x100;
930 if ( m_alloc_size ) {
931 m_data = new unsigned char[m_alloc_size];
932 } else {
933 m_data = 0;
934 }
935}
936
937CAnyImage::~CAnyImage()
938{
939 if ( m_data ) {
940 delete [] m_data;
941 }
942}
943
944void CAnyImage::Realloc(int size)
945{
946 if ( size == m_alloc_size ) {
947 return;
948 }
949 // always grow, but shrink only x2
950 if ( (size > m_alloc_size) || (size < (m_alloc_size / 2)) ) {
951 m_alloc_size = size;
952 if ( m_data ) {
953 delete [] m_data;
954 }
955 m_data = new unsigned char[m_alloc_size];
956 }
957}
958
959unsigned char *CAnyImage::RequestData(int &size)
960{
961 size = m_size;
962 return m_data;
963}
964
965void CAnyImage::SetHttpType(wxString ext)
966{
967 m_Http = wxT("Content-Type: ")L"Content-Type: " + ext + wxT("\r\n")L"\r\n";
968
969 time_t t = time(NULL__null);
970 char tmp[255];
971 strftime(tmp, 255, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t));
972 m_Http += wxT("Last-Modified: ")L"Last-Modified: " + wxString(char2unicode(tmp)) + wxT("\r\n")L"\r\n";
973
974 m_Http += wxT("ETag: ")L"ETag: " + MD5Sum(char2unicode(tmp)).GetHash() + wxT("\r\n")L"\r\n";
975}
976
977CFileImage::CFileImage(const wxString& name) : CAnyImage(0)
978{
979 m_size = 0;
980 m_name = name;
981#ifdef __WINDOWS__
982 wxFFile fis(m_name, wxT("rb")L"rb");
983#else
984 wxFFile fis(m_name);
985#endif
986 // FIXME: proper logging is needed
987 if ( fis.IsOpened() ) {
988 size_t file_size = fis.Length();
989 if ( file_size ) {
990 Realloc(fis.Length());
991 m_size = fis.Read(m_data,file_size);
992 } else {
993 printf("CFileImage: file %s have zero length\n", (const char *)unicode2char(m_name));
994 }
995 wxString ext = m_name.Right(3).MakeLower();
996 if ( ext == wxT("css")L"css" ) {
997 SetHttpType(wxT("text/css")L"text/css");
998 } else {
999 SetHttpType(wxT("image/")L"image/" + ext);
1000 }
1001 } else {
1002 printf("CFileImage: failed to open %s\n", (const char *)unicode2char(m_name));
1003 }
1004}
1005
1006/*!
1007 * "Modifiers" for 3D look of progress bar. Those modifiers must be substracted from
1008 * image (with saturation), values, and not multiplied, as amule doesn for some reason.
1009 *
1010 */
1011CImage3D_Modifiers::CImage3D_Modifiers(int width)
1012{
1013 m_width = width;
1014 m_modifiers = new unsigned char[m_width];
1015 for(int i = 0; i < m_width; i++) {
1016 // "70" - webserver uses fixed depth
1017 double f_curr_mod = 30 * (1 + cos( (2 * M_PI3.14159265358979323846) * ( m_width - (((double)i)/m_width) ) ) );
1018 m_modifiers[i] = (unsigned char)f_curr_mod;
1019 }
1020}
1021
1022CImage3D_Modifiers::~CImage3D_Modifiers()
1023{
1024 delete [] m_modifiers;
1025}
1026
1027CProgressImage::CProgressImage(int width, int height, wxString &tmpl, DownloadFile *file) :
1028 CAnyImage(width, height), m_template(tmpl)
1029{
1030 m_file = file;
1031 m_ColorLine = new uint32[m_width];
1032}
1033
1034CProgressImage::~CProgressImage()
1035{
1036 delete [] m_ColorLine;
1037}
1038
1039void CProgressImage::CreateSpan()
1040{
1041 // Step 1: get gap list
1042 const Gap_Struct * gap_list = (const Gap_Struct *) &(m_file->m_Gaps[0]);
1043 int gap_list_size = m_file->m_Gaps.size() / 2;
1044
1045 // allocate for worst case !
1046 int color_gaps_alloc = 2 * (2 * gap_list_size + m_file->lFileSize / PARTSIZE + 1);
1047 Color_Gap_Struct *colored_gaps = new Color_Gap_Struct[color_gaps_alloc];
1048
1049 // Step 2: combine gap and part status information
1050
1051 // Init first item to dummy info, so we will always have "previous" item
1052 int colored_gaps_size = 0;
1053 colored_gaps[0].start = 0;
1054 colored_gaps[0].end = 0;
1055 colored_gaps[0].color = 0xffffffff;
1056 for (int j = 0; j < gap_list_size;j++) {
1057 uint64 gap_start = gap_list[j].start;
1058 uint64 gap_end = gap_list[j].end;
1059
1060 uint32 start = gap_start / PARTSIZE;
1061 uint32 end = (gap_end / PARTSIZE) + 1;
1062
1063 for (uint32 i = start; i < end; i++) {
1064 COLORTYPE color = RGB(255, 0, 0);
1065 if (m_file->m_PartInfo.size() > i && m_file->m_PartInfo[i]) {
1066 int blue = 210 - ( 22 * ( m_file->m_PartInfo[i] - 1 ) );
1067 color = RGB( 0, ( blue < 0 ? 0 : blue ), 255 );
1068 }
1069
1070 uint64 fill_gap_begin = ( (i == start) ? gap_start: PARTSIZE * i );
1071 uint64 fill_gap_end = ( (i == (end - 1)) ? gap_end : PARTSIZE * ( i + 1 ) );
1072
1073 wxASSERT(colored_gaps_size < color_gaps_alloc)do { if ( colored_gaps_size < color_gaps_alloc ) { } else if
( wxTheAssertHandler && (wxOnAssert("WebServer.cpp",
1073, __FUNCTION__, "colored_gaps_size < color_gaps_alloc"
, (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false
; asm volatile ("int $3"); } } while ( (void)0, 0 )
;
1074
1075 if ( (colored_gaps[colored_gaps_size].end == fill_gap_begin) &&
1076 (colored_gaps[colored_gaps_size].color == color) ) {
1077 colored_gaps[colored_gaps_size].end = fill_gap_end;
1078 } else {
1079 colored_gaps_size++;
1080 colored_gaps[colored_gaps_size].start = fill_gap_begin;
1081 colored_gaps[colored_gaps_size].end = fill_gap_end;
1082 colored_gaps[colored_gaps_size].color = color;
1083 }
1084 }
1085
1086 }
1087 //
1088 // Now line rendering
1089 for(int i = 0; i < m_width; ++i) {
1090 m_ColorLine[i] = 0x0;
1091 }
1092 if (m_file->lFileSize < (uint32)m_width) {
1093 //
1094 // if file is that small, draw it in single step
1095 //
1096 if (!m_file->m_ReqParts.empty()) {
1097 for(int i = 0; i < m_width; ++i) {
1098 m_ColorLine[i] = RGB(255, 208, 0);
1099 }
1100 } else if ( colored_gaps_size ) {
1101 for(int i = 0; i < m_width; ++i) {
1102 m_ColorLine[i] = colored_gaps[1].color;
1103 }
1104 }
1105 } else {
1106 uint32 factor = m_file->lFileSize / m_width;
1107 for (int i = 1; i <= colored_gaps_size;i++) {
1108 uint32 start = colored_gaps[i].start / factor;
1109 uint32 end = colored_gaps[i].end / factor;
1110 if ((int)end > m_width) {
1111 end = m_width;
1112 }
1113 for (uint32 j = start; j < end; j++) {
1114 m_ColorLine[j] = colored_gaps[i].color;
1115 }
1116 }
1117 // overwrite requested parts
1118 for (uint32 i = 0; i < m_file->m_ReqParts.size(); i++) {
1119 uint32 start = m_file->m_ReqParts[i].start / factor;
1120 uint32 end = m_file->m_ReqParts[i].end / factor;
1121 if ((int)end > m_width) {
1122 end = m_width;
1123 }
1124 for (uint32 j = start; j < end; j++) {
1125 m_ColorLine[j] = RGB(255, 208, 0);
1126 }
1127 }
1128 }
1129 delete [] colored_gaps;
1130}
1131
1132#ifdef WITH_LIBPNG1
1133
1134CDynPngImage::CDynPngImage(int w, int h) : CAnyImage(w, h)
1135{
1136
1137 //
1138 // Allocate array of "row pointers" - libpng need it in this form
1139 // Fill it also with the image data
1140 //
1141 m_img_data = new png_byte[3*m_width*m_height];
1142 memset(m_img_data, 0, 3*m_width*m_height);
1143 m_row_ptrs = new png_bytep [m_height];
1144 for (int i = 0; i < m_height;i++) {
1145 m_row_ptrs[i] = &m_img_data[3*m_width*i];
1146 }
1147
1148}
1149
1150CDynPngImage::~CDynPngImage()
1151{
1152 delete [] m_row_ptrs;
1153 delete [] m_img_data;
1154}
1155
1156void CDynPngImage::png_write_fn(png_structp png_ptr, png_bytep data, png_size_t length)
1157{
1158 CDynPngImage *This = static_cast<CDynPngImage *>(png_get_io_ptr(png_ptr));
1159 wxASSERT((png_size_t)(This->m_size + length) <= (png_size_t)This->m_alloc_size)do { if ( (png_size_t)(This->m_size + length) <= (png_size_t
)This->m_alloc_size ) { } else if ( wxTheAssertHandler &&
(wxOnAssert("WebServer.cpp", 1159, __FUNCTION__, "(png_size_t)(This->m_size + length) <= (png_size_t)This->m_alloc_size"
, (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false
; asm volatile ("int $3"); } } while ( (void)0, 0 )
;
1160 memcpy(This->m_data + This->m_size, data, length);
1161 This->m_size += length;
1162}
1163
1164
1165unsigned char *CDynPngImage::RequestData(int &size)
1166{
1167 // write png into buffer
1168 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING"1.6.44", 0, 0, 0);
1169 png_infop info_ptr = png_create_info_struct(png_ptr);
1170 png_set_IHDR(png_ptr, info_ptr, m_width, m_height, 8, PNG_COLOR_TYPE_RGB(2),
1171 PNG_INTERLACE_NONE0, PNG_COMPRESSION_TYPE_DEFAULT0, PNG_FILTER_TYPE_DEFAULT0);
1172 png_set_write_fn(png_ptr, this, png_write_fn, 0);
1173
1174 m_size = 0;
1175 png_write_info(png_ptr, info_ptr);
1176 png_write_image(png_ptr, (png_bytep *)m_row_ptrs);
1177 png_write_end(png_ptr, 0);
1178 png_destroy_write_struct(&png_ptr, &info_ptr);
1179
1180 return CAnyImage::RequestData(size);
1181}
1182
1183CDynProgressImage::CDynProgressImage(int width, int height, wxString &tmpl, DownloadFile *file) :
1184 CAnyImage(width, height),
1185 CProgressImage(width, height, tmpl, file),
1186 CDynPngImage(width, height),
1187 m_modifiers(height)
1188{
1189 m_name = wxT("dyn_")L"dyn_" + m_file->sFileHash + wxT(".png")L".png";
1190}
1191
1192CDynProgressImage::~CDynProgressImage()
1193{
1194}
1195
1196wxString CDynProgressImage::GetHTML()
1197{
1198 // template contain %s (name) %d (width) %s (alt)
1199 return (CFormat(m_template) % m_name % m_width % wxT("Progress bar")L"Progress bar").GetString();
1200}
1201
1202void CDynProgressImage::DrawImage()
1203{
1204 CreateSpan();
1205
1206 for(int i = 0; i < m_height; i++) {
1207 memset(m_row_ptrs[i], 0, 3*m_width);
1208 }
1209 for(int i = 0; i < m_height/2; i++) {
1210 png_bytep u_row = m_row_ptrs[i];
1211 png_bytep d_row = m_row_ptrs[m_height-i-1];
1212 for(int j = 0; j < m_width; j++) {
1213 set_rgb_color_val(u_row+3*j, m_ColorLine[j], m_modifiers[i]);
1214 set_rgb_color_val(d_row+3*j, m_ColorLine[j], m_modifiers[i]);
1215 }
1216 }
1217}
1218
1219unsigned char *CDynProgressImage::RequestData(int &size)
1220{
1221 // create new one
1222 DrawImage();
1223
1224 return CDynPngImage::RequestData(size);
1225}
1226
1227#else
1228
1229CDynProgressImage::CDynProgressImage(int width, int height, wxString &tmpl, DownloadFile *file) :
1230 CAnyImage(width, height),
1231 CProgressImage(width, height, tmpl, file)
1232{
1233 m_name = wxT("dyn_")L"dyn_" + m_file->sFileHash + wxT(".png")L".png";
1234
1235}
1236
1237
1238wxString CDynProgressImage::GetHTML()
1239{
1240 static wxChar *progresscolor[12] = {
1241 wxT("transparent.gif")L"transparent.gif", wxT("black.gif")L"black.gif", wxT("yellow.gif")L"yellow.gif", wxT("red.gif")L"red.gif",
1242 wxT("blue1.gif")L"blue1.gif", wxT("blue2.gif")L"blue2.gif", wxT("blue3.gif")L"blue3.gif", wxT("blue4.gif")L"blue4.gif",
1243 wxT("blue5.gif")L"blue5.gif", wxT("blue6.gif")L"blue6.gif", wxT("green.gif")L"green.gif", wxT("greenpercent.gif")L"greenpercent.gif" };
1244
1245 CreateSpan();
1246
1247 wxString str;
1248 uint32 lastcolor = m_ColorLine[0];
1249 int lastindex = 0;
1250 for(int i = 0; i < m_width; i++) {
1251 if ( (lastcolor != m_ColorLine[i]) || (i == (m_width - 1)) ) {
1252 int color_idx = -1;
1253 if ( lastcolor & RGB(0, 0, 0xff) ) { // blue
1254 int green = (lastcolor >> 8) & 0xff;
1255 // reverse calculation: green = 210 - ( 22 * ( part_info[i] - 1 ) )
1256 wxASSERT( !green || (green < 211) )do { if ( !green || (green < 211) ) { } else if ( wxTheAssertHandler
&& (wxOnAssert("WebServer.cpp", 1256, __FUNCTION__, "!green || (green < 211)"
, (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false
; asm volatile ("int $3"); } } while ( (void)0, 0 )
;
1257 color_idx = (green) ? (210 - green) / 22 + 1 : 11;
1258 // now calculate it same way as PartFile did
1259 color_idx = (color_idx > 10) ? 9 : (4 + color_idx / 2);
1260 } else {
1261 if ( lastcolor & RGB(0, 0xff, 0) ) { // yellow
1262 color_idx = 2;
1263 } else {
1264 if ( lastcolor & RGB(0xff, 0, 0) ) { // red
1265 color_idx = 3;
1266 } else {
1267 color_idx = 1;
1268 }
1269 }
1270 }
1271 str += (CFormat(m_template) % progresscolor[color_idx]
1272 % (i - lastindex) % wxString(progresscolor[color_idx]).BeforeLast(wxT('.')L'.')).GetString();
1273 lastindex = i;
1274 lastcolor = m_ColorLine[i];
1275 }
1276 }
1277
1278 return str;
1279}
1280
1281#endif
1282
1283CStatsData::CStatsData(int size)
1284{
1285 m_size = size;
1286 m_data = new uint32[size];
1287 m_max_value = 0;
1288 //
1289 // initial situation: all data is 0's
1290 //
1291 memset(m_data, 0, m_size*sizeof(int));
1292 m_start_index = m_curr_index = 0;
1293 m_end_index = size - 1;
1294}
1295
1296CStatsData::~CStatsData()
1297{
1298 delete [] m_data;
1299}
1300
1301uint32 CStatsData::GetFirst()
1302{
1303 m_curr_index = m_start_index;
1304 return m_data[m_curr_index];
1305}
1306
1307uint32 CStatsData::GetNext()
1308{
1309 m_curr_index++;
1310 m_curr_index %= m_size;
1311 return m_data[m_curr_index];
1312}
1313
1314void CStatsData::PushSample(uint32 sample)
1315{
1316 m_start_index = (m_start_index + 1) % m_size;
1317 m_end_index = (m_end_index + 1) % m_size;
1318 m_data[m_start_index] = sample;
1319
1320 if ( m_max_value < sample ) {
1321 m_max_value = sample;
1322 }
1323}
1324
1325CStatsCollection::CStatsCollection(int size, CamulewebApp *iface)
1326{
1327 m_down_speed = new CStatsData(size);
1328 m_up_speed = new CStatsData(size);
1329 m_conn_number = new CStatsData(size);
1330 m_kad_count = new CStatsData(size);
1331
1332 m_iface = iface;
1333 m_LastTimeStamp = 0.0;
1334 m_size = size;
1335}
1336
1337CStatsCollection::~CStatsCollection()
1338{
1339 delete m_down_speed;
1340 delete m_up_speed;
1341 delete m_conn_number;
1342 delete m_kad_count;
1343}
1344
1345void CStatsCollection::ReQuery()
1346{
1347 CECPacket request(EC_OP_GET_STATSGRAPHS);
1348
1349 request.AddTag(CECTag(EC_TAG_STATSGRAPH_WIDTH, (uint16)m_size));
1350
1351 uint16 m_nGraphScale = 1;
1352 request.AddTag(CECTag(EC_TAG_STATSGRAPH_SCALE, m_nGraphScale));
1353 if (m_LastTimeStamp > 0.0) {
1354 request.AddTag(CECTag(EC_TAG_STATSGRAPH_LAST, m_LastTimeStamp));
1355 }
1356
1357 const CECPacket *response = m_iface->SendRecvMsg_v2(&request);
1358
1359 m_LastTimeStamp = response->GetTagByNameSafe(EC_TAG_STATSGRAPH_LAST)->GetDoubleData();
1360
1361 const CECTag *dataTag = response->GetTagByName(EC_TAG_STATSGRAPH_DATA);
1362 const uint32 *data = (const uint32 *)dataTag->GetTagData();
1363 unsigned int count = dataTag->GetTagDataLen() / sizeof(uint32);
1364 for (unsigned int i = 0; i < count; i += 4) {
1365 m_down_speed->PushSample(ENDIAN_NTOHL(data[i+0])( ((wxUint32) ( (((wxUint32) (data[i+0]) & (wxUint32) 0x000000ffU
) << 24) | (((wxUint32) (data[i+0]) & (wxUint32) 0x0000ff00U
) << 8) | (((wxUint32) (data[i+0]) & (wxUint32) 0x00ff0000U
) >> 8) | (((wxUint32) (data[i+0]) & (wxUint32) 0xff000000U
) >> 24))) )
);
1366 m_up_speed->PushSample(ENDIAN_NTOHL(data[i+1])( ((wxUint32) ( (((wxUint32) (data[i+1]) & (wxUint32) 0x000000ffU
) << 24) | (((wxUint32) (data[i+1]) & (wxUint32) 0x0000ff00U
) << 8) | (((wxUint32) (data[i+1]) & (wxUint32) 0x00ff0000U
) >> 8) | (((wxUint32) (data[i+1]) & (wxUint32) 0xff000000U
) >> 24))) )
);
1367 m_conn_number->PushSample(ENDIAN_NTOHL(data[i+2])( ((wxUint32) ( (((wxUint32) (data[i+2]) & (wxUint32) 0x000000ffU
) << 24) | (((wxUint32) (data[i+2]) & (wxUint32) 0x0000ff00U
) << 8) | (((wxUint32) (data[i+2]) & (wxUint32) 0x00ff0000U
) >> 8) | (((wxUint32) (data[i+2]) & (wxUint32) 0xff000000U
) >> 24))) )
);
1368 m_kad_count->PushSample(ENDIAN_NTOHL(data[i+3])( ((wxUint32) ( (((wxUint32) (data[i+3]) & (wxUint32) 0x000000ffU
) << 24) | (((wxUint32) (data[i+3]) & (wxUint32) 0x0000ff00U
) << 8) | (((wxUint32) (data[i+3]) & (wxUint32) 0x00ff0000U
) >> 8) | (((wxUint32) (data[i+3]) & (wxUint32) 0xff000000U
) >> 24))) )
);
1369 }
1370}
1371
1372//
1373// Dynamically generated statistic images
1374//
1375#ifdef WITH_LIBPNG1
1376
1377CDynStatisticImage::CDynStatisticImage(int height, bool scale1024, CStatsData *data) :
1378 CAnyImage(data->Size(), height), CDynPngImage(data->Size(), height)
1379{
1380 m_data = data;
1381 m_scale1024 = scale1024;
1382
1383 // actual name doesn't matter, just make it unique
1384 m_name = CFormat(wxT("dyn_%p_stat.png")L"dyn_%p_stat.png") % data;
1385
1386 m_num_font_w_size = 8;
1387 m_num_font_h_size = 16;
1388
1389 // leave enough space for 4 digit number
1390 int img_delta = m_num_font_w_size / 4;
1391 m_left_margin = 4*(m_num_font_w_size + img_delta) + img_delta;
1392 // leave enough space for number height
1393 m_bottom_margin = m_num_font_h_size;
1394
1395
1396 m_y_axis_size = m_height - m_bottom_margin;
1397 // allocate storage for background. Using 1 chunk to speed up
1398 // the rendering
1399 m_background = new png_byte[m_width*m_height*3];
1400 m_row_bg_ptrs = new png_bytep[m_height];
1401 for(int i = 0; i < m_height; i++) {
1402 m_row_bg_ptrs[i] = &m_background[i*m_width*3];
1403 }
1404
1405 //
1406 // Prepare background
1407 //
1408 static const COLORTYPE bg_color = RGB(0x00, 0x00, 0x40);
1409 for(int i = 0; i < m_height; i++) {
1410 png_bytep u_row = m_row_bg_ptrs[i];
1411 for(int j = 0; j < m_width; j++) {
1412 set_rgb_color_val(u_row+3*j, bg_color, 0);
1413 }
1414 }
1415 //
1416 // draw axis
1417 //
1418 static const COLORTYPE axis_color = RGB(0xff, 0xff, 0xff);
1419 // Y
1420 for(int i = m_bottom_margin; i < m_y_axis_size; i++) {
1421 png_bytep u_row = m_row_bg_ptrs[i];
1422 set_rgb_color_val(u_row+3*(m_left_margin + 0), axis_color, 0);
1423 set_rgb_color_val(u_row+3*(m_left_margin + 1), axis_color, 0);
1424 }
1425 // X
1426 for(int j = m_left_margin; j < m_width; j++) {
1427 set_rgb_color_val(m_row_bg_ptrs[m_y_axis_size - 0]+3*j, axis_color, 0);
1428 set_rgb_color_val(m_row_bg_ptrs[m_y_axis_size - 1]+3*j, axis_color, 0);
1429 }
1430
1431 // horisontal grid
1432 int v_grid_size = m_y_axis_size / 4;
1433 for(int i = m_y_axis_size - v_grid_size; i >= v_grid_size; i -= v_grid_size) {
1434 png_bytep u_row = m_row_bg_ptrs[i];
1435 for(int j = m_left_margin; j < m_width; j++) {
1436 if ( (j % 10) < 5 ) {
1437 set_rgb_color_val(u_row+3*j, axis_color, 0);
1438 }
1439 }
1440 }
1441
1442 //
1443 // Pre-create masks for digits
1444 //
1445 for(int i = 0; i < 10; i++) {
1446 m_digits[i] = new CNumImageMask(i, m_num_font_w_size, m_num_font_h_size);
1447 }
1448}
1449
1450CDynStatisticImage::~CDynStatisticImage()
1451{
1452 delete [] m_row_bg_ptrs;
1453 delete [] m_background;
1454 for(int i = 0; i < 10; i++) {
1455 delete m_digits[i];
1456 }
1457}
1458
1459void CDynStatisticImage::DrawImage()
1460{
1461 // copy background first
1462 memcpy(m_img_data, m_background, m_width*m_height*3);
1463
1464 //
1465 // Now graph itself
1466 //
1467 static const COLORTYPE graph_color = RGB(0xff, 0x00, 0x00);
1468 int maxval = m_data->Max();
1469
1470 if ( m_scale1024 ) {
1471 if ( maxval > 1024 ) {
1472 maxval /= 1024;
1473 } else {
1474 maxval = 1;
1475 }
1476 }
1477 //
1478 // Check if we need to scale data up or down
1479 //
1480 int m_scale_up = 1, m_scale_down = 1;
1481 if ( maxval >= (m_height - m_bottom_margin) ) {
1482 m_scale_down = 1 + (maxval / (m_y_axis_size - 10));
1483 }
1484 // if maximum value is 1/5 or less of graph height - scale it UP, to make 2/3
1485 if ( maxval && (maxval < (m_y_axis_size / 5)) ) {
1486 m_scale_up = (2*m_y_axis_size / 3) / maxval;
1487 }
1488
1489 //
1490 // draw axis scale
1491 //
1492 int img_delta = m_num_font_w_size / 4;
1493 // Number "0" is always there
1494 m_digits[0]->Apply(m_row_ptrs, 3*img_delta+2*m_num_font_w_size, m_y_axis_size-m_num_font_h_size-5);
1495
1496 //
1497 // When data is scaled down, axis are scaled UP and viceversa
1498 int y_axis_max = m_y_axis_size;
1499 if ( m_scale_down != 1 ) {
1500 y_axis_max *= m_scale_down;
1501 } else if ( m_scale_up != 1 ) {
1502 y_axis_max /= m_scale_up;
1503 }
1504
1505 // X---
1506 if ( y_axis_max > 999 ) {
1507 m_digits[y_axis_max / 1000]->Apply(m_row_ptrs, img_delta, img_delta);
1508 }
1509 // -X--
1510 if ( y_axis_max > 99 ) {
1511 m_digits[(y_axis_max % 1000) / 100]->Apply(m_row_ptrs,
1512 2*img_delta+m_num_font_w_size, img_delta);
1513 }
1514 // --X-
1515 if ( y_axis_max > 9 ) {
1516 m_digits[(y_axis_max % 100) / 10]->Apply(m_row_ptrs,
1517 3*img_delta+2*m_num_font_w_size, img_delta);
1518 }
1519 // ---X
1520 m_digits[y_axis_max % 10]->Apply(m_row_ptrs, 4*img_delta+3*m_num_font_w_size, img_delta);
1521
1522 int prev_data = m_data->GetFirst();
1523 if ( m_scale_down != 1 ) {
1524 prev_data /= m_scale_down;
1525 } else if ( m_scale_up != 1 ) {
1526 prev_data *= m_scale_up;
1527 }
1528 if ( m_scale1024 ) {
1529 if ( prev_data > 1024) {
1530 prev_data /= 1024;
1531 } else {
1532 prev_data = 1;
1533 }
1534 }
1535 for(int j = m_left_margin + 1, curr_data = m_data->GetNext(); j < m_width; j++, curr_data = m_data->GetNext()) {
1536 if ( m_scale_down != 1 ) {
1537 curr_data /= m_scale_down;
1538 } else if ( m_scale_up != 1 ) {
1539 curr_data *= m_scale_up;
1540 }
1541 if ( m_scale1024 ) {
1542 if ( curr_data > 1024) {
1543 curr_data /= 1024;
1544 } else {
1545 curr_data = 1;
1546 }
1547 }
1548 //
1549 // draw between curr_data and prev_data
1550 //
1551 int min_y, max_y;
1552 if ( prev_data > curr_data ) {
1553 min_y = curr_data; max_y = prev_data;
1554 } else {
1555 min_y = prev_data; max_y = curr_data;
1556 }
1557 for(int k = min_y; k <= max_y; k++) {
1558 int i = m_y_axis_size - k;
1559 png_bytep u_row = m_row_ptrs[i];
1560 set_rgb_color_val(u_row+3*j, graph_color, 0);
1561 }
1562 prev_data = curr_data;
1563 }
1564}
1565
1566unsigned char *CDynStatisticImage::RequestData(int &size)
1567{
1568 DrawImage();
1569
1570 return CDynPngImage::RequestData(size);
1571}
1572
1573wxString CDynStatisticImage::GetHTML()
1574{
1575 return wxEmptyString;
1576}
1577
1578//
1579// Imprint numbers on generated png's
1580//
1581// 0 1 2 3 4 5 6 7 8 9
1582const int CNumImageMask::m_num_to_7_decode[] = {0x77, 0x24, 0x5d, 0x6d, 0x2e, 0x5d, 0x7a, 0x25, 0x7f, 0x2f};
1583
1584CNumImageMask::CNumImageMask(int number, int width, int height)
1585{
1586 m_v_segsize = height / 2;
1587 m_h_segsize = width;
1588 m_height = height;
1589 m_width = width;
1590
1591 m_row_mask_ptrs = new png_bytep[m_height];
1592 for(int i = 0; i < m_height; i++) {
1593 m_row_mask_ptrs[i] = new png_byte[3*m_width];
1594 memset(m_row_mask_ptrs[i], 0x00, 3*m_width);
1595 }
1596
1597 int seg_status = m_num_to_7_decode[number];
1598 for(int i = 0; i < 7; i++) {
1599 if ( seg_status & (1 << i) ) {
1600 DrawSegment(i);
1601 }
1602 }
1603}
1604
1605CNumImageMask::~CNumImageMask()
1606{
1607 for(int i = 0; i < m_height; i++) {
1608 delete [] m_row_mask_ptrs[i];
1609 }
1610 delete [] m_row_mask_ptrs;
1611}
1612
1613void CNumImageMask::Apply(png_bytep *image, int offx, int offy)
1614{
1615 offx *= 3;
1616 for(int i = 0; i < m_height; i++) {
1617 png_bytep img_row = image[offy + i];
1618 png_bytep num_row = m_row_mask_ptrs[i];
1619 for(int j = 0; j < m_width*3; j++) {
1620 img_row[offx + j] |= num_row[j];
1621 }
1622 }
1623}
1624
1625void CNumImageMask::DrawHorzLine(int off)
1626{
1627 png_bytep m_row = m_row_mask_ptrs[off*(m_v_segsize-1)];
1628 for(int i = 0; i < m_h_segsize; i++) {
1629 m_row[i*3] = m_row[i*3+1] = m_row[i*3+2] = 0xff;
1630 }
1631}
1632
1633void CNumImageMask::DrawVertLine(int offx, int offy)
1634{
1635 for(int i = 0; i < m_v_segsize; i++) {
1636 png_bytep m_row = m_row_mask_ptrs[offy*(m_v_segsize-1)+i];
1637 int x_idx = offx*(m_h_segsize-1)*3;
1638 m_row[x_idx] = m_row[x_idx+1] = m_row[x_idx+2] = 0xff;
1639 }
1640}
1641
1642/*
1643 * Segment id decoding defined as following
1644 *
1645 * ---- 0 ----
1646 * | |
1647 * 1 2
1648 * |___ 3 ___|
1649 * | |
1650 * 4 5
1651 * |___ 6 ___|
1652 */
1653void CNumImageMask::DrawSegment(int id)
1654{
1655 switch(id) {
1656 case 0:
1657 DrawHorzLine(0);
1658 break;
1659 case 1:
1660 DrawVertLine(0, 0);
1661 break;
1662 case 2:
1663 DrawVertLine(1, 0);
1664 break;
1665 case 3:
1666 DrawHorzLine(1);
1667 break;
1668 case 4:
1669 DrawVertLine(0, 1);
1670 break;
1671 case 5:
1672 DrawVertLine(1, 1);
1673 break;
1674 case 6:
1675 DrawHorzLine(2);
1676 break;
1677 default:
1678 wxFAILdo { if ( wxTheAssertHandler && (wxOnAssert("WebServer.cpp"
, 1678, __FUNCTION__, "\"Assert failure\"", (const char*)__null
), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile (
"int $3"); } } while ( (void)0, 0 )
;
1679 break;
1680 }
1681}
1682
1683#endif
1684
1685CImageLib::CImageLib(wxString image_dir) : m_image_dir(image_dir)
1686{
1687}
1688
1689CImageLib::~CImageLib()
1690{
1691}
1692
1693void CImageLib::AddImage(CAnyImage *img, const wxString &name)
1694{
1695 ImageMap::iterator it = m_image_map.find(name);
1696 if (it == m_image_map.end()) {
1697 m_image_map[name] = img;
1698 } else {
1699 delete it->second;
1700 it->second = img;
1701 }
1702}
1703
1704void CImageLib::RemoveImage(const wxString &name)
1705{
1706 ImageMap::iterator it = m_image_map.find(name);
1707 if (it != m_image_map.end()) {
1708 delete it->second;
1709 m_image_map.erase(it);
1710 }
1711}
1712
1713CAnyImage *CImageLib::GetImage(const wxString &name)
1714{
1715 ImageMap::iterator it = m_image_map.find(name);
1716 if (it != m_image_map.end()) {
1717 return it->second;
1718 }
1719 wxFileName filename(m_image_dir + name);
1720 CFileImage *fimg = new CFileImage(filename.GetFullPath());
1721 if ( fimg->OpenOk() ) {
1722 m_image_map[name] = fimg;
1723 return fimg;
1724 } else {
1725 delete fimg;
1726 return 0;
1727 }
1728}
1729
1730/*
1731 * Script-based webserver
1732 */
1733CScriptWebServer::CScriptWebServer(CamulewebApp *webApp, const wxString& templateDir)
1734 : CWebServerBase(webApp, templateDir), m_wwwroot(templateDir)
1735{
1736 wxString img_tmpl(wxT("<img src=\"%s\" height=\"20\" width=\"%d\" alt=\"%s\">")L"<img src=\"%s\" height=\"20\" width=\"%d\" alt=\"%s\">");
1737 m_DownloadFileInfo.LoadImageParams(img_tmpl, 200, 20);
1738
1739 if ( ::wxFileExists(wxFileName(m_wwwroot, wxT("index.html")L"index.html").GetFullPath()) ) {
1740 m_index = wxT("index.html")L"index.html";
1741 } else if ( ::wxFileExists(wxFileName(m_wwwroot, wxT("index.php")L"index.php").GetFullPath()) ) {
1742 m_index = wxT("index.php")L"index.php";
1743 } else {
1744 webInterface->Show(_("Index file not found: ")wxGetTranslation(("Index file not found: ")) +
1745 wxFileName(m_wwwroot, wxT("index.{html,php}")L"index.{html,php}").GetFullPath() + wxT("\n")L"\n");
1746 }
1747}
1748
1749CScriptWebServer::~CScriptWebServer()
1750{
1751}
1752
1753char *CScriptWebServer::GetErrorPage(const char *message, long &size)
1754{
1755 char *buf = new char [1024];
1756 snprintf(buf, 1024,
1757 "<html><title> Error -%s </title></html>", message);
1758
1759 size = strlen(buf);
1760
1761 return buf;
1762}
1763
1764char *CScriptWebServer::Get_404_Page(long &size)
1765{
1766 char *buf = new char [1024];
1767 strcpy(buf, "<html><title> Error - requested page not found </title></html>");
1768
1769 size = strlen(buf);
1770
1771 return buf;
1772}
1773
1774char *CScriptWebServer::ProcessHtmlRequest(const char *filename, long &size)
1775{
1776 FILE *f = fopen(filename, "r");
1777 if ( !f ) {
1778 return Get_404_Page(size);
1779 }
1780 if ( fseek(f, 0, SEEK_END2) != 0 ) {
1781 fclose(f);
1782 return GetErrorPage("fseek failed", size);
1783 }
1784
1785 size = ftell(f);
1786 char *buf = new char [size+1];
1787 rewind(f);
1788 // fread may actually read less if it is a CR-LF-file in Windows
1789 size = fread(buf, 1, size, f);
1790 buf[size] = 0;
1791 fclose(f);
1792
1793 return buf;
1794}
1795
1796char *CScriptWebServer::ProcessPhpRequest(const char *filename, CSession *sess, long &size)
1797{
1798 FILE *f = fopen(filename, "r");
1799 if ( !f ) {
1800 return Get_404_Page(size);
1801 }
1802
1803 CWriteStrBuffer buffer;
1804 CPhpFilter(this, sess, filename, &buffer);
1805
1806 size = buffer.Length();
1807 char *buf = new char [size+1];
1808 buffer.CopyAll(buf);
1809
1810 fclose(f);
1811
1812 return buf;
1813}
1814
1815CSession *CScriptWebServer::CheckLoggedin(ThreadData &Data)
1816{
1817 time_t curr_time = time(0);
1818 CSession *session = 0;
1819 if ( Data.SessionID && m_sessions.count(Data.SessionID) ) {
1820 session = &m_sessions[Data.SessionID];
1821 // session times out in 2 hours
1822 if ( (curr_time - session->m_last_access) > 7200 ) {
1823 Print(_("Session expired - requesting login\n")wxGetTranslation(("Session expired - requesting login\n")));
1824 m_sessions.erase(Data.SessionID);
1825 session = 0;
1826 } else {
1827 if ( session->m_loggedin ) {
1828 Print(_("Session ok, logged in\n")wxGetTranslation(("Session ok, logged in\n")));
1829 } else {
1830 Print(_("Session ok, not logged in\n")wxGetTranslation(("Session ok, not logged in\n")));
1831 }
1832 session->m_last_access = curr_time;
1833 }
1834 } else {
1835 Print(_("No session opened - will request login\n")wxGetTranslation(("No session opened - will request login\n")
)
);
1836 }
1837 if ( !session ) {
1838 while ( !Data.SessionID || m_sessions.count(Data.SessionID) ) {
1839 Data.SessionID = rand();
1840 }
1841 session = &m_sessions[Data.SessionID];
1842 session->m_last_access = curr_time;
1843 session->m_loggedin = false;
1844 Print(_("Session created - requesting login\n")wxGetTranslation(("Session created - requesting login\n")));
1845 }
1846 Data.parsedURL.ConvertParams(session->m_get_vars);
1847 return session;
1848}
1849
1850
1851void CScriptWebServer::ProcessURL(ThreadData Data)
1852{
1853 long httpOutLen;
1854 char *httpOut = 0;
1855
1856 // Strip out any path-component to prevent information leakage.
1857 wxString filename = wxFileName(Data.parsedURL.File()).GetFullName();
1858
1859 Print(_("Processing request [original]: ")wxGetTranslation(("Processing request [original]: ")) + filename + wxT("\n")L"\n");
1860
1861 if ( filename.Length() == 0 ) {
1862 filename = m_index;
1863 }
1864
1865 CSession *session = CheckLoggedin(Data);
1866
1867 session->m_vars["login_error"] = "";
1868 if ( !session->m_loggedin ) {
1869 filename = wxT("login.php")L"login.php";
1870
1871 wxString PwStr(Data.parsedURL.Param(wxT("pass")L"pass"));
1872 if (webInterface->m_AdminPass.IsEmpty() && webInterface->m_GuestPass.IsEmpty()) {
1873 session->m_vars["login_error"] = "No password specified, login will not be allowed.";
1874 Print(_("No password specified, login will not be allowed.")wxGetTranslation(("No password specified, login will not be allowed."
))
);
1875 } else if ( PwStr.Length() ) {
1876 Print(_("Checking password\n")wxGetTranslation(("Checking password\n")));
1877 session->m_loggedin = false;
1878
1879 CMD4Hash PwHash;
1880 if (!PwHash.Decode(MD5Sum(PwStr).GetHash())) {
1881 Print(_("Password hash invalid\n")wxGetTranslation(("Password hash invalid\n")));
1882 session->m_vars["login_error"] = "Invalid password hash, please report on http://forum.amule.org";
1883 } else if ( PwHash == webInterface->m_AdminPass ) {
1884 session->m_loggedin = true;
1885 // m_vars is map<string, string> - so _() will not work here !
1886 session->m_vars["guest_login"] = "0";
1887 } else if ( PwHash == webInterface->m_GuestPass ) {
1888 session->m_loggedin = true;
1889 session->m_vars["guest_login"] = "1";
1890 } else {
1891 session->m_vars["login_error"] = "Password incorrect, please try again.";
1892 }
1893
1894 if ( session->m_loggedin ) {
1895 filename = m_index;
1896 Print(_("Password ok\n")wxGetTranslation(("Password ok\n")));
1897 } else {
1898 Print(_("Password bad\n")wxGetTranslation(("Password bad\n")));
1899 }
1900 } else {
1901 Print(_("You did not enter any password. Blank password is not allowed.\n")wxGetTranslation(("You did not enter any password. Blank password is not allowed.\n"
))
);
1902 }
1903 } else {
1904 //
1905 // if logged in, but requesting login page again,
1906 // means logout command
1907 //
1908 if ( filename == wxT("login.php")L"login.php" ) {
1909 Print(_("Logout requested\n")wxGetTranslation(("Logout requested\n")));
1910 session->m_loggedin = false;
1911 }
1912 }
1913
1914 Print(_("Processing request [redirected]: ")wxGetTranslation(("Processing request [redirected]: ")) + filename + wxT("\n")L"\n");
1915
1916 session->m_vars["auto_refresh"] = (const char *)unicode2char(
1917 wxString(CFormat(wxT("%d")L"%d") % webInterface->m_PageRefresh));
1918 session->m_vars["content_type"] = "text/html";
1919
1920 wxString req_file(wxFileName(m_wwwroot, filename).GetFullPath());
1921 if (req_file.EndsWith(wxT(".html")L".html")) {
1922 httpOut = ProcessHtmlRequest(unicode2char(req_file), httpOutLen);
1923 } else if (req_file.EndsWith(wxT(".php")L".php")) {
1924 httpOut = ProcessPhpRequest(unicode2char(req_file), session, httpOutLen);
1925 } else if (req_file.EndsWith(wxT(".css")L".css")) {
1926 session->m_vars["content_type"] = "text/css";
1927 httpOut = ProcessHtmlRequest(unicode2char(req_file), httpOutLen);
1928 } else if (req_file.EndsWith(wxT(".js")L".js")) {
1929 session->m_vars["content_type"] = "text/javascript";
1930 httpOut = ProcessHtmlRequest(unicode2char(req_file), httpOutLen);
1931 } else if ( req_file.EndsWith(wxT(".dtd")L".dtd")
1932 || req_file.EndsWith(wxT(".xsd")L".xsd")
1933 || req_file.EndsWith(wxT(".xsl")L".xsl")) {
1934 session->m_vars["content_type"] = "text/xml";
1935 httpOut = ProcessHtmlRequest(unicode2char(req_file), httpOutLen);
1936 } else if (req_file.EndsWith(wxT(".appcache")L".appcache")
1937 || req_file.EndsWith(wxT(".manifest")L".manifest")) {
1938 session->m_vars["content_type"] = "text/cache-manifest";
1939 httpOut = ProcessHtmlRequest(unicode2char(req_file), httpOutLen);
1940 } else if (req_file.EndsWith(wxT(".json")L".json")) {
1941 session->m_vars["content_type"] = "application/json";
1942 httpOut = ProcessHtmlRequest(unicode2char(req_file), httpOutLen);
1943 } else {
1944 httpOut = GetErrorPage("aMuleweb doesn't handle the requested file type ", httpOutLen);
1945 }
1946
1947 bool isUseGzip = webInterface->m_UseGzip;
1948
1949 if (isUseGzip) {
1950 bool bOk = false;
1951 uLongf destLen = httpOutLen + 1024;
1952 char *gzipOut = new char[destLen];
1953 if( GzipCompress((Bytef*)gzipOut, &destLen,
1954 (const Bytef*)httpOut, httpOutLen, Z_DEFAULT_COMPRESSION(-1)) == Z_OK0) {
1955 bOk = true;
1956 }
1957 if ( bOk ) {
1958 delete [] httpOut;
1959 httpOut = gzipOut;
1960 httpOutLen = destLen;
1961 } else {
1962 isUseGzip = false;
1963 delete[] gzipOut;
1964 }
1965 }
1966
1967 if ( httpOut ) {
1968 Data.pSocket->SendHttpHeaders(session->m_vars["content_type"].c_str(), isUseGzip, httpOutLen, Data.SessionID);
1969 Data.pSocket->SendData(httpOut, httpOutLen);
1970 delete [] httpOut;
1971 }
1972}
1973
1974CNoTemplateWebServer::CNoTemplateWebServer(CamulewebApp *webApp) : CScriptWebServer(webApp, wxEmptyString)
1975{
1976}
1977
1978CNoTemplateWebServer::~CNoTemplateWebServer()
1979{
1980}
1981
1982void CNoTemplateWebServer::ProcessURL(ThreadData Data)
1983{
1984 /*
1985 * Since template has not been found, I suspect that installation is broken. Falling back
1986 * into hardcoded page as last resort.
1987 */
1988 const char *httpOut = ""
1989 "<html>"
1990 "<head>"
1991 "<title>aMuleWeb error page</title>"
1992 "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">"
1993 "</head>"
1994 "<body>"
1995 "<p>You are seeing this page instead of aMuleWeb login page because a valid template has not been found.</p>"
1996 "<p>This probably means that there's a problem with your aMule installation </p>"
1997 "<ul>"
1998 "<li>Before installing new versions, please ensure that you uninstalled older versions of aMule.</li>"
1999 "<li>If you are installing by compiling from source, check configuration and run &quot;make&quot; and &quot;make install&quot; again </li>"
2000 "<li>If you are installing by using a precompiled package, you may need to contact the package maintainer </li>"
2001 "</ul>"
2002 "<p>For more information please visit</p>"
2003 "<p><a href=\"http://www.amule.org\">aMule main site</a> or <a href=\"http://forum.amule.org\">aMule forums</a></p>"
2004 "</body>"
2005 "</html>";
2006
2007 long httpOutLen = strlen(httpOut);
2008
2009 Data.pSocket->SendHttpHeaders("text/html", false, httpOutLen, 0);
2010 Data.pSocket->SendData(httpOut, httpOutLen);
2011}
2012
2013// File_checked_for_headers