]> git.mxchange.org Git - simgear.git/blobdiff - simgear/scene/tsync/terrasync.cxx
Make tsync part of libSimGearCore when building shared libraries
[simgear.git] / simgear / scene / tsync / terrasync.cxx
index 939ff6fb6640c27ad26150406aa59ce2fa4c5c11..e4ae8ff8ad0a7ce35f7ee6a395e9f72e12a67abb 100644 (file)
@@ -45,6 +45,7 @@
 
 #include <stdlib.h>             // atoi() atof() abs() system()
 #include <signal.h>             // signal()
+#include <string.h>
 
 #include <iostream>
 #include <fstream>
 #include "terrasync.hxx"
 #include <simgear/bucket/newbucket.hxx>
 #include <simgear/misc/sg_path.hxx>
+#include <simgear/misc/strutils.hxx>
 #include <simgear/threads/SGQueue.hxx>
-#include <simgear/scene/tgdb/TileCache.hxx>
 #include <simgear/misc/sg_dir.hxx>
-#include <OpenThreads/Thread>
 
 #ifdef HAVE_SVN_CLIENT_H
 #  ifdef HAVE_LIBSVN_CLIENT_1
 #endif
 
 using namespace simgear;
+using namespace std;
 
 const char* rsync_cmd = 
         "rsync --verbose --archive --delete --perms --owner --group";
 
-const char* svn_cmd =
-        "svn checkout -q";
+const char* svn_options =
+        "checkout -q";
+
+namespace UpdateInterval
+{
+    // interval in seconds to allow an update to repeat after a successful update (=daily)
+    static const double SuccessfulAttempt = 24*60*60;
+    // interval in seconds to allow another update after a failed attempt (10 minutes)
+    static const double FailedAttempt     = 10*60;
+};
 
 typedef map<string,time_t> CompletedTiles;
 
+///////////////////////////////////////////////////////////////////////////////
+// helper functions ///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+string stripPath(string path)
+{
+    // svn doesn't like trailing white-spaces or path separators - strip them!
+    path = simgear::strutils::strip(path);
+    int slen = path.length();
+    while ((slen>0)&&
+            ((path[slen-1]=='/')||(path[slen-1]=='\\')))
+    {
+        slen--;
+    }
+    return path.substr(0,slen);
+}
+
+bool hasWhitespace(string path)
+{
+    return path.find(' ')!=string::npos;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // WaitingTile ////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
@@ -109,7 +139,7 @@ public:
 ///////////////////////////////////////////////////////////////////////////////
 // SGTerraSync::SvnThread /////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
-class SGTerraSync::SvnThread : public OpenThreads::Thread
+class SGTerraSync::SvnThread : public SGThread
 {
 public:
    SvnThread();
@@ -124,11 +154,13 @@ public:
    bool hasNewTiles() { return !_freshTiles.empty();}
    WaitingTile getNewTile() { return _freshTiles.pop_front();}
 
-   void   setSvnServer(string server) { _svn_server = server;}
-   void   setRsyncServer(string server) { _rsync_server = server;}
-   void   setLocalDir(string dir) { _local_dir = dir;}
-   string getLocalDir() { return _local_dir;}
-   void   setUseSvn(bool use_svn) { _use_svn = use_svn;}
+   void   setSvnServer(string server)       { _svn_server   = stripPath(server);}
+   void   setExtSvnUtility(string svn_util) { _svn_command  = simgear::strutils::strip(svn_util);}
+   void   setRsyncServer(string server)     { _rsync_server = simgear::strutils::strip(server);}
+   void   setLocalDir(string dir)           { _local_dir    = stripPath(dir);}
+   string getLocalDir()                     { return _local_dir;}
+   void   setUseSvn(bool use_svn)           { _use_svn = use_svn;}
+   void   setAllowedErrorCount(int errors)  {_allowed_errors = errors;}
 
 #ifdef HAVE_SVN_CLIENT_H
    void setUseBuiltin(bool built_in) { _use_built_in = built_in;}
@@ -142,10 +174,11 @@ public:
    volatile int  _updated_tile_count;
    volatile int  _success_count;
    volatile int  _consecutive_errors;
+   volatile int  _allowed_errors;
 
 private:
    virtual void run();
-   bool syncTree(const char* dir);
+   bool syncTree(const char* dir, bool& isNewDirectory);
    bool syncTreeExternal(const char* dir);
 
 #ifdef HAVE_SVN_CLIENT_H
@@ -168,6 +201,7 @@ private:
    SGBlockingDeque <WaitingTile> _freshTiles;
    bool _use_svn;
    string _svn_server;
+   string _svn_command;
    string _rsync_server;
    string _local_dir;
 };
@@ -188,6 +222,7 @@ SGTerraSync::SvnThread::SvnThread() :
     _updated_tile_count(0),
     _success_count(0),
     _consecutive_errors(0),
+    _allowed_errors(6),
 #ifdef HAVE_SVN_CLIENT_H
     _use_built_in(true),
 #endif
@@ -229,13 +264,23 @@ bool SGTerraSync::SvnThread::start()
     if (_local_dir=="")
     {
         SG_LOG(SG_TERRAIN,SG_ALERT,
-               "Cannot start scenery download. No local cache directory defined.");
+               "Cannot start scenery download. Local cache directory is undefined.");
         _fail_count++;
         _stalled = true;
         return false;
     }
-    
+
     SGPath path(_local_dir);
+    if (!path.exists())
+    {
+        SG_LOG(SG_TERRAIN,SG_ALERT,
+               "Cannot start scenery download. Directory '" << _local_dir <<
+               "' does not exist. Set correct directory path or create directory folder.");
+        _fail_count++;
+        _stalled = true;
+        return false;
+    }
+
     path.append("version");
     if (path.exists())
     {
@@ -246,6 +291,7 @@ bool SGTerraSync::SvnThread::start()
         _stalled = true;
         return false;
     }
+
 #ifdef HAVE_SVN_CLIENT_H
     _use_svn |= _use_built_in;
 #endif
@@ -258,7 +304,6 @@ bool SGTerraSync::SvnThread::start()
         _stalled = true;
         return false;
     }
-
     if ((!_use_svn)&&(_rsync_server==""))
     {
         SG_LOG(SG_TERRAIN,SG_ALERT,
@@ -276,28 +321,51 @@ bool SGTerraSync::SvnThread::start()
     _stalled = false;
     _running = true;
 
+    string status;
+#ifdef HAVE_SVN_CLIENT_H
+    if (_use_svn && _use_built_in)
+        status = "Using built-in SVN support. ";
+    else
+#endif
+    if (_use_svn)
+    {
+        status = "Using external SVN utility '";
+        status += _svn_command;
+        status += "'. ";
+    }
+    else
+    {
+        status = "Using RSYNC. ";
+    }
+
     // not really an alert - but we want to (always) see this message, so user is
     // aware we're downloading scenery (and using bandwidth).
     SG_LOG(SG_TERRAIN,SG_ALERT,
-           "Starting automatic scenery download/synchronization. Directory: '" << _local_dir << "'");
+           "Starting automatic scenery download/synchronization. "
+           << status
+           << "Directory: '" << _local_dir << "'.");
 
-    OpenThreads::Thread::start();
+    SGThread::start();
     return true;
 }
 
 // sync one directory tree
-bool SGTerraSync::SvnThread::syncTree(const char* dir)
+bool SGTerraSync::SvnThread::syncTree(const char* dir, bool& isNewDirectory)
 {
     int rc;
     SGPath path( _local_dir );
 
     path.append( dir );
-    rc = path.create_dir( 0755 );
-    if (rc)
+    isNewDirectory = !path.exists();
+    if (isNewDirectory)
     {
-        SG_LOG(SG_TERRAIN,SG_ALERT,
-               "Cannot create directory '" << dir << "', return code = " << rc );
-        return false;
+        rc = path.create_dir( 0755 );
+        if (rc)
+        {
+            SG_LOG(SG_TERRAIN,SG_ALERT,
+                   "Cannot create directory '" << dir << "', return code = " << rc );
+            return false;
+        }
     }
 
 #ifdef HAVE_SVN_CLIENT_H
@@ -322,21 +390,19 @@ bool SGTerraSync::SvnThread::syncTreeInternal(const char* dir)
         return false;
     }
 
-    char command[512];
-    char dest_base_dir[512];
-    snprintf( command, 512,
-        "%s/%s", _svn_server.c_str(), dir);
-    snprintf( dest_base_dir, 512,
-        "%s/%s", _local_dir.c_str(), dir);
-    svn_error_t *err = NULL;
+    ostringstream command;
+    command << _svn_server << "/" << dir;
+
+    ostringstream dest_base_dir;
+    dest_base_dir << _local_dir << "/" << dir;
 
     apr_pool_t *subpool = svn_pool_create(_svn_pool);
 
-    err=0;
+    svn_error_t *err = NULL;
 #if (SVN_VER_MINOR >= 5)
     err = svn_client_checkout3(NULL,
-            command,
-            dest_base_dir,
+            command.str().c_str(),
+            dest_base_dir.str().c_str(),
             _svn_rev_peg,
             _svn_rev,
             svn_depth_infinity,
@@ -347,8 +413,8 @@ bool SGTerraSync::SvnThread::syncTreeInternal(const char* dir)
 #else
     // version 1.4 API
     err = svn_client_checkout2(NULL,
-            command,
-            dest_base_dir,
+            command.str().c_str(),
+            dest_base_dir.str().c_str(),
             _svn_rev_peg,
             _svn_rev,
             1, // recurse=true - same as svn_depth_infinity for checkout3 above
@@ -361,19 +427,26 @@ bool SGTerraSync::SvnThread::syncTreeInternal(const char* dir)
     if (err)
     {
         // Report errors from the checkout attempt
-        SG_LOG(SG_TERRAIN,SG_ALERT,
-                "Failed to synchronize directory '" << dir << "', " <<
-                err->message);
-        svn_error_clear(err);
-        // try to clean up
-        err = svn_client_cleanup(dest_base_dir,
-                _svn_ctx,subpool);
-        if (!err)
+        if (err->apr_err == SVN_ERR_RA_ILLEGAL_URL)
+        {
+            // ignore errors when remote path doesn't exist (no scenery data for ocean areas)
+        }
+        else
         {
             SG_LOG(SG_TERRAIN,SG_ALERT,
-                   "SVN repository cleanup successful for '" << dir << "'.");
+                    "Failed to synchronize directory '" << dir << "', " <<
+                    err->message << " (code " << err->apr_err << ").");
+            svn_error_clear(err);
+            // try to clean up
+            err = svn_client_cleanup(dest_base_dir.str().c_str(),
+                    _svn_ctx,subpool);
+            if (!err)
+            {
+                SG_LOG(SG_TERRAIN,SG_ALERT,
+                       "SVN repository cleanup successful for '" << dir << "'.");
+            }
+            ReturnValue = false;
         }
-        ReturnValue = false;
     } else
     {
         SG_LOG(SG_TERRAIN,SG_DEBUG, "Done with scenery directory " << dir);
@@ -385,22 +458,48 @@ bool SGTerraSync::SvnThread::syncTreeInternal(const char* dir)
 
 bool SGTerraSync::SvnThread::syncTreeExternal(const char* dir)
 {
-    int rc;
-    char command[512];
+    ostringstream buf;
+    SGPath localPath( _local_dir );
+    localPath.append( dir );
+
     if (_use_svn)
     {
-        snprintf( command, 512,
-            "%s %s/%s %s/%s", svn_cmd,
-            _svn_server.c_str(), dir,
-            _local_dir.c_str(), dir );
+        buf << "\"" << _svn_command << "\" "
+            << svn_options << " "
+            << "\"" << _svn_server << "/" << dir << "\" "
+            << "\"" << localPath.str_native() << "\"";
     } else {
-        snprintf( command, 512,
-            "%s %s/%s/ %s/%s/", rsync_cmd,
-            _rsync_server.c_str(), dir,
-            _local_dir.c_str(), dir );
+        buf << rsync_cmd << " "
+            << "\"" << _rsync_server << "/" << dir << "/\" "
+            << "\"" << localPath.str_native() << "/\"";
     }
+
+    string command;
+#ifdef SG_WINDOWS
+        // windows command line parsing is just lovely...
+        // to allow white spaces, the system call needs this:
+        // ""C:\Program Files\something.exe" somearg "some other arg""
+        // Note: whitespace strings quoted by a pair of "" _and_ the 
+        //       entire string needs to be wrapped by "" too.
+        // The svn url needs forward slashes (/) as a path separator while
+        // the local path needs windows-native backslash as a path separator.
+    command = "\"" + buf.str() + "\"";
+#else
+    command = buf.str();
+#endif
     SG_LOG(SG_TERRAIN,SG_DEBUG, "sync command '" << command << "'");
-    rc = system( command );
+
+#ifdef SG_WINDOWS
+    // tbd: does Windows support "popen"?
+    int rc = system( command.c_str() );
+#else
+    FILE* pipe = popen( command.c_str(), "r");
+    int rc=-1;
+    // wait for external process to finish
+    if (pipe)
+        rc = pclose(pipe);
+#endif
+
     if (rc)
     {
         SG_LOG(SG_TERRAIN,SG_ALERT,
@@ -424,13 +523,16 @@ void SGTerraSync::SvnThread::run()
             _completedTiles.find( next._dir );
         time_t now = time(0);
         if ((ii == _completedTiles.end())||
-            ((ii->second + 60*60*24) < now ))
+            (ii->second < now ))
         {
+            bool isNewDirectory = false;
+
             _busy = true;
-            if (!syncTree(next._dir.c_str()))
+            if (!syncTree(next._dir.c_str(),isNewDirectory))
             {
                 _consecutive_errors++;
                 _fail_count++;
+                _completedTiles[ next._dir ] = now + UpdateInterval::FailedAttempt;
             }
             else
             {
@@ -442,15 +544,21 @@ void SGTerraSync::SvnThread::run()
                 {
                     // updated a tile
                     _updated_tile_count++;
-                    _freshTiles.push_back(next);
-                    _is_dirty = true;
+                    if (isNewDirectory)
+                    {
+                        // for now only report new directories to refresh display
+                        // (i.e. only when ocean needs to be replaced with actual data)
+                        _freshTiles.push_back(next);
+                        _is_dirty = true;
+                    }
                 }
+                _completedTiles[ next._dir ] = now + UpdateInterval::SuccessfulAttempt;
             }
             _busy = false;
-            _completedTiles[ next._dir ] = now;
         }
 
-        if (_consecutive_errors >= 5)
+        if ((_allowed_errors >= 0)&&
+            (_consecutive_errors >= _allowed_errors))
         {
             _stalled = true;
             _stop = true;
@@ -476,16 +584,18 @@ int SGTerraSync::SvnThread::svnClientSetup(void)
     //  not supported under msvc 7.1 ( code inside svn_cmdline_init )
     if (svn_cmdline_init("terrasync", 0) != EXIT_SUCCESS)
         return EXIT_FAILURE;
+
+    // revert locale setting
+    setlocale(LC_ALL,"C");
 #else
+    /* svn_cmdline_init configures the locale. Setup environment to ensure the
+     * default "C" locale remains active, since fgfs isn't locale aware - especially
+     * requires "." as decimal point in strings containing floating point varibales. */
+    setenv("LC_ALL", "C", 1);
+
     if (svn_cmdline_init("terrasync", stderr) != EXIT_SUCCESS)
         return EXIT_FAILURE;
 #endif
-    /* Oh no! svn_cmdline_init configures the locale - affecting numeric output
-     * formats (i.e. sprintf("%f", ...)). fgfs relies on "C" locale in many places
-     * (including assumptions on required sprintf buffer sizes). Things go horribly
-     * wrong when the locale is changed to anything else but "C". Might be enough to
-     * revert LC_NUMERIC locale - but we'll do a complete revert for now...*/
-    setlocale(LC_ALL,"C");
 
     apr_pool_t *pool;
     apr_pool_create(&pool, NULL);
@@ -562,7 +672,8 @@ SGTerraSync::SGTerraSync(SGPropertyNode_ptr root) :
     last_lat(NOWHERE),
     last_lon(NOWHERE),
     _terraRoot(root->getNode("/sim/terrasync",true)),
-    _tile_cache(NULL)
+    _refreshCb(NULL),
+    _userCbData(NULL)
 {
     _svnThread = new SvnThread();
 }
@@ -576,40 +687,51 @@ SGTerraSync::~SGTerraSync()
 
 void SGTerraSync::init()
 {
-    _refresh_display = _terraRoot->getNode("refresh-display",true);
-    _terraRoot->getNode("built-in-svn-available",true)->setBoolValue(svn_built_in_available);
+    _refreshDisplay = _terraRoot->getNode("refresh-display",true);
+    _terraRoot->setBoolValue("built-in-svn-available",svn_built_in_available);
     reinit();
 }
 
 void SGTerraSync::reinit()
 {
     // do not reinit when enabled and we're already up and running
-    if ((_terraRoot->getNode("enabled",true)->getBoolValue())&&
+    if ((_terraRoot->getBoolValue("enabled",false))&&
          (_svnThread->_active && _svnThread->_running))
         return;
 
     _svnThread->stop();
 
-    if (_terraRoot->getNode("enabled",true)->getBoolValue())
+    if (_terraRoot->getBoolValue("enabled",false))
     {
-        _svnThread->setSvnServer(_terraRoot->getNode("svn-server",true)->getStringValue());
-        _svnThread->setRsyncServer(_terraRoot->getNode("rsync-server",true)->getStringValue());
-        _svnThread->setLocalDir(_terraRoot->getNode("scenery-dir",true)->getStringValue());
+        _svnThread->setSvnServer(_terraRoot->getStringValue("svn-server",""));
+        _svnThread->setRsyncServer(_terraRoot->getStringValue("rsync-server",""));
+        _svnThread->setLocalDir(_terraRoot->getStringValue("scenery-dir",""));
+        _svnThread->setAllowedErrorCount(_terraRoot->getIntValue("max-errors",5));
 
     #ifdef HAVE_SVN_CLIENT_H
-        _svnThread->setUseBuiltin(_terraRoot->getNode("use-built-in-svn",true)->getBoolValue());
+        _svnThread->setUseBuiltin(_terraRoot->getBoolValue("use-built-in-svn",true));
     #else
-        _terraRoot->getNode("use-built-in-svn",true)->setBoolValue(false);
+        _terraRoot->setBoolValue("use-built-in-svn",false);
     #endif
-        _svnThread->setUseSvn(_terraRoot->getNode("use-svn",true)->getBoolValue());
+        _svnThread->setUseSvn(_terraRoot->getBoolValue("use-svn",true));
+        _svnThread->setExtSvnUtility(_terraRoot->getStringValue("ext-svn-utility","svn"));
 
         if (_svnThread->start())
+        {
             syncAirportsModels();
+            if (last_lat != NOWHERE && last_lon != NOWHERE)
+            {
+                // reschedule most recent position
+                int lat = last_lat;
+                int lon = last_lon;
+                last_lat = NOWHERE;
+                last_lon = NOWHERE;
+                schedulePosition(lat, lon);
+            }
+        }
     }
 
-    _stalled_node->setBoolValue(_svnThread->_stalled);
-    last_lat = NOWHERE;
-    last_lon = NOWHERE;
+    _stalledNode->setBoolValue(_svnThread->_stalled);
 }
 
 void SGTerraSync::bind()
@@ -624,10 +746,12 @@ void SGTerraSync::bind()
     _terraRoot->getNode("update-count", true)->setAttribute(SGPropertyNode::WRITE,false);
     _terraRoot->getNode("error-count", true)->setAttribute(SGPropertyNode::WRITE,false);
     _terraRoot->getNode("tile-count", true)->setAttribute(SGPropertyNode::WRITE,false);
+    _terraRoot->getNode("use-built-in-svn", true)->setAttribute(SGPropertyNode::USERARCHIVE,false);
+    _terraRoot->getNode("use-svn", true)->setAttribute(SGPropertyNode::USERARCHIVE,false);
     // stalled is used as a signal handler (to connect listeners triggering GUI pop-ups)
-    _stalled_node = _terraRoot->getNode("stalled", true);
-    _stalled_node->setBoolValue(_svnThread->_stalled);
-    _stalled_node->setAttribute(SGPropertyNode::PRESERVE,true);
+    _stalledNode = _terraRoot->getNode("stalled", true);
+    _stalledNode->setBoolValue(_svnThread->_stalled);
+    _stalledNode->setAttribute(SGPropertyNode::PRESERVE,true);
 }
 
 void SGTerraSync::unbind()
@@ -654,10 +778,10 @@ void SGTerraSync::update(double)
                 SG_LOG(SG_TERRAIN,SG_ALERT,
                         "Automatic scenery download/synchronization has stopped.");
             }
-            _stalled_node->setBoolValue(_svnThread->_stalled);
+            _stalledNode->setBoolValue(_svnThread->_stalled);
         }
 
-        if (!_refresh_display->getBoolValue())
+        if (!_refreshDisplay->getBoolValue())
             return;
 
         while (_svnThread->hasNewTiles())
@@ -674,7 +798,7 @@ void SGTerraSync::update(double)
 void SGTerraSync::refreshScenery(SGPath path,const string& relativeDir)
 {
     // find tiles to be refreshed
-    if (_tile_cache)
+    if (_refreshCb)
     {
         path.append(relativeDir);
         if (path.exists())
@@ -688,7 +812,7 @@ void SGTerraSync::refreshScenery(SGPath path,const string& relativeDir)
             {
                 // reload scenery tile
                 long index = atoi(tileList[i].file().c_str());
-                _tile_cache->refresh_tile(index);
+                _refreshCb(_userCbData, index);
             }
         }
     }
@@ -696,27 +820,25 @@ void SGTerraSync::refreshScenery(SGPath path,const string& relativeDir)
 
 bool SGTerraSync::isIdle() {return _svnThread->isIdle();}
 
-void SGTerraSync::setTileCache(TileCache* tile_cache)
+void SGTerraSync::setTileRefreshCb(SGTerraSyncCallback refreshCb, void* userCbData)
 {
-    _tile_cache = tile_cache;
+    _refreshCb = refreshCb;
+    _userCbData = userCbData;
 }
 
 void SGTerraSync::syncAirportsModels()
 {
-    char synced_other;
-    for ( synced_other = 'K'; synced_other <= 'Z'; synced_other++ )
-    {
-        char dir[512];
-        snprintf( dir, 512, "Airports/%c", synced_other );
-        WaitingTile w(dir,false);
-        _svnThread->request( w );
-    }
-    for ( synced_other = 'A'; synced_other <= 'J'; synced_other++ )
+    static const char* bounds = "MZAJKL"; // airport sync order: K-L, A-J, M-Z
+    // note "request" method uses LIFO order, i.e. processes most recent request first
+    for( unsigned i = 0; i < strlen(bounds)/2; i++ )
     {
-        char dir[512];
-        snprintf( dir, 512, "Airports/%c", synced_other );
-        WaitingTile w(dir,false);
-        _svnThread->request( w );
+        for ( char synced_other = bounds[2*i]; synced_other <= bounds[2*i+1]; synced_other++ )
+        {
+            ostringstream dir;
+            dir << "Airports/" << synced_other;
+            WaitingTile w(dir.str(),false);
+            _svnThread->request( w );
+        }
     }
     WaitingTile w("Models",false);
     _svnThread->request( w );
@@ -759,12 +881,11 @@ void SGTerraSync::syncArea( int lat, int lon )
     bool refresh=true;
     for (const char** tree = &terrainobjects[0]; *tree; tree++)
     {
-        char dir[512];
-        snprintf( dir, 512, "%s/%c%03d%c%02d/%c%03d%c%02d",
-            *tree,
-            EW, abs(baselon), NS, abs(baselat),
-            EW, abs(lon), NS, abs(lat) );
-        WaitingTile w(dir,refresh);
+        ostringstream dir;
+        dir << *tree << "/" << setfill('0')
+            << EW << setw(3) << abs(baselon) << NS << setw(2) << abs(baselat) << "/"
+            << EW << setw(3) << abs(lon)     << NS << setw(2) << abs(lat);
+        WaitingTile w(dir.str(),refresh);
         _svnThread->request( w );
         refresh=false;
     }
@@ -802,46 +923,49 @@ void SGTerraSync::syncAreas( int lat, int lon, int lat_dir, int lon_dir )
 
 bool SGTerraSync::schedulePosition(int lat, int lon)
 {
+    bool Ok = false;
+
     // Ignore messages where the location does not change
     if ( lat != last_lat || lon != last_lon )
     {
-        SG_LOG(SG_TERRAIN,SG_DEBUG, "Requesting scenery update for position " << 
-                                    lat << "," << lon);
-        int lat_dir, lon_dir, dist;
-        if ( last_lat == NOWHERE || last_lon == NOWHERE )
-        {
-            lat_dir = lon_dir = 0;
-        } else
+        if (_svnThread->_running)
         {
-            dist = lat - last_lat;
-            if ( dist != 0 )
-            {
-                lat_dir = dist / abs(dist);
-            }
-            else
-            {
-                lat_dir = 0;
-            }
-            dist = lon - last_lon;
-            if ( dist != 0 )
-            {
-                lon_dir = dist / abs(dist);
-            } else
+            SG_LOG(SG_TERRAIN,SG_DEBUG, "Requesting scenery update for position " <<
+                                        lat << "," << lon);
+            int lat_dir=0;
+            int lon_dir=0;
+            if ( last_lat != NOWHERE && last_lon != NOWHERE )
             {
-                lon_dir = 0;
+                int dist = lat - last_lat;
+                if ( dist != 0 )
+                {
+                    lat_dir = dist / abs(dist);
+                }
+                else
+                {
+                    lat_dir = 0;
+                }
+                dist = lon - last_lon;
+                if ( dist != 0 )
+                {
+                    lon_dir = dist / abs(dist);
+                } else
+                {
+                    lon_dir = 0;
+                }
             }
-        }
-
-        SG_LOG(SG_TERRAIN,SG_DEBUG, "Scenery update for " << 
-               "lat = " << lat << ", lon = " << lon <<
-               ", lat_dir = " << lat_dir << ",  " <<
-               "lon_dir = " << lon_dir);
 
-        syncAreas( lat, lon, lat_dir, lon_dir );
+            SG_LOG(SG_TERRAIN,SG_DEBUG, "Scenery update for " <<
+                   "lat = " << lat << ", lon = " << lon <<
+                   ", lat_dir = " << lat_dir << ",  " <<
+                   "lon_dir = " << lon_dir);
 
+            syncAreas( lat, lon, lat_dir, lon_dir );
+            Ok = true;
+        }
         last_lat = lat;
         last_lon = lon;
-        return true;
     }
-    return false;
+
+    return Ok;
 }