void VerbCapturePlanet::onExecute() { NounPlanet * pPlanet = WidgetCast<NounPlanet>( target() ); if ( validate( pPlanet ) ) { // notify the planet's current owners the planet has been captured.. CharString sMessage; if ( pPlanet->context()->isTeamValid( m_nFleetId ) ) { sMessage.format( "<color;ffffff>NEWS: %s has been captured by the %s.", pPlanet->name(), pPlanet->context()->team( m_nFleetId ).name.cstr() ); } else { sMessage.format( "<color;ffffff>NEWS: %s has been captured by rebels.", pPlanet->name() ); } pPlanet->clientChat( sMessage ); // planet captured set the owner pPlanet->setTeamId( m_nFleetId ); // reset lock rank pPlanet->setLockRank( 0 ); // reduce the moral of the planet if ( pPlanet->population() > 0 && pPlanet->factionId() != 0 ) pPlanet->setMoral( Clamp( pPlanet->moral() - 0.25f, 0.2f, 1.0f ) ); // stop reloading any friendly ships if ( pPlanet->isServer() ) { for(int i=0;i<pPlanet->childCount();i++) { StructureDefense * pDefense = WidgetCast<StructureDefense>( pPlanet->child(i) ); if ( pDefense == NULL ) continue; pDefense->setTeamId( 0 ); // HACK: Somehow defense bases are getting their teamId set.. for(int j=0;j<pDefense->childCount();j++) { GadgetReload * pReload = WidgetCast<GadgetReload>( pDefense->child(j) ); if ( pReload != NULL && pReload->reloading() != NULL && !pPlanet->isFriend( pReload->reloading() ) ) pDefense->useGadget( NULL, pReload ); } } } // send message to the new owners of this planet as well... pPlanet->clientChat( sMessage ); } }
void TextMission::onUpdate( float t ) { WindowText::onUpdate( t ); if ( visible() ) { if ( activeTime() > UPDATE_MISSION_TEXT ) { GameDocument * pDoc = WidgetCast<GameDocument>( document() ); ASSERT( pDoc ); NounShip * pShip = pDoc->ship(); if (! pShip ) return; static char * ORDER_DESC[] = { "NO ORDER %s", // NOORDER "Engage %s and destroy.", // ATTACK "Defend %s from attack by enemy ships.", // DEFEND "Capture %s.", // CAPTURE "Proceed to %s.", // MOVE "Reload and repair %s.", // RELOAD "Attach beacon to %s.", // BEACON "Hold current position %s.", // HOLD "Trade %s", // TRADE "Recon enemy positions at %s.", // RECON "Build structures on %s.", // BUILD "Fallback and repair at %s." // FALLBACK }; CharString sText; sText.format( ORDER_DESC[ pShip->order() ], pShip->orderTarget() ? pShip->orderTarget()->name() : "" ); setText( sText ); setActiveTime( 0 ); } } }
int main( int argc, char ** argv ) { CharString iniFile = "./ProcessServer.ini"; if ( argc > 1 ) iniFile = argv[1]; Settings settings( "ProcessServer", iniFile ); // initialize the logging first thing before we do anything else.. std::string logFile( settings.get( "logFile", "ProcessServer.log" ) ); std::string logExclude( settings.get( "logExclude", "" ) ); unsigned int nMinLogLevel = settings.get( "logLevel", LL_STATUS ); new FileReactor( logFile, nMinLogLevel, logExclude ); bool bRemoteUpdate = settings.get( "remoteUpdate", 1 ) != 0; bool bLocalUpdate = settings.get( "localUpdate", (dword)0 ) != 0; CharString sPath( FileDisk::currentDirectory() ); if (! sPath.endsWith( PATH_SEPERATOR ) ) sPath += PATH_SEPERATOR; #if !defined(_DEBUG) // update the files if ( settings.get( "doUpdate", 1 ) != 0 ) { settings.put( "doUpdate", (dword)0 ); if ( bLocalUpdate ) { CharString updatePath = settings.get( "localUpdatePath", "" ); if ( updatePath.length() > 0 ) { FileDisk::normalizePath( updatePath.buffer() ); if (! updatePath.endsWith( PATH_SEPERATOR ) ) updatePath += PATH_SEPERATOR; // copy the files from a directory if ( localUpdate( sPath, updatePath ) ) return -3; // let the service/script update our files.. } } } #endif // do the update next time! settings.put( "doUpdate", 1 ); ProcessServer::Context context; context.logFile = logFile.c_str(); context.name = settings.get( "name", "ProcessServer" ); context.config = iniFile; context.gameId = settings.get( "gameId", 1 ); context.processGroup = settings.get( "processGroup", 1 ); context.networkGroup = settings.get( "networkGroup", 1 ); context.metaAddress = settings.get( "metaAddress", "meta-server.palestar.com" ); context.metaPort = settings.get( "metaPort", 9000 ); context.uid = settings.get( "uid", "DSS" ); context.pw = settings.get( "pw", "darkspace" ); context.address = settings.get( "address", "" ); context.port = settings.get( "port", 8000 ); context.maxClients = settings.get( "maxClients", 1000 ); context.processFile = iniFile; context.syncClock = settings.get ("syncClock", (dword)0 ) != 0; // start the server MyProcessServer theServer; if (! theServer.start( context ) ) return -1; // signal that we are running Event serverRunning( "ProcessServerRun" ); serverRunning.signal(); dword nNextUpdateCheck = Time::seconds() + settings.get("updateTime",300); dword nLastCRC = 0; // run the server forever, unless it crashes Event serverStop( "ProcessServerStop" ); while( theServer.running() && !theServer.shutdownCompleted() ) { if (! serverStop.wait( 10 ) ) { LOG_STATUS( "ProcessServer", "Recevied shutdown signal." ); theServer.shutdown(); serverStop.clear(); } theServer.update(); theServer.updatePerformanceMonitor(); #if !defined(_DEBUG) if ( bRemoteUpdate && nNextUpdateCheck < Time::seconds() ) { // check for new code update MirrorClient mirrorClient; if ( mirrorClient.open( settings.get( "mirrorAddress", "mirror-server.palestar.com" ), settings.get( "mirrorPort", 9200 ), sPath, NULL, true ) ) { // attempt to login, ingore if failed mirrorClient.login( settings.get( "uid", "" ), settings.get( "pw", "" ) ); // get the CRC only, only do a sync if remote files have been changed... dword nCRC = mirrorClient.getCRC(); if ( nCRC != nLastCRC ) { nLastCRC = nCRC; dword nJobID = mirrorClient.syncronize(); if ( nJobID != 0 && mirrorClient.waitJob( nJobID, 86400 * 1000 ) ) { int nWarningTime = settings.get( "warningTime", 300 ); LOG_STATUS( "ProcessServer", "Files updated -- Restarting the server in %d seconds.", nWarningTime ); CharString sWarningMessage = settings.get( "warningMessage", CharString().format("/notice /%s Updating in $T...", context.name.cstr() ) ); while( nWarningTime > 0 ) { CharString sTimeLeft; sTimeLeft.format("%d %s", nWarningTime > 60 ? nWarningTime / 60 : nWarningTime, nWarningTime > 60 ? "minute(s)" : "second(s)"); // replace the "$T" token with the time remaining... CharString sChat = sWarningMessage; sChat.replace( "$T", sTimeLeft ); theServer.sendChat( sChat ); int nSleepTime = 0; if ( nWarningTime > (60 * 10) ) nSleepTime = 60 * 5; // sleep for 5 minutes else nSleepTime = 60; // sleep for 1 minute if ( nSleepTime > nWarningTime ) nSleepTime = nWarningTime; nWarningTime -= nSleepTime; dword nEndSleep = Time::seconds() + nSleepTime; while( Time::seconds() < nEndSleep ) { if (! serverStop.wait( 10 ) ) { LOG_STATUS( "ProcessServer", "Received stop signal, stopping now." ); nSleepTime = nWarningTime = 0; // stop now... no warning break; } theServer.update(); theServer.updatePerformanceMonitor(); } } // start the shutdown, server will exit once the last process has stopped.. theServer.shutdown(); } } mirrorClient.close(); } else { LOG_ERROR( "ProcessServer", "Failed to connect to MirrorServer!" ); } nNextUpdateCheck = Time::seconds() + settings.get("updateTime",300); } #endif } theServer.stop(); return 0; }
static bool localUpdate( const char * pDest, const char * pSrc ) { bool bRestart = false; ASSERT( pDest[ strlen(pDest) - 1 ] == PATH_SEPERATORC ); ASSERT( pSrc[ strlen(pSrc) - 1 ] == PATH_SEPERATORC ); Path srcPath( pSrc ); CharString sMask( srcPath.directory() + "*" ); FindFile ff( sMask ); // make sure destination directory exists FileDisk::createDirectory( pDest ); // move files for(int i=0;i<ff.fileCount();i++) { CharString dstFile; dstFile.format( "%s%s", pDest, ff.file(i) ); CharString srcFile; srcFile.format( "%s%s", pSrc, ff.file(i) ); bool copyFile = false; bool copyUpdate = false; if ( FileDisk::fileExists( dstFile ) ) { // make sure date of src file is newer if ( FileDisk::fileDate( srcFile ) > FileDisk::fileDate( dstFile ) ) { copyFile = true; // attempt to delete the old file, if it fails then use MirrorUpdate if (! FileDisk::deleteFile( dstFile ) ) copyUpdate = true; } } else copyFile = true; bRestart |= copyFile; if ( copyFile && copyUpdate ) FileDisk::copyFile( srcFile, dstFile + ".upd" ); else if ( copyFile ) FileDisk::copyFile( srcFile, dstFile ); } // recurse into subdirectories for(int i=0;i<ff.directoryCount();i++) { if ( ff.directory(i)[0] == '.' ) continue; CharString newDst; newDst.format( "%s%s" PATH_SEPERATOR, pDest, ff.directory( i ) ); CharString newSrc; newSrc.format( "%s%s" PATH_SEPERATOR, pSrc, ff.directory( i ) ); bRestart |= localUpdate( newDst, newSrc ); } return bRestart; }
void CChatView::OnTimer(UINT nIDEvent) { CChatFrame * pFrame = (CChatFrame *)GetParentFrame(); //CMainFrame* pMainFrame = (CMainFrame *)AfxGetMainWnd(); // //// SpamCheck heartbeat //CChatEdit* pChatEdit = pMainFrame->getChatEdit(); //if( pChatEdit->m_SpamBlock.heartbeat() ) // reenable chatbar if spampenality-time expired // if( ! pChatEdit->acceptsInput() ) // pChatEdit->enableInput(); // don't update/scroll if the user is currently marking text BOOL bAllowUpdate = true; if( m_UpdateBlockedTime > 0 ) { m_UpdateBlockedTime--; bAllowUpdate = false; } if ( CGCQLApp::sm_bBtnDown ) { RECT rChatWindow; GetWindowRect( &rChatWindow ); if ( ( rChatWindow.bottom >= CGCQLApp::sm_ptMouseDown.y ) && ( rChatWindow.top <= CGCQLApp::sm_ptMouseDown.y ) && ( rChatWindow.left <= CGCQLApp::sm_ptMouseDown.x ) && ( rChatWindow.right >= CGCQLApp::sm_ptMouseDown.x ) ) { bAllowUpdate = false; m_UpdateBlockedTime = 5; } } if ( bAllowUpdate ) { MetaClient & client = CGCQLApp::sm_MetaClient; AutoLock lock( client.autoLock() ); if ( m_TopChatMessage < client.chatCount() ) { for(;m_TopChatMessage<client.chatCount();m_TopChatMessage++) { const MetaClient::Chat & chat = client.chat( m_TopChatMessage ); if( chat.recpId == client.profile().userId ) pFrame->onPrivateMessage( chat.authorId, chat.author, chat.text ); else if ( CGCQLApp::sm_bChatSound ) PlaySound( MAKEINTRESOURCE(IDW_CHAT01), AfxGetResourceHandle(), SND_RESOURCE|SND_ASYNC ); if ( chat.text.length() > 0 && chat.text[ 0 ] == '/' ) // emotes and server messages { CharString sText; // mark emotes to prevent message faking // /me echos are received with authorId 0 but should be marked as player emote too if( ( chat.authorId == 0 && chat.text.find( CharString("/") + client.profile().name ) >= 0 ) || ( chat.authorId != 0 && chat.text.find( CharString("/") + chat.author ) >= 0 ) ) sText.format( "<b><font color=ffa000>*</font></b> %s", FilterText::enhance( chat.text.buffer() + 1 ) ); else sText.format( "<b>*</b> %s", FilterText::enhance( chat.text.buffer() + 1 ) ); // Write to ChatLog CChatLog & cChatLog = CGCQLApp::s_ChatLog; if ( cChatLog.isLogging() ) cChatLog.write( CString( sText ) ); // don't include the time stamp, just add the text directly m_ChatBuffer += MESSAGE_HEAD; // add timestamp if message is older than 5 minutes //if ( chat.time < (Time::seconds() - 300 ) ) // m_ChatBuffer += CTime( chat.time ).FormatGmt( "[%H:%M:%S %d/%m/%y] " ); m_ChatBuffer += CString( sText ); m_ChatBuffer += MESSAGE_TAIL; m_ChatBuffer += "\n"; } else // normal chatlines { // prepend the time and author CharString sText; if( chat.authorId != client.profile().userId ) // make chatlines from other users clickable { sText.format( "%s <a class=\"normal\" href=\"%u\">%s</a>: \"<b>%s</b>\"", Time::format( chat.time, "%H:%M:%S" ), chat.authorId, chat.author, FilterText::enhance( chat.text ) ); } else { sText.format( "%s %s: \"<b>%s</b>\"", Time::format( chat.time, "%H:%M:%S" ), chat.author, FilterText::enhance( chat.text ) ); } // Write to ChatLog CChatLog & cChatLog = CGCQLApp::s_ChatLog; if ( cChatLog.isLogging() ) cChatLog.write( CString( sText ) ); // add new message to buffer m_ChatBuffer += MESSAGE_HEAD; m_ChatBuffer += CString( sText ); m_ChatBuffer += MESSAGE_TAIL; m_ChatBuffer += "\n"; } } // trim the buffer int length = m_ChatBuffer.GetLength(); while( length > CGCQLApp::sm_ChatBufferSize ) { m_ChatBuffer = m_ChatBuffer.Right( m_ChatBuffer.GetLength() - (m_ChatBuffer.Find( '\n' ) + 1) ); length = m_ChatBuffer.GetLength(); } CString sBodyHeader; sBodyHeader.Format( BODY_HEAD, CGCQLApp::sm_TextSize ); sBodyHeader += STYLE_TAG; // update the body text m_Body = sBodyHeader + m_ChatBuffer + BODY_TAIL; PutBodyContent( m_Body ); // scroll to the bottom of the window if ( m_pParentWindow != NULL ) m_pParentWindow->scrollBy( 0, 1000 ); } } //CHtmlView::OnTimer(nIDEvent); }
void ProcessServer::updateDemon() { dword lastRegister = 0; dword lastTimeSync = 0; dword pingTime = 0; while ( running() && !m_bShutdownCompleted ) { Thread::sleep( 1000 ); if (! m_MetaClient.loggedIn() ) { LOG_STATUS( "ProcessServer", "Establishing connection to the metaserver" ); // attempt to connect if ( m_MetaClient.open( m_Context.metaAddress, m_Context.metaPort ) > 0 ) { if ( m_MetaClient.login( m_Context.uid, m_Context.pw ) < 0 ) { LOG_STATUS( "ProcessServer", "Failed to login to the metaserver" ); m_MetaClient.close(); // failed to login } else { LOG_STATUS( "ProcessServer", "Connected to the metaserver" ); // select the correct game m_MetaClient.selectGame( m_Context.gameId ); } } } m_MetaClient.update(); if ( m_MetaClient.loggedIn() ) { if ( lastRegister < (Time::seconds() - REGISTER_TIME) ) { AutoLock lock( &m_Lock ); MetaClient::Server server; server.gameId = m_Context.gameId; server.type = MetaClient::PROCESS_SERVER; server.flags = 0; server.name = m_Context.name; server.shortDescription.format( "CPU: %d%%, MEM: %d%%", cpuUsage(), memoryUsage() ); server.description = server.shortDescription + "\n\n"; for(int i=0;i<m_ProcessList.size();i++) { Process & proc = m_ProcessList[ i ]; if ( (proc.flags & ProcessClient::PF_RUNNING) == 0 ) continue; server.description += CharString().format( "%s\n", proc.name.cstr() ); } server.address = m_Context.address; server.port = m_Context.port; server.maxClients = m_Context.maxClients; server.clients = clientCount(); server.data = CharString().format("processGroup=%u;networkGroup=%u;processCount=%u;cpuUsage=%d;memoryUsage=%d", m_Context.processGroup, m_Context.networkGroup, m_ProcessList.size(), cpuUsage(), memoryUsage() ); lock.release(); if ( m_MetaClient.registerServer( server ) < 0 ) lastRegister = (Time::seconds() - REGISTER_TIME) + 30; // failed, try again in 30 seconds else lastRegister = Time::seconds(); } if ( m_Context.syncClock && lastTimeSync < (Time::seconds() - SYNC_CLOCKS_TIME) ) { // get the current time from the metaserver dword currentTime = m_MetaClient.getTime(); if ( currentTime > 0 ) { LOG_STATUS( "ProcessServer", "Syncronizing system time to %s", Time::format( currentTime, "%c" ).cstr() ); if (! Time::setTime( currentTime ) ) LOG_STATUS( "ProcessServer", "Failed to set the system time!" ); lastTimeSync = Time::seconds(); } else { LOG_STATUS( "ProcessServer", "Failed to syncronize system time from MetaServer!" ); lastTimeSync = (Time::seconds() - SYNC_CLOCKS_TIME) + 300; // try again in another 5 min } } } AutoLock lock( &m_Lock ); bool shutdownComplete = true; // have all child processes stopped // check for log updates for(int i=0;i<m_ActiveLog.size();i++) { dword logId = m_ActiveLog[ i ]; FileDisk & file = m_LogFile[ logId ]; try { if ( file.position() > file.size() ) file.setPosition( 0 ); // file has been rotated... reset read position dword read = file.size() - file.position(); if ( read > 0 ) { if ( read > MAX_LOG_SIZE ) { file.setPosition( file.size() - MAX_LOG_SIZE ); read = MAX_LOG_SIZE; } char * pLines = new char[ read + 1 ]; pLines[ read ] = 0; file.read( pLines, read ); send( m_LogClient[ logId ], ProcessClient::CLIENT_RECV_LOG_UPDATE ) << logId << CharString(pLines); delete [] pLines; } } catch( FileDisk::FileError ) { LOG_STATUS( "ProcessServer", CharString().format("Log Read Error, logFile = %s, logId = %u", file.fileName(), logId) ); // close the previously open file file.close(); // attempt to reopen the file file.open( file.fileName() ); } } // check process list for(int i=0;i<m_ProcessList.size();i++) { Process & proc = m_ProcessList[ i ]; if ( m_ProcessInfo.find( proc.processId ).valid() ) { ProcessInfo & info = m_ProcessInfo[ proc.processId ]; proc.flags |= ProcessClient::PF_RUNNING; if ( (proc.flags & ProcessClient::PF_DISABLED) == 0 ) { // make sure the process is still running if (! ::Process::active( info.m_pHandle ) ) { proc.flags &= ~ProcessClient::PF_RUNNING; if ( ! m_Shutdown ) { if ( info.m_nRestartTime != 0 && Time::seconds() < info.m_nRestartTime ) continue; // not time to restart yet, continue onto the next process.. // process has exited, increment the number of restarts, then calculate the next restart // time increasing the wait time each time the process exits info.m_nRestarts += 1; info.m_nRestartTime = Time::seconds() + (60 * (info.m_nRestarts * info.m_nRestarts) ); int exitCode = ::Process::exitCode( info.m_pHandle ); ::Process::close( info.m_pHandle ); CharString message; message.format( "Process %u exit, name = %s, exec = %s, arg = %s, exitCode = %d, restarts = %u", proc.processId, proc.name.cstr(), proc.executable.cstr(), proc.arguments.cstr(), exitCode, info.m_nRestarts ); LOG_STATUS( "ProcessServer", message ); // send report if exit code is negative if ( exitCode < 0 ) m_MetaClient.sendChat( 0, CharString().format("/report %s", message.cstr()) ); // restart the process.. Path exePath( proc.executable ); void * pStart = ::Process::start( CharString().format("%s %s", exePath.file().cstr(), proc.arguments.cstr()), exePath.directory() ); if ( pStart == NULL ) { LOG_STATUS( "ProcessServer", "Process %u failed to restart", proc.processId ); m_ProcessInfo.remove( proc.processId ); proc.flags |= ProcessClient::PF_DISABLED; } else { LOG_STATUS( "ProcessServer", "Process %u restarted", proc.processId ); info.m_pHandle = pStart; } } else { int exitCode = ::Process::exitCode( info.m_pHandle ); LOG_STATUS( "ProcessServer", "Process Stopped, name = %s, exitCode = %d", proc.name.cstr(), exitCode ); ::Process::close( info.m_pHandle ); m_ProcessInfo.remove( proc.processId ); } } else if ( m_Shutdown ) { shutdownComplete = false; stopProcess( proc.processId ); } else if ( info.m_nRestartTime != 0 && Time::seconds() > info.m_nRestartTime ) { // process has been running long enough to clear the restart time. info.m_nRestartTime = 0; info.m_nRestarts = 0; } } else { if (! ::Process::active( info.m_pHandle ) ) { LOG_STATUS( "ProcessServer", "Process Stopped, name = %s", proc.name.cstr() ); ::Process::close( info.m_pHandle ); m_ProcessInfo.remove( proc.processId ); } else stopProcess( proc.processId ); } } else { proc.flags &= ~ProcessClient::PF_RUNNING; if ( (proc.flags & ProcessClient::PF_DISABLED) == 0 && !m_Shutdown ) { LOG_STATUS( "ProcessServer", "Starting Process %u, name = %s, exec = %s, arg = %s", proc.processId, proc.name.cstr(), proc.executable.cstr(), proc.arguments.cstr() ); Path exePath( proc.executable ); void * pStart = ::Process::start( CharString().format("%s %s", exePath.file().cstr(), proc.arguments.cstr()), exePath.directory() ); if ( pStart == NULL ) { proc.flags |= ProcessClient::PF_DISABLED; LOG_STATUS( "ProcessServer", "Process %u Failed to Start, name = %s, exec = %s", proc.processId, proc.name.cstr(), proc.executable.cstr() ); } else m_ProcessInfo[ proc.processId ].m_pHandle = pStart; } } } pingTime++; if ( pingTime > 15 ) { // ping all clients for(int i=0;i<clientCount();i++) send( client(i), ProcessClient::PING ); pingTime = 0; } // check for shutdown if ( m_Shutdown && shutdownComplete ) { m_bShutdownCompleted = true; if ( m_RebootOnShutdown ) rebootMachine(); } lock.release(); } }
void HttpRequestHandler::processRequest() { HttpRequest httpRequest(m_dataInput); httpRequest.readHeader(); StringStorage request; request.fromAnsiString(httpRequest.getRequest()); if (!httpRequest.parseHeader()) { Log::warning(_T("invalid http request from %s"), m_peerHost.getString()); return ; } request.replaceChar(_T('\n'), _T(' ')); request.replaceChar(_T('\t'), _T(' ')); Log::message(_T("\"%s\" from %s"), request.getString(), m_peerHost.getString()); HttpReply reply(m_dataOutput); bool pageFound = false; if (strcmp(httpRequest.getFilename(), "/") == 0) { CharString paramsString("\n"); bool isAppletArgsValid = true; bool paramsInUrlIsEnabled = Configurator::getInstance()->getServerConfig()->isAppletParamInUrlEnabled(); if (httpRequest.hasArguments() && paramsInUrlIsEnabled) { ArgList *args = httpRequest.getArguments(); for (size_t i = 0; i < args->getCount(); i++) { const char *key = args->getKey(i); AppletParameter parameter(key, args->getValue(key)); if (!parameter.isValid()) { isAppletArgsValid = false; break; } paramsString.format("%s%s", paramsString.getString(), parameter.getFormattedString()); } } reply.send200(); if (!isAppletArgsValid) { m_dataOutput->writeFully(HTTP_MSG_BADPARAMS, strlen(HTTP_MSG_BADPARAMS)); } else { CharString page; StringStorage computerName(_T("TightVNC Server")); Environment::getComputerName(&computerName); size_t computerNameANSILength = computerName.getLength() + 1; char *computerNameANSI = new char[computerNameANSILength]; computerName.toAnsiString(computerNameANSI, computerNameANSILength); page.format(HTTP_INDEX_PAGE_FORMAT, computerNameANSI, Configurator::getInstance()->getServerConfig()->getRfbPort(), paramsString.getString()); delete[] computerNameANSI; m_dataOutput->writeFully(page.getString(), page.getLength()); } pageFound = true; } else if ((strcmp(httpRequest.getFilename(), "/VncViewer.jar") == 0)) { reply.send200(); m_dataOutput->writeFully(VNC_VIEWER_JAR_BODY, sizeof(VNC_VIEWER_JAR_BODY)); pageFound = true; } if (!pageFound) { reply.send404(); } }