diff --git a/Common/CMakeLists.txt b/Common/CMakeLists.txt
index cb20d416309f44d81e2f49a931584bd68690ec30..bbdd495fe01748cf6935b0219a910dd729cb55cb 100644
--- a/Common/CMakeLists.txt
+++ b/Common/CMakeLists.txt
@@ -26,5 +26,12 @@ set(SRC
   GamePad.cpp
 )
 
+if(NOT ENABLE_ONELAB2)
+  set(SRC
+    ${SRC}
+    gmshLocalNetworkClient.cpp
+  )
+endif(NOT ENABLE_ONELAB2)
+
 file(GLOB HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h) 
 append_gmsh_src(Common "${SRC};${HDR}")
diff --git a/Common/Gmsh.cpp b/Common/Gmsh.cpp
index 1c26a2b39e059818dd0d097af3a5fc8f2d765faa..ffd8a5078b4d1b090afc548223b7e0b6c89713c6 100644
--- a/Common/Gmsh.cpp
+++ b/Common/Gmsh.cpp
@@ -277,11 +277,8 @@ int GmshBatch()
     CreateOutputFile(name, CTX::instance()->mesh.fileFormat);
   }
 
-#if defined(HAVE_FLTK) // FIXME this actually does not require the GUI
   // launch solver (if requested)
-  solver_batch_cb(0, (void*)CTX::instance()->launchSolverAtStartup);
-#endif
-
+  solver_batch_cb((void*)CTX::instance()->launchSolverAtStartup);
 
   time_t now;
   time(&now);
diff --git a/Common/GmshSocket.h b/Common/GmshSocket.h
index 467a93687d1e3f852d2d3cd430c98bce6798bff1..935745e2df63aee7e3a762f90074818109e78334 100644
--- a/Common/GmshSocket.h
+++ b/Common/GmshSocket.h
@@ -28,9 +28,7 @@
 #ifndef _GMSH_SOCKET_H_
 #define _GMSH_SOCKET_H_
 
-#if !defined(ONELAB_LOADER)
 #include "GmshConfig.h"
-#endif
 
 #include <string>
 #include <stdio.h>
diff --git a/Common/gmshLocalNetworkClient.cpp b/Common/gmshLocalNetworkClient.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..25db11c1df28f81f864fae95e5877f9bad6bc753
--- /dev/null
+++ b/Common/gmshLocalNetworkClient.cpp
@@ -0,0 +1,864 @@
+// Gmsh - Copyright (C) 1997-2014 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to the public mailing list <gmsh@geuz.org>.
+
+#include "gmshLocalNetworkClient.h"
+#include "GmshConfig.h"
+#include "Gmsh.h"
+#include "Context.h"
+#include "OS.h"
+#include "StringUtils.h"
+#include "onelabUtils.h"
+#include "OpenFile.h"
+#include "CreateFile.h"
+#include "PView.h"
+#include "Options.h"
+#include "GModel.h"
+
+#if defined(HAVE_FLTK)
+#include "FlGui.h"
+#include "onelabGroup.h"
+#include "drawContext.h"
+#endif
+
+#if defined(HAVE_ONELAB_METAMODEL)
+#include "OnelabClients.h"
+#include "metamodel.h"
+#endif
+
+class onelabGmshServer : public GmshServer{
+ private:
+  onelab::localNetworkClient *_client;
+ public:
+  onelabGmshServer(onelab::localNetworkClient *client)
+    : GmshServer(), _client(client) {}
+  ~onelabGmshServer(){}
+  int NonBlockingSystemCall(const char *str)
+  {
+    return SystemCall(str);
+  }
+  int NonBlockingWait(double waitint, double timeout, int socket)
+  {
+    double start = GetTimeInSeconds();
+    while(1){
+      if(timeout > 0 && GetTimeInSeconds() - start > timeout)
+        return 2; // timeout
+      if(_client->getPid() < 0 || (_client->getExecutable().empty() &&
+                                   !CTX::instance()->solver.listen))
+        return 1; // process has been killed or we stopped listening
+      // check if there is data (call select with a zero timeout to
+      // return immediately, i.e., do polling)
+      int ret = Select(0, 0, socket);
+      if(ret == 0){ // nothing available
+        if(timeout < 0){
+          // if asked, refresh the onelab GUI, but no more than every 1/4th of
+          // a second
+          static double lastRefresh = 0.;
+          if(start - lastRefresh > 0.25){
+            std::vector<onelab::string> ps;
+            onelab::server::instance()->get(ps, "Gmsh/Action");
+            if(ps.size() && ps[0].getValue() == "refresh"){
+              ps[0].setVisible(false);
+              ps[0].setValue("");
+              onelab::server::instance()->set(ps[0]);
+#if defined(HAVE_FLTK)
+              if(FlGui::available()) onelab_cb(0, (void*)"refresh");
+#endif
+            }
+            lastRefresh = start;
+          }
+        }
+        // wait at most waitint seconds and respond to FLTK events
+#if defined(HAVE_FLTK)
+        if(FlGui::available()) FlGui::instance()->wait(waitint);
+#endif
+        // return to caller (we will be back here soon again)
+	if(timeout < 0) return 3;
+      }
+      else if(ret > 0){
+        return 0; // data is there!
+      }
+      else{
+        // an error happened
+        _client->setPid(-1);
+        return 1;
+      }
+    }
+  }
+  int LaunchClient()
+  {
+    std::string sockname;
+    std::ostringstream tmp;
+    const char *port = strstr(CTX::instance()->solver.socketName.c_str(), ":");
+    if(!port){
+      // Unix socket
+      tmp << CTX::instance()->homeDir << CTX::instance()->solver.socketName
+          << _client->getId();
+      sockname = FixWindowsPath(tmp.str());
+    }
+    else{
+      // TCP/IP socket
+      if(CTX::instance()->solver.socketName.size() &&
+         CTX::instance()->solver.socketName[0] == ':')
+        tmp << GetHostName(); // prepend hostname if only the port number is given
+      tmp << CTX::instance()->solver.socketName;
+      if(atoi(port + 1)) // nonzero port is given - append client id
+        tmp << _client->getId();
+      sockname = tmp.str();
+    }
+
+    std::string command = FixWindowsPath(_client->getExecutable());
+    if(command.size()){
+      std::vector<std::string> args = onelabUtils::getCommandLine(_client);
+      for(unsigned int i = 0; i < args.size(); i++)
+        command.append(" " + args[i]);
+      command.append(" " + _client->getSocketSwitch() +
+                     " \"" + _client->getName() + "\" %s");
+    }
+    else{
+      Msg::Info("Listening on socket '%s'", sockname.c_str());
+    }
+
+    int sock;
+    try{
+      sock = Start(command.c_str(), sockname.c_str(),
+                   CTX::instance()->solver.timeout);
+    }
+    catch(const char *err){
+      Msg::Error("Abnormal server termination (%s on socket %s)", err,
+                 sockname.c_str());
+      sock = -1;
+    }
+
+    return sock;
+  }
+};
+
+bool gmshLocalNetworkClient::receiveMessage(gmshLocalNetworkClient *master)
+{
+  // receive a message on the associated GmshServer; 'master' is only used when
+  // creating subclients with GMSH_CONNECT.
+
+  double timer = GetTimeInSeconds();
+
+  if(!getGmshServer()){
+    Msg::Error("Abnormal server termination (no valid server)");
+    return false;
+  }
+
+  int type, length, swap;
+  if(!getGmshServer()->ReceiveHeader(&type, &length, &swap)){
+    Msg::Error("Abnormal server termination (did not receive message header)");
+    return false;
+  }
+
+  std::string message(length, ' '), blank = message;
+  if(!getGmshServer()->ReceiveMessage(length, &message[0])){
+    Msg::Error("Abnormal server termination (did not receive message body)");
+    return false;
+  }
+
+  if(message == blank && !(type == GmshSocket::GMSH_PROGRESS ||
+                           type == GmshSocket::GMSH_INFO ||
+                           type == GmshSocket::GMSH_WARNING ||
+                           type == GmshSocket::GMSH_ERROR)){
+    // we should still allow blank msg strings to be sent
+    Msg::Error("Abnormal server termination (blank message: client not stopped?)");
+    return false;
+  }
+
+  switch (type) {
+  case GmshSocket::GMSH_START:
+    setPid(atoi(message.c_str()));
+    break;
+  case GmshSocket::GMSH_STOP:
+    setPid(-1);
+    if(getFather()){
+      std::string reply = getName(); // reply is dummy
+      getFather()->getGmshServer()->SendMessage
+        (GmshSocket::GMSH_STOP, reply.size(), &reply[0]);
+    }
+    break;
+  case GmshSocket::GMSH_PARAMETER:
+  case GmshSocket::GMSH_PARAMETER_UPDATE:
+    {
+      std::string version, ptype, name;
+      onelab::parameter::getInfoFromChar(message, version, ptype, name);
+      if(onelab::parameter::version() != version){
+        Msg::Error("ONELAB version mismatch (server: %s / client: %s)",
+                   onelab::parameter::version().c_str(), version.c_str());
+      }
+      else if(ptype == "number"){
+        onelab::number p; p.fromChar(message);
+        if(type == GmshSocket::GMSH_PARAMETER_UPDATE){
+          std::vector<onelab::number> par; get(par, name);
+          if(par.size()) {
+            onelab::number y = p; p = par[0]; onelabUtils::updateNumber(p, y);
+          }
+        }
+        set(p);
+        if(p.getName() == getName() + "/Progress"){
+#if defined(HAVE_FLTK)
+          if(FlGui::available())
+            FlGui::instance()->setProgress(p.getLabel().c_str(), p.getValue(),
+                                           p.getMin(), p.getMax());
+#endif
+        }
+      }
+      else if(ptype == "string"){
+        onelab::string p; p.fromChar(message);
+        if(type == GmshSocket::GMSH_PARAMETER_UPDATE){
+          std::vector<onelab::string> par; get(par, name);
+          if(par.size()){
+            onelab::string y = p; p = par[0]; onelabUtils::updateString(p,y);
+          }
+	}
+        set(p);
+      }
+      else if(ptype == "region"){
+        onelab::region p; p.fromChar(message); set(p);
+      }
+      else if(ptype == "function"){
+        onelab::function p; p.fromChar(message); set(p);
+      }
+      else
+        Msg::Error("Unknown ONELAB parameter type: %s", ptype.c_str());
+    }
+    break;
+  case GmshSocket::GMSH_PARAMETER_QUERY:
+    {
+      std::string version, ptype, name, reply;
+      onelab::parameter::getInfoFromChar(message, version, ptype, name);
+      if(onelab::parameter::version() != version){
+        Msg::Error("ONELAB version mismatch (server: %s / client: %s)",
+                   onelab::parameter::version().c_str(), version.c_str());
+      }
+      else if(ptype == "number"){
+        std::vector<onelab::number> par; get(par, name);
+        if(par.size() == 1) reply = par[0].toChar();
+      }
+      else if(ptype == "string"){
+        std::vector<onelab::string> par; get(par, name);
+        if(par.size() == 1) reply = par[0].toChar();
+      }
+      else if(ptype == "region"){
+        std::vector<onelab::region> par; get(par, name);
+        if(par.size() == 1) reply = par[0].toChar();
+      }
+      else if(ptype == "function"){
+        std::vector<onelab::function> par; get(par, name);
+        if(par.size() == 1) reply = par[0].toChar();
+      }
+      else
+        Msg::Error("Unknown ONELAB parameter type in query: %s", ptype.c_str());
+
+      if(reply.size()){
+        getGmshServer()->SendMessage
+          (GmshSocket::GMSH_PARAMETER, reply.size(), &reply[0]);
+      }
+      else{
+        reply = name;
+        getGmshServer()->SendMessage
+          (GmshSocket::GMSH_PARAMETER_NOT_FOUND, reply.size(), &reply[0]);
+      }
+    }
+    break;
+  case GmshSocket::GMSH_PARAMETER_QUERY_ALL:
+    {
+      std::string version, ptype, name, reply;
+      std::vector<std::string> replies;
+      onelab::parameter::getInfoFromChar(message, version, ptype, name);
+      if(onelab::parameter::version() != version){
+        Msg::Error("ONELAB version mismatch (server: %s / client: %s)",
+                   onelab::parameter::version().c_str(), version.c_str());
+      }
+      else if(ptype == "number"){
+        std::vector<onelab::number> numbers; get(numbers);
+        for(std::vector<onelab::number>::iterator it = numbers.begin();
+            it != numbers.end(); it++) replies.push_back((*it).toChar());
+      }
+      else if(ptype == "string"){
+        std::vector<onelab::string> strings; get(strings);
+        for(std::vector<onelab::string>::iterator it = strings.begin();
+            it != strings.end(); it++) replies.push_back((*it).toChar());
+      }
+      else if(ptype == "region"){
+        std::vector<onelab::region> regions; get(regions);
+        for(std::vector<onelab::region>::iterator it = regions.begin();
+            it != regions.end(); it++) replies.push_back((*it).toChar());
+      }
+      else if(ptype == "function"){
+        std::vector<onelab::function> functions; get(functions);
+        for(std::vector<onelab::function>::iterator it = functions.begin();
+            it != functions.end(); it++) replies.push_back((*it).toChar());
+      }
+      else
+        Msg::Error("Unknown ONELAB parameter type in query: %s", ptype.c_str());
+
+      for(unsigned int i = 0; i < replies.size(); i++)
+        getGmshServer()->SendMessage
+          (GmshSocket::GMSH_PARAMETER_QUERY_ALL, replies[i].size(), &replies[i][0]);
+      reply = "Sent all ONELAB " + ptype + "s";
+      getGmshServer()->SendMessage
+        (GmshSocket::GMSH_PARAMETER_QUERY_END, reply.size(), &reply[0]);
+    }
+    break;
+  case GmshSocket::GMSH_PARAMETER_CLEAR:
+    clear(message == "*" ? "" : message);
+    break;
+  case GmshSocket::GMSH_PROGRESS:
+    Msg::StatusBar(false, "%s %s", _name.c_str(), message.c_str());
+    break;
+  case GmshSocket::GMSH_INFO:
+    Msg::Direct("Info    : %s - %s", _name.c_str(), message.c_str());
+    break;
+  case GmshSocket::GMSH_WARNING:
+    Msg::Warning("%s - %s", _name.c_str(), message.c_str());
+    break;
+  case GmshSocket::GMSH_ERROR:
+    Msg::Error("%s - %s", _name.c_str(), message.c_str());
+    break;
+  case GmshSocket::GMSH_MERGE_FILE:
+    if(CTX::instance()->solver.autoMergeFile){
+      unsigned int n = PView::list.size();
+      MergePostProcessingFile(message, CTX::instance()->solver.autoShowViews,
+                              CTX::instance()->solver.autoShowLastStep, true);
+#if defined(HAVE_FLTK)
+      drawContext::global()->draw();
+      if(FlGui::available() && n != PView::list.size()){
+        FlGui::instance()->rebuildTree(true);
+        FlGui::instance()->openModule("Post-processing");
+      }
+#endif
+    }
+    break;
+  case GmshSocket::GMSH_OPEN_PROJECT:
+    OpenProject(message);
+#if defined(HAVE_FLTK)
+    drawContext::global()->draw();
+#endif
+    break;
+  case GmshSocket::GMSH_PARSE_STRING:
+    ParseString(message, true);
+#if defined(HAVE_FLTK)
+    drawContext::global()->draw();
+#endif
+    break;
+  case GmshSocket::GMSH_SPEED_TEST:
+    Msg::Info("got %d Mb message in %g seconds",
+              length / 1024 / 1024, GetTimeInSeconds() - timer);
+    break;
+  case GmshSocket::GMSH_VERTEX_ARRAY:
+    {
+      int n = PView::list.size();
+      PView::fillVertexArray(this, length, &message[0], swap);
+#if defined(HAVE_FLTK)
+      if(FlGui::available())
+        FlGui::instance()->updateViews(n != (int)PView::list.size(), true);
+      drawContext::global()->draw();
+#endif
+    }
+    break;
+  case GmshSocket::GMSH_CONNECT:
+    {
+      std::string::size_type first = 0;
+      std::string clientName = onelab::parameter::getNextToken(message, first);
+      std::string command = onelab::parameter::getNextToken(message, first);
+      if (!onelab::server::instance()->isRegistered(clientName)){
+	gmshLocalNetworkClient* subClient =
+	  new gmshLocalNetworkClient(clientName, command);
+	onelabGmshServer *server = new onelabGmshServer(subClient);
+	subClient->setPid(0);
+	int sock = server->LaunchClient();
+	if(sock < 0){ // could not establish the connection: aborting
+	  server->Shutdown();
+	  delete server;
+	  Msg::Error("Could not connect client '%s'", subClient->getName().c_str());
+	}
+	else{
+	  Msg::StatusBar(true, "Running '%s'...", subClient->getName().c_str());
+	  subClient->setGmshServer(server);
+	  subClient->setFather(this);
+	  master->addClient(subClient);
+	}
+      }
+      else{
+	std::string reply = "";
+	for(onelab::server::citer it = onelab::server::instance()->firstClient();
+	    it != onelab::server::instance()->lastClient(); it++){
+	  reply.append(it->second->getName() + " ");
+	}
+	Msg::Error("Skipping already existing client <%s> - Registered clients are < %s>",clientName.c_str(),reply.c_str());
+	getGmshServer()->SendMessage
+	  (GmshSocket::GMSH_STOP, reply.size(), &reply[0]); // reply is dummy
+      }
+    }
+    break;
+  case GmshSocket::GMSH_OLPARSE:
+    {
+      std::string reply = "unavailable";
+#if defined(HAVE_ONELAB_METAMODEL)
+      std::string::size_type first = 0;
+      std::string clientName = onelab::parameter::getNextToken(message, first);
+      std::string fullName = onelab::parameter::getNextToken(message, first);
+      if (!onelab::server::instance()->isRegistered(clientName)){
+	preProcess(clientName, fullName); // contrib/onelab/OnelabParser.cpp
+	Msg::Info("Preprocess file <%s> done", fullName.c_str());
+	reply = onelab::server::instance()->getChanged(clientName) ? "true" : "false";
+      }
+      else{
+	Msg::Error("Skipping client with already existing name <%s>",clientName.c_str());
+      }
+#endif
+      getGmshServer()->SendMessage
+	(GmshSocket::GMSH_OLPARSE, reply.size(), &reply[0]);
+    }
+    break;
+  case GmshSocket::GMSH_CLIENT_CHANGED:
+    {
+      std::string::size_type first = 0;
+      std::string command = onelab::parameter::getNextToken(message, first);
+      std::string name = onelab::parameter::getNextToken(message, first);
+      if(command == "get"){
+	std::string reply = onelab::server::instance()->getChanged(name) ? "true" : "false";
+	getGmshServer()->SendMessage
+	  (GmshSocket::GMSH_CLIENT_CHANGED, reply.size(), &reply[0]);
+      }
+      else if(command == "set"){
+	std::string changed = onelab::parameter::getNextToken(message, first);
+	onelab::server::instance()->setChanged(changed=="true"?true:false,name);
+      }
+    }
+    break;
+  default:
+    Msg::Warning("Received unknown message type (%d)", type);
+    break;
+  }
+
+  return true;
+}
+
+bool gmshLocalNetworkClient::run()
+{
+ new_connection:
+  setPid(0); // dummy pid, should be non-negative
+
+  onelabGmshServer *server = new onelabGmshServer(this);
+
+  int sock = server->LaunchClient();
+
+  if(sock < 0){
+    // could not establish the connection: aborting
+    server->Shutdown();
+    delete server;
+    return false;
+  }
+
+  Msg::StatusBar(true, "Running '%s'...", _name.c_str());
+
+  setGmshServer(server);
+
+  while(1) {
+    if(getExecutable().empty() && !CTX::instance()->solver.listen){
+      // we stopped listening to the special "Listen" client
+      break;
+    }
+
+    // loop over all the clients (usually only one, but can be more if we
+    // spawned subclients) and check if data is available for one of them
+    bool stop = false, haveData = false;
+    gmshLocalNetworkClient *c = 0;
+    std::vector<gmshLocalNetworkClient*> toDelete;
+    for(int i = 0; i < getNumClients(); i++){
+      c = getClient(i);
+      if(c->getPid() < 0){
+        if(c == this){ // the "master" client stopped
+          stop = true;
+          break;
+        }
+        else{
+          // this subclient is not active anymore: shut down and delete its
+          // server and mark the client for deletion
+          GmshServer *s = c->getGmshServer();
+          c->setGmshServer(0);
+          c->setFather(0);
+          if(s){
+            s->Shutdown();
+            delete s;
+          }
+          toDelete.push_back(c);
+          continue;
+        }
+      }
+      GmshServer *s = c->getGmshServer();
+      if(!s){
+        Msg::Error("Abnormal server termination (no valid server)");
+        stop = true;
+        break;
+      }
+      else{
+        int ret = s->NonBlockingWait(0.001, -1.);
+        if(ret == 0){ // we have data from this particular client
+          haveData = true;
+          break;
+        }
+        else if(ret == 3){ // pass to the next client
+          continue;
+        }
+        else{ // an error occurred
+          stop = true;
+          break;
+        }
+      }
+    }
+    for(unsigned int i = 0; i < toDelete.size(); i++){
+      removeClient(toDelete[i]);
+      delete toDelete[i];
+    }
+
+    // break the while(1) if the master client has stopped or if we encountered
+    // a problem
+    if(stop) break;
+
+    // if data is available try to get the message from the corresponding
+    // client; break the while(1) if we could not receive the message
+    if(haveData && !c->receiveMessage(this)) break;
+
+    // break the while(1) if the master client has stopped
+    if(c == this && c->getPid() < 0) break;
+  }
+
+  // we are done running the (master) client: delete the servers and the
+  // subclients, if any remain (they should have been deleted already).
+  std::vector<gmshLocalNetworkClient*> toDelete;
+  for(int i = 0; i < getNumClients(); i++){
+    gmshLocalNetworkClient *c = getClient(i);
+    GmshServer *s = c->getGmshServer();
+    c->setGmshServer(0);
+    c->setFather(0);
+    if(s){
+      s->Shutdown();
+      delete s;
+    }
+    if(c != this){
+      if(c->getPid() > 0)
+        Msg::Error("Subclient %s was not stopped correctly", c->getName().c_str());
+      toDelete.push_back(c);
+    }
+  }
+  for(unsigned int i = 0; i < toDelete.size(); i++){
+    removeClient(toDelete[i]);
+    delete toDelete[i];
+  }
+
+  Msg::StatusBar(true, "Done running '%s'", _name.c_str());
+
+  if(getExecutable().empty()){
+    Msg::Info("Client disconnected: starting new connection");
+    goto new_connection;
+  }
+
+  return true;
+}
+
+bool gmshLocalNetworkClient::kill()
+{
+  // FIXME: we should kill all the clients in the list
+  if(getPid() > 0) {
+    if(KillProcess(getPid())){
+      Msg::Info("Killed '%s' (pid %d)", _name.c_str(), getPid());
+#if defined(HAVE_FLTK)
+      if(FlGui::available())
+        FlGui::instance()->setProgress("Killed", 0, 0, 0);
+#endif
+      setPid(-1);
+      return true;
+    }
+  }
+  setPid(-1);
+  return false;
+}
+
+void initializeLoops()
+{
+  onelabUtils::initializeLoop("1");
+  onelabUtils::initializeLoop("2");
+  onelabUtils::initializeLoop("3");
+
+#if defined(HAVE_FLTK)
+  if(FlGui::available() && onelab::server::instance()->getChanged())
+    FlGui::instance()->rebuildTree(false);
+#endif
+}
+
+bool incrementLoops()
+{
+  bool ret = false;
+  if(onelabUtils::incrementLoop("3"))      ret = true;
+  else if(onelabUtils::incrementLoop("2")) ret = true;
+  else if(onelabUtils::incrementLoop("1")) ret = true;
+
+  //Define ONELAB parameter indicating whether or not in a loop
+  onelab::number n("0Metamodel/Loop",ret?1:0);
+  n.setVisible(false);
+  onelab::server::instance()->set(n);
+
+#if defined(HAVE_FLTK)
+  if(FlGui::available() && onelab::server::instance()->getChanged())
+    FlGui::instance()->rebuildTree(false);
+#endif
+  return ret;
+}
+
+void updateGraphs()
+{
+  bool redraw = false;
+  for(int i = 0; i < 18; i++){
+    std::ostringstream tmp;
+    tmp << i;
+    bool ret = onelabUtils::updateGraph(tmp.str());
+    redraw = redraw || ret;
+  }
+  if(redraw){
+    // don't delete the widgets, as this is called in widget callbacks
+#if defined(HAVE_FLTK)
+    FlGui::instance()->updateViews(true, false);
+    drawContext::global()->draw();
+#endif
+  }
+}
+
+std::string timeStamp()
+{
+  time_t now;
+  time(&now);
+  tm *t = localtime(&now);
+  char stamp[32];
+  // stamp.size() is always 20
+  sprintf(stamp, "_%04d-%02d-%02d_%02d-%02d-%02d", 1900 + t->tm_year,
+          1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
+  return std::string(stamp);
+}
+
+void saveDb(const std::string &fileName)
+{
+  FILE *fp = Fopen(fileName.c_str(), "wb");
+  if(fp){
+    Msg::StatusBar(true, "Saving database '%s'...", fileName.c_str());
+    onelab::server::instance()->toFile(fp);
+    fclose(fp);
+    Msg::StatusBar(true, "Done saving database '%s'", fileName.c_str());
+  }
+  else
+    Msg::Error("Could not save database '%s'", fileName.c_str());
+}
+
+void archiveOutputFiles(const std::string &fileName)
+{
+  std::string stamp;
+  std::vector<onelab::string> ps;
+  onelab::server::instance()->get(ps,"0Metamodel/9Tag");
+  if(ps.size() && ps[0].getValue().size())
+    stamp.assign(timeStamp() + "_" + ps[0].getValue());
+  else
+    stamp.assign(timeStamp());
+
+  // add time stamp in all output files in the db, and rename them on disk
+  std::vector<onelab::string> strings;
+  onelab::server::instance()->get(strings);
+  for(unsigned int i = 0; i < strings.size(); i++){
+    if(strings[i].getName().find("9Output files") != std::string::npos){
+      std::vector<std::string> names = strings[i].getChoices();
+      names.push_back(strings[i].getValue());
+      for(unsigned int j = 0; j < names.size(); j++){
+        std::vector<std::string> split = SplitFileName(names[j]);
+        int n = split[1].size();
+        // if name is not already stamped
+        if(n < 18 || split[1][n-3] != '-' || split[1][n-6] != '-' ||
+           split[1][n-9] != '_'){
+          std::string old = names[j];
+          CreateSingleDir(split[0] + "archive/");
+          names[j] = split[0] + "archive/" + split[1] + stamp + split[2];
+          Msg::Info("Renaming '%s' into '%s'", old.c_str(), names[j].c_str());
+          rename(old.c_str(), names[j].c_str());
+        }
+      }
+      strings[i].setValue(names.back());
+      names.pop_back();
+      strings[i].setChoices(names);
+      onelab::server::instance()->set(strings[i]);
+    }
+  }
+
+  // save stamped db
+  {
+    std::vector<std::string> split = SplitFileName(fileName);
+    CreateSingleDir(split[0] + "archive/");
+    saveDb(split[0] + "archive/" + split[1] + stamp + split[2]);
+  }
+
+#if defined(HAVE_FLTK)
+  FlGui::instance()->rebuildTree(true);
+#endif
+}
+
+void archiveSolutionFiles(const std::string &fileName)
+{
+  // extract tag from db fileName, use fileName as tag otherwise
+  std::vector<std::string> split = SplitFileName(fileName);
+  std::string dir = split[0] + "archive/";
+  std::string tag = split[1];
+  if (!tag.compare(0,6,"onelab"))
+    tag.assign(tag.substr(6)); // cut off 'onelab' if present
+
+  // add tag to all solution files in the db, and rename them on disk
+  std::vector<onelab::string> strings;
+  onelab::server::instance()->get(strings,"0Metamodel/9Solution files");
+  if(strings.size()){
+    std::vector<std::string> names = strings[0].getChoices();
+    if(names.size()){
+      for(unsigned int j = 0; j < names.size(); j++){
+	std::vector<std::string> split = SplitFileName(names[j]);
+	std::string old = names[j];
+	CreateSingleDir(dir);
+	names[j] = dir + split[1] + tag + split[2];
+	Msg::Info("Renaming '%s' into '%s'", old.c_str(), names[j].c_str());
+	rename(old.c_str(), names[j].c_str());
+      }
+      strings[0].setValue(names[0]);
+      strings[0].setChoices(names);
+      onelab::server::instance()->set(strings[0]);
+#if defined(HAVE_FLTK)
+      FlGui::instance()->rebuildTree(true);
+#endif
+    }
+  }
+}
+
+void loadDb(const std::string &name)
+{
+  Msg::StatusBar(true, "Loading database '%s'...", name.c_str());
+  FILE *fp = Fopen(name.c_str(), "rb");
+  if(fp){
+    onelab::server::instance()->fromFile(fp);
+    fclose(fp);
+    Msg::StatusBar(true, "Done loading database '%s'", name.c_str());
+  }
+  else
+    Msg::Error("Could not load database '%s'", name.c_str());
+}
+
+void resetDb(bool runGmshClient)
+{
+  Msg::Info("Resetting database");
+
+  // clear everything except persistent parameters
+  std::vector<onelab::number> allNumbers, persistentNumbers;
+  std::vector<onelab::string> allStrings, persistentStrings;
+  onelab::server::instance()->get(allNumbers);
+  onelab::server::instance()->get(allStrings);
+  for(unsigned int i = 0; i < allNumbers.size(); i++){
+    if(allNumbers[i].getAttribute("Persistent") == "1")
+      persistentNumbers.push_back(allNumbers[i]);
+  }
+  for(unsigned int i = 0; i < allStrings.size(); i++){
+    if(allStrings[i].getAttribute("Persistent") == "1")
+      persistentStrings.push_back(allStrings[i]);
+  }
+
+  // TODO FIXME: this will be removed once the new stable version of getdp is
+  // released
+  for(onelab::server::citer it = onelab::server::instance()->firstClient();
+      it != onelab::server::instance()->lastClient(); it++){
+    onelab::client *c = it->second;
+    std::vector<onelab::number> ps;
+    c->get(ps, c->getName() + "/UseCommandLine");
+    if(ps.size()) persistentNumbers.push_back(ps[0]);
+    c->get(ps, c->getName() + "/GuessModelName");
+    if(ps.size()) persistentNumbers.push_back(ps[0]);
+    std::vector<onelab::string> ps2;
+    c->get(ps2, c->getName() + "/FileExtension");
+    if(ps2.size()) persistentStrings.push_back(ps2[0]);
+  }
+  // END TODO
+
+  // clear the db
+  onelab::server::instance()->clear();
+
+  // run Gmsh client for non-python metamodels
+  if(runGmshClient && onelab::server::instance()->findClient("Gmsh") !=
+     onelab::server::instance()->lastClient())
+    onelabUtils::runGmshClient("reset", CTX::instance()->solver.autoMesh);
+
+  for(unsigned int i = 0; i < persistentNumbers.size(); i++){
+    Msg::Info("Restoring persistent parameter %s",
+              persistentNumbers[i].getName().c_str());
+    onelab::server::instance()->set(persistentNumbers[i]);
+  }
+  for(unsigned int i = 0; i < persistentStrings.size(); i++){
+    Msg::Info("Restoring persistent parameter %s",
+              persistentStrings[i].getName().c_str());
+    onelab::server::instance()->set(persistentStrings[i]);
+  }
+}
+
+void solver_batch_cb(void *data)
+{
+  int num = (intptr_t)data;
+  if(num < 0) return;
+  std::string name = opt_solver_name(num, GMSH_GET, "");
+  std::string exe = opt_solver_executable(num, GMSH_GET, "");
+  std::string host = opt_solver_remote_login(num, GMSH_GET, "");
+  if(exe.empty()){
+    Msg::Error("Solver executable name not provided");
+    return;
+  }
+
+  onelab::number n("0Metamodel/Batch", CTX::instance()->batch);
+  n.setVisible(false);
+  onelab::server::instance()->set(n);
+
+  // create client
+  onelab::localNetworkClient *c = new gmshLocalNetworkClient(name, exe, host);
+  c->setIndex(num);
+  onelab::string o(c->getName() + "/Action");
+
+  // initialize
+  onelabUtils::runGmshClient("initialize", CTX::instance()->solver.autoMesh);
+  o.setValue("initialize");
+  onelab::server::instance()->set(o);
+  c->run();
+
+  // load db
+  if(CTX::instance()->solver.autoSaveDatabase){
+    std::string db = SplitFileName(GModel::current()->getFileName())[0] + "onelab.db";
+    if(!StatFile(db)) loadDb(db);
+  }
+
+  // check
+  onelabUtils::runGmshClient("check", CTX::instance()->solver.autoMesh);
+  onelabUtils::guessModelName(c);
+  o.setValue("check");
+  onelab::server::instance()->set(o);
+  c->run();
+
+  // compute
+  initializeLoops();
+  do{
+    onelabUtils::runGmshClient("compute", CTX::instance()->solver.autoMesh);
+    onelabUtils::guessModelName(c);
+    o.setValue("compute");
+    onelab::server::instance()->set(o);
+    c->run();
+    onelab::server::instance()->setChanged(false, c->getName());
+  } while(incrementLoops());
+
+  if(CTX::instance()->solver.autoSaveDatabase ||
+     CTX::instance()->solver.autoArchiveOutputFiles){
+    std::string db = SplitFileName(GModel::current()->getFileName())[0] + "onelab.db";
+    if(CTX::instance()->solver.autoArchiveOutputFiles) archiveOutputFiles(db);
+    if(CTX::instance()->solver.autoSaveDatabase) saveDb(db);
+  }
+}
+
diff --git a/Fltk/gmshLocalNetworkClient.h b/Common/gmshLocalNetworkClient.h
similarity index 84%
rename from Fltk/gmshLocalNetworkClient.h
rename to Common/gmshLocalNetworkClient.h
index d8b56c77cb1cb971fa15f4eff2cbf6d5ce253347..76835f23fabdb907d7d4ca5cd81bac12d858bebc 100644
--- a/Fltk/gmshLocalNetworkClient.h
+++ b/Common/gmshLocalNetworkClient.h
@@ -69,4 +69,16 @@ class gmshLocalNetworkClient : public onelab::localNetworkClient{
 #endif
 };
 
+// FIXME: move this to onelabUtils
+void initializeLoops();
+bool incrementLoops();
+void updateGraphs();
+std::string timeStamp();
+void saveDb(const std::string &fileName);
+void archiveOutputFiles(const std::string &fileName);
+void archiveSolutionFiles(const std::string &fileName);
+void loadDb(const std::string &name);
+void resetDb(bool runGmshClient);
+void solver_batch_cb(void *data);
+
 #endif
diff --git a/Fltk/CMakeLists.txt b/Fltk/CMakeLists.txt
index 3469ee79bcac6bd44a91f92f3ece12e2406ef111..1a621a10d1807de4d75b42f716e0ce8a28c4ddc4 100644
--- a/Fltk/CMakeLists.txt
+++ b/Fltk/CMakeLists.txt
@@ -26,24 +26,21 @@ set(SRC
     projectionEditor.cpp
     classificationEditor.cpp
     partitionDialog.cpp
+    inputValue.cpp inputRegion.cpp
+    viewButton.cpp solverButton.cpp
+    Navigator.cpp
 )
 if(ENABLE_ONELAB2)
   set(SRC
     ${SRC}
     onelab2Group.cpp
   )
-else(ENALBE_ONELAB2)
+else(ENABLE_ONELAB2)
   set(SRC
     ${SRC}
     onelabGroup.cpp
   )
 endif(ENABLE_ONELAB2)
-set(SRC
-    ${SRC}
-    inputValue.cpp inputRegion.cpp
-    viewButton.cpp solverButton.cpp
-    Navigator.cpp
-)
 
 file(GLOB HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h) 
 append_gmsh_src(Fltk "${SRC};${HDR}")
diff --git a/Fltk/onelab2Group.cpp b/Fltk/onelab2Group.cpp
index b41d8c00ab61959b20663193c5b873cbcb7fa326..d61bf2b5af243ffec46b9d2a39a4998f42b98bcf 100644
--- a/Fltk/onelab2Group.cpp
+++ b/Fltk/onelab2Group.cpp
@@ -83,7 +83,7 @@ void onelab_cb(Fl_Widget *w, void *data)
     Msg::Info("I'm busy! Ask me that later...");
     return;
   }
-  
+
   if(action == "reset"){
     OnelabDatabase::instance()->clear(); // TODO keep persitant
     return;
@@ -151,20 +151,6 @@ void solver_cb(Fl_Widget *w, void *data)
   }
   FlGui::instance()->onelab->updateGearMenu();
 }
-void solver_batch_cb(Fl_Widget *w, void *data)
-{
-  int num = (intptr_t)data;
-  if(num >= 0) {
-    std::string name = opt_solver_name(num, GMSH_GET, "");
-    std::string exe = opt_solver_executable(num, GMSH_GET, "");
-    if(exe.empty()){
-      Msg::Error("Solver executable name not provided");
-      return;
-    }
-  }
-  Msg::Warning("solver_batch_cb TODO");
-  // TODO
-}
 
 static bool getFlColor(const std::string &str, Fl_Color &c)
 {
diff --git a/Fltk/onelab2Group.h b/Fltk/onelab2Group.h
index 69cf7690bf2518c195c386e067edf4cfdea41065..5a945860dd7895ea5acfeb22f847b1c72f503fd4 100644
--- a/Fltk/onelab2Group.h
+++ b/Fltk/onelab2Group.h
@@ -89,6 +89,6 @@ public:
 void connect_cb(Fl_Widget *w, void *arg);
 void onelab_cb(Fl_Widget *w, void *data);
 inline void onelab_cb(void *data) {onelab_cb(0, data);}
-void solver_cb(Fl_Widget *w, void *data);
-void solver_batch_cb(Fl_Widget *w, void *data);
+void solver_cb(void *data);
+
 #endif
diff --git a/Fltk/onelabGroup.cpp b/Fltk/onelabGroup.cpp
index a32f6468263f11981d9e7be7486240fe8956bd3d..b56f8aa72d158c8a50a03855e9a4d1e7d13539f2 100644
--- a/Fltk/onelabGroup.cpp
+++ b/Fltk/onelabGroup.cpp
@@ -45,765 +45,10 @@ typedef unsigned long intptr_t;
 #include "drawContext.h"
 #include "PView.h"
 
-#if defined(HAVE_ONELAB_METAMODEL)
-#include "OnelabClients.h"
-#include "metamodel.h"
-#endif
-
 // This file contains the Gmsh/FLTK specific parts of the ONELAB
 // interface. You'll need to reimplement this if you plan to build a different
 // ONELAB server.
 
-class onelabGmshServer : public GmshServer{
- private:
-  onelab::localNetworkClient *_client;
- public:
-  onelabGmshServer(onelab::localNetworkClient *client)
-    : GmshServer(), _client(client) {}
-  ~onelabGmshServer(){}
-  int NonBlockingSystemCall(const char *str)
-  {
-    return SystemCall(str);
-  }
-  int NonBlockingWait(double waitint, double timeout, int socket)
-  {
-    double start = GetTimeInSeconds();
-    while(1){
-      if(timeout > 0 && GetTimeInSeconds() - start > timeout)
-        return 2; // timeout
-      if(_client->getPid() < 0 || (_client->getExecutable().empty() &&
-                                   !CTX::instance()->solver.listen))
-        return 1; // process has been killed or we stopped listening
-      // check if there is data (call select with a zero timeout to
-      // return immediately, i.e., do polling)
-      int ret = Select(0, 0, socket);
-      if(ret == 0){ // nothing available
-        if(timeout < 0){
-          // if asked, refresh the onelab GUI, but no more than every 1/4th of
-          // a second
-          static double lastRefresh = 0.;
-          if(start - lastRefresh > 0.25){
-            std::vector<onelab::string> ps;
-            onelab::server::instance()->get(ps, "Gmsh/Action");
-            if(ps.size() && ps[0].getValue() == "refresh"){
-              ps[0].setVisible(false);
-              ps[0].setValue("");
-              onelab::server::instance()->set(ps[0]);
-              if(FlGui::available()) onelab_cb(0, (void*)"refresh");
-            }
-            lastRefresh = start;
-          }
-        }
-        // wait at most waitint seconds and respond to FLTK events
-        if(FlGui::available()) FlGui::instance()->wait(waitint);
-        // return to caller (we will be back here soon again)
-	if(timeout < 0) return 3;
-      }
-      else if(ret > 0){
-        return 0; // data is there!
-      }
-      else{
-        // an error happened
-        _client->setPid(-1);
-        return 1;
-      }
-    }
-  }
-  int LaunchClient()
-  {
-    std::string sockname;
-    std::ostringstream tmp;
-    const char *port = strstr(CTX::instance()->solver.socketName.c_str(), ":");
-    if(!port){
-      // Unix socket
-      tmp << CTX::instance()->homeDir << CTX::instance()->solver.socketName
-          << _client->getId();
-      sockname = FixWindowsPath(tmp.str());
-    }
-    else{
-      // TCP/IP socket
-      if(CTX::instance()->solver.socketName.size() &&
-         CTX::instance()->solver.socketName[0] == ':')
-        tmp << GetHostName(); // prepend hostname if only the port number is given
-      tmp << CTX::instance()->solver.socketName;
-      if(atoi(port + 1)) // nonzero port is given - append client id
-        tmp << _client->getId();
-      sockname = tmp.str();
-    }
-
-    std::string command = FixWindowsPath(_client->getExecutable());
-    if(command.size()){
-      std::vector<std::string> args = onelabUtils::getCommandLine(_client);
-      for(unsigned int i = 0; i < args.size(); i++)
-        command.append(" " + args[i]);
-      command.append(" " + _client->getSocketSwitch() +
-                     " \"" + _client->getName() + "\" %s");
-    }
-    else{
-      Msg::Info("Listening on socket '%s'", sockname.c_str());
-    }
-
-    int sock;
-    try{
-      sock = Start(command.c_str(), sockname.c_str(),
-                   CTX::instance()->solver.timeout);
-    }
-    catch(const char *err){
-      Msg::Error("Abnormal server termination (%s on socket %s)", err,
-                 sockname.c_str());
-      sock = -1;
-    }
-
-    return sock;
-  }
-};
-
-bool gmshLocalNetworkClient::receiveMessage(gmshLocalNetworkClient *master)
-{
-  // receive a message on the associated GmshServer; 'master' is only used when
-  // creating subclients with GMSH_CONNECT.
-
-  double timer = GetTimeInSeconds();
-
-  if(!getGmshServer()){
-    Msg::Error("Abnormal server termination (no valid server)");
-    return false;
-  }
-
-  int type, length, swap;
-  if(!getGmshServer()->ReceiveHeader(&type, &length, &swap)){
-    Msg::Error("Abnormal server termination (did not receive message header)");
-    return false;
-  }
-
-  std::string message(length, ' '), blank = message;
-  if(!getGmshServer()->ReceiveMessage(length, &message[0])){
-    Msg::Error("Abnormal server termination (did not receive message body)");
-    return false;
-  }
-
-  if(message == blank && !(type == GmshSocket::GMSH_PROGRESS ||
-                           type == GmshSocket::GMSH_INFO ||
-                           type == GmshSocket::GMSH_WARNING ||
-                           type == GmshSocket::GMSH_ERROR)){
-    // we should still allow blank msg strings to be sent
-    Msg::Error("Abnormal server termination (blank message: client not stopped?)");
-    return false;
-  }
-
-  switch (type) {
-  case GmshSocket::GMSH_START:
-    setPid(atoi(message.c_str()));
-    break;
-  case GmshSocket::GMSH_STOP:
-    setPid(-1);
-    if(getFather()){
-      std::string reply = getName(); // reply is dummy
-      getFather()->getGmshServer()->SendMessage
-        (GmshSocket::GMSH_STOP, reply.size(), &reply[0]);
-    }
-    break;
-  case GmshSocket::GMSH_PARAMETER:
-  case GmshSocket::GMSH_PARAMETER_UPDATE:
-    {
-      std::string version, ptype, name;
-      onelab::parameter::getInfoFromChar(message, version, ptype, name);
-      if(onelab::parameter::version() != version){
-        Msg::Error("ONELAB version mismatch (server: %s / client: %s)",
-                   onelab::parameter::version().c_str(), version.c_str());
-      }
-      else if(ptype == "number"){
-        onelab::number p; p.fromChar(message);
-        if(type == GmshSocket::GMSH_PARAMETER_UPDATE){
-          std::vector<onelab::number> par; get(par, name);
-          if(par.size()) {
-            onelab::number y = p; p = par[0]; onelabUtils::updateNumber(p, y);
-          }
-        }
-        set(p);
-        if(p.getName() == getName() + "/Progress")
-          if(FlGui::available())
-            FlGui::instance()->setProgress(p.getLabel().c_str(), p.getValue(),
-                                           p.getMin(), p.getMax());
-      }
-      else if(ptype == "string"){
-        onelab::string p; p.fromChar(message);
-        if(type == GmshSocket::GMSH_PARAMETER_UPDATE){
-          std::vector<onelab::string> par; get(par, name);
-          if(par.size()){
-            onelab::string y = p; p = par[0]; onelabUtils::updateString(p,y);
-          }
-	}
-        set(p);
-      }
-      else if(ptype == "region"){
-        onelab::region p; p.fromChar(message); set(p);
-      }
-      else if(ptype == "function"){
-        onelab::function p; p.fromChar(message); set(p);
-      }
-      else
-        Msg::Error("Unknown ONELAB parameter type: %s", ptype.c_str());
-    }
-    break;
-  case GmshSocket::GMSH_PARAMETER_QUERY:
-    {
-      std::string version, ptype, name, reply;
-      onelab::parameter::getInfoFromChar(message, version, ptype, name);
-      if(onelab::parameter::version() != version){
-        Msg::Error("ONELAB version mismatch (server: %s / client: %s)",
-                   onelab::parameter::version().c_str(), version.c_str());
-      }
-      else if(ptype == "number"){
-        std::vector<onelab::number> par; get(par, name);
-        if(par.size() == 1) reply = par[0].toChar();
-      }
-      else if(ptype == "string"){
-        std::vector<onelab::string> par; get(par, name);
-        if(par.size() == 1) reply = par[0].toChar();
-      }
-      else if(ptype == "region"){
-        std::vector<onelab::region> par; get(par, name);
-        if(par.size() == 1) reply = par[0].toChar();
-      }
-      else if(ptype == "function"){
-        std::vector<onelab::function> par; get(par, name);
-        if(par.size() == 1) reply = par[0].toChar();
-      }
-      else
-        Msg::Error("Unknown ONELAB parameter type in query: %s", ptype.c_str());
-
-      if(reply.size()){
-        getGmshServer()->SendMessage
-          (GmshSocket::GMSH_PARAMETER, reply.size(), &reply[0]);
-      }
-      else{
-        reply = name;
-        getGmshServer()->SendMessage
-          (GmshSocket::GMSH_PARAMETER_NOT_FOUND, reply.size(), &reply[0]);
-      }
-    }
-    break;
-  case GmshSocket::GMSH_PARAMETER_QUERY_ALL:
-    {
-      std::string version, ptype, name, reply;
-      std::vector<std::string> replies;
-      onelab::parameter::getInfoFromChar(message, version, ptype, name);
-      if(onelab::parameter::version() != version){
-        Msg::Error("ONELAB version mismatch (server: %s / client: %s)",
-                   onelab::parameter::version().c_str(), version.c_str());
-      }
-      else if(ptype == "number"){
-        std::vector<onelab::number> numbers; get(numbers);
-        for(std::vector<onelab::number>::iterator it = numbers.begin();
-            it != numbers.end(); it++) replies.push_back((*it).toChar());
-      }
-      else if(ptype == "string"){
-        std::vector<onelab::string> strings; get(strings);
-        for(std::vector<onelab::string>::iterator it = strings.begin();
-            it != strings.end(); it++) replies.push_back((*it).toChar());
-      }
-      else if(ptype == "region"){
-        std::vector<onelab::region> regions; get(regions);
-        for(std::vector<onelab::region>::iterator it = regions.begin();
-            it != regions.end(); it++) replies.push_back((*it).toChar());
-      }
-      else if(ptype == "function"){
-        std::vector<onelab::function> functions; get(functions);
-        for(std::vector<onelab::function>::iterator it = functions.begin();
-            it != functions.end(); it++) replies.push_back((*it).toChar());
-      }
-      else
-        Msg::Error("Unknown ONELAB parameter type in query: %s", ptype.c_str());
-
-      for(unsigned int i = 0; i < replies.size(); i++)
-        getGmshServer()->SendMessage
-          (GmshSocket::GMSH_PARAMETER_QUERY_ALL, replies[i].size(), &replies[i][0]);
-      reply = "Sent all ONELAB " + ptype + "s";
-      getGmshServer()->SendMessage
-        (GmshSocket::GMSH_PARAMETER_QUERY_END, reply.size(), &reply[0]);
-    }
-    break;
-  case GmshSocket::GMSH_PARAMETER_CLEAR:
-    clear(message == "*" ? "" : message);
-    break;
-  case GmshSocket::GMSH_PROGRESS:
-    Msg::StatusBar(false, "%s %s", _name.c_str(), message.c_str());
-    break;
-  case GmshSocket::GMSH_INFO:
-    Msg::Direct("Info    : %s - %s", _name.c_str(), message.c_str());
-    break;
-  case GmshSocket::GMSH_WARNING:
-    Msg::Warning("%s - %s", _name.c_str(), message.c_str());
-    break;
-  case GmshSocket::GMSH_ERROR:
-    Msg::Error("%s - %s", _name.c_str(), message.c_str());
-    break;
-  case GmshSocket::GMSH_MERGE_FILE:
-    if(CTX::instance()->solver.autoMergeFile){
-      unsigned int n = PView::list.size();
-      MergePostProcessingFile(message, CTX::instance()->solver.autoShowViews,
-                              CTX::instance()->solver.autoShowLastStep, true);
-      drawContext::global()->draw();
-      if(FlGui::available() && n != PView::list.size()){
-        FlGui::instance()->rebuildTree(true);
-        FlGui::instance()->openModule("Post-processing");
-      }
-    }
-    break;
-  case GmshSocket::GMSH_OPEN_PROJECT:
-    OpenProject(message);
-    drawContext::global()->draw();
-    break;
-  case GmshSocket::GMSH_PARSE_STRING:
-    ParseString(message, true);
-    drawContext::global()->draw();
-    break;
-  case GmshSocket::GMSH_SPEED_TEST:
-    Msg::Info("got %d Mb message in %g seconds",
-              length / 1024 / 1024, GetTimeInSeconds() - timer);
-    break;
-  case GmshSocket::GMSH_VERTEX_ARRAY:
-    {
-      int n = PView::list.size();
-      PView::fillVertexArray(this, length, &message[0], swap);
-      if(FlGui::available())
-        FlGui::instance()->updateViews(n != (int)PView::list.size(), true);
-      drawContext::global()->draw();
-    }
-    break;
-  case GmshSocket::GMSH_CONNECT:
-    {
-      std::string::size_type first = 0;
-      std::string clientName = onelab::parameter::getNextToken(message, first);
-      std::string command = onelab::parameter::getNextToken(message, first);
-      if (!onelab::server::instance()->isRegistered(clientName)){
-	gmshLocalNetworkClient* subClient =
-	  new gmshLocalNetworkClient(clientName, command);
-	onelabGmshServer *server = new onelabGmshServer(subClient);
-	subClient->setPid(0);
-	int sock = server->LaunchClient();
-	if(sock < 0){ // could not establish the connection: aborting
-	  server->Shutdown();
-	  delete server;
-	  Msg::Error("Could not connect client '%s'", subClient->getName().c_str());
-	}
-	else{
-	  Msg::StatusBar(true, "Running '%s'...", subClient->getName().c_str());
-	  subClient->setGmshServer(server);
-	  subClient->setFather(this);
-	  master->addClient(subClient);
-	}
-      }
-      else{
-	std::string reply = "";
-	for(onelab::server::citer it = onelab::server::instance()->firstClient();
-	    it != onelab::server::instance()->lastClient(); it++){
-	  reply.append(it->second->getName() + " ");
-	}
-	Msg::Error("Skipping already existing client <%s> - Registered clients are < %s>",clientName.c_str(),reply.c_str());
-	getGmshServer()->SendMessage
-	  (GmshSocket::GMSH_STOP, reply.size(), &reply[0]); // reply is dummy
-      }
-    }
-    break;
-  case GmshSocket::GMSH_OLPARSE:
-    {
-      std::string reply = "unavailable";
-#if defined(HAVE_ONELAB_METAMODEL)
-      std::string::size_type first = 0;
-      std::string clientName = onelab::parameter::getNextToken(message, first);
-      std::string fullName = onelab::parameter::getNextToken(message, first);
-      if (!onelab::server::instance()->isRegistered(clientName)){
-	preProcess(clientName, fullName); // contrib/onelab/OnelabParser.cpp
-	Msg::Info("Preprocess file <%s> done", fullName.c_str());
-	reply = onelab::server::instance()->getChanged(clientName) ? "true" : "false";
-      }
-      else{
-	Msg::Error("Skipping client with already existing name <%s>",clientName.c_str());
-      }
-#endif
-      getGmshServer()->SendMessage
-	(GmshSocket::GMSH_OLPARSE, reply.size(), &reply[0]);
-    }
-    break;
-  case GmshSocket::GMSH_CLIENT_CHANGED:
-    {
-      std::string::size_type first = 0;
-      std::string command = onelab::parameter::getNextToken(message, first);
-      std::string name = onelab::parameter::getNextToken(message, first);
-      if(command == "get"){
-	std::string reply = onelab::server::instance()->getChanged(name) ? "true" : "false";
-	getGmshServer()->SendMessage
-	  (GmshSocket::GMSH_CLIENT_CHANGED, reply.size(), &reply[0]);
-      }
-      else if(command == "set"){
-	std::string changed = onelab::parameter::getNextToken(message, first);
-	onelab::server::instance()->setChanged(changed=="true"?true:false,name);
-      }
-    }
-    break;
-  default:
-    Msg::Warning("Received unknown message type (%d)", type);
-    break;
-  }
-
-  return true;
-}
-
-bool gmshLocalNetworkClient::run()
-{
- new_connection:
-  setPid(0); // dummy pid, should be non-negative
-
-  onelabGmshServer *server = new onelabGmshServer(this);
-
-  int sock = server->LaunchClient();
-
-  if(sock < 0){
-    // could not establish the connection: aborting
-    server->Shutdown();
-    delete server;
-    return false;
-  }
-
-  Msg::StatusBar(true, "Running '%s'...", _name.c_str());
-
-  setGmshServer(server);
-
-  while(1) {
-    if(getExecutable().empty() && !CTX::instance()->solver.listen){
-      // we stopped listening to the special "Listen" client
-      break;
-    }
-
-    // loop over all the clients (usually only one, but can be more if we
-    // spawned subclients) and check if data is available for one of them
-    bool stop = false, haveData = false;
-    gmshLocalNetworkClient *c = 0;
-    std::vector<gmshLocalNetworkClient*> toDelete;
-    for(int i = 0; i < getNumClients(); i++){
-      c = getClient(i);
-      if(c->getPid() < 0){
-        if(c == this){ // the "master" client stopped
-          stop = true;
-          break;
-        }
-        else{
-          // this subclient is not active anymore: shut down and delete its
-          // server and mark the client for deletion
-          GmshServer *s = c->getGmshServer();
-          c->setGmshServer(0);
-          c->setFather(0);
-          if(s){
-            s->Shutdown();
-            delete s;
-          }
-          toDelete.push_back(c);
-          continue;
-        }
-      }
-      GmshServer *s = c->getGmshServer();
-      if(!s){
-        Msg::Error("Abnormal server termination (no valid server)");
-        stop = true;
-        break;
-      }
-      else{
-        int ret = s->NonBlockingWait(0.001, -1.);
-        if(ret == 0){ // we have data from this particular client
-          haveData = true;
-          break;
-        }
-        else if(ret == 3){ // pass to the next client
-          continue;
-        }
-        else{ // an error occurred
-          stop = true;
-          break;
-        }
-      }
-    }
-    for(unsigned int i = 0; i < toDelete.size(); i++){
-      removeClient(toDelete[i]);
-      delete toDelete[i];
-    }
-
-    // break the while(1) if the master client has stopped or if we encountered
-    // a problem
-    if(stop) break;
-
-    // if data is available try to get the message from the corresponding
-    // client; break the while(1) if we could not receive the message
-    if(haveData && !c->receiveMessage(this)) break;
-
-    // break the while(1) if the master client has stopped
-    if(c == this && c->getPid() < 0) break;
-  }
-
-  // we are done running the (master) client: delete the servers and the
-  // subclients, if any remain (they should have been deleted already).
-  std::vector<gmshLocalNetworkClient*> toDelete;
-  for(int i = 0; i < getNumClients(); i++){
-    gmshLocalNetworkClient *c = getClient(i);
-    GmshServer *s = c->getGmshServer();
-    c->setGmshServer(0);
-    c->setFather(0);
-    if(s){
-      s->Shutdown();
-      delete s;
-    }
-    if(c != this){
-      if(c->getPid() > 0)
-        Msg::Error("Subclient %s was not stopped correctly", c->getName().c_str());
-      toDelete.push_back(c);
-    }
-  }
-  for(unsigned int i = 0; i < toDelete.size(); i++){
-    removeClient(toDelete[i]);
-    delete toDelete[i];
-  }
-
-  Msg::StatusBar(true, "Done running '%s'", _name.c_str());
-
-  if(getExecutable().empty()){
-    Msg::Info("Client disconnected: starting new connection");
-    goto new_connection;
-  }
-
-  return true;
-}
-
-bool gmshLocalNetworkClient::kill()
-{
-  // FIXME: we should kill all the clients in the list
-  if(getPid() > 0) {
-    if(KillProcess(getPid())){
-      Msg::Info("Killed '%s' (pid %d)", _name.c_str(), getPid());
-      if(FlGui::available())
-        FlGui::instance()->setProgress("Killed", 0, 0, 0);
-      setPid(-1);
-      return true;
-    }
-  }
-  setPid(-1);
-  return false;
-}
-
-static void initializeLoops()
-{
-  onelabUtils::initializeLoop("1");
-  onelabUtils::initializeLoop("2");
-  onelabUtils::initializeLoop("3");
-
-  if(FlGui::available() && onelab::server::instance()->getChanged())
-    FlGui::instance()->rebuildTree(false);
-}
-
-static bool incrementLoops()
-{
-  bool ret = false;
-  if(onelabUtils::incrementLoop("3"))      ret = true;
-  else if(onelabUtils::incrementLoop("2")) ret = true;
-  else if(onelabUtils::incrementLoop("1")) ret = true;
-
-  //Define ONELAB parameter indicating whether or not in a loop
-  onelab::number n("0Metamodel/Loop",ret?1:0);
-  n.setVisible(false);
-  onelab::server::instance()->set(n);
-
-  if(FlGui::available() && onelab::server::instance()->getChanged())
-    FlGui::instance()->rebuildTree(false);
-
-  return ret;
-}
-
-static void updateGraphs()
-{
-  bool redraw = false;
-  for(int i = 0; i < 18; i++){
-    std::ostringstream tmp;
-    tmp << i;
-    bool ret = onelabUtils::updateGraph(tmp.str());
-    redraw = redraw || ret;
-  }
-  if(redraw){
-    // don't delete the widgets, as this is called in widget callbacks
-    FlGui::instance()->updateViews(true, false);
-    drawContext::global()->draw();
-  }
-}
-
-static std::string timeStamp()
-{
-  time_t now;
-  time(&now);
-  tm *t = localtime(&now);
-  char stamp[32];
-  // stamp.size() is always 20
-  sprintf(stamp, "_%04d-%02d-%02d_%02d-%02d-%02d", 1900 + t->tm_year,
-          1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
-  return std::string(stamp);
-}
-
-static void saveDb(const std::string &fileName)
-{
-  FILE *fp = Fopen(fileName.c_str(), "wb");
-  if(fp){
-    Msg::StatusBar(true, "Saving database '%s'...", fileName.c_str());
-    onelab::server::instance()->toFile(fp);
-    fclose(fp);
-    Msg::StatusBar(true, "Done saving database '%s'", fileName.c_str());
-  }
-  else
-    Msg::Error("Could not save database '%s'", fileName.c_str());
-}
-
-static void archiveOutputFiles(const std::string &fileName)
-{
-  std::string stamp;
-  std::vector<onelab::string> ps;
-  onelab::server::instance()->get(ps,"0Metamodel/9Tag");
-  if(ps.size() && ps[0].getValue().size())
-    stamp.assign(timeStamp() + "_" + ps[0].getValue());
-  else
-    stamp.assign(timeStamp());
-
-  // add time stamp in all output files in the db, and rename them on disk
-  std::vector<onelab::string> strings;
-  onelab::server::instance()->get(strings);
-  for(unsigned int i = 0; i < strings.size(); i++){
-    if(strings[i].getName().find("9Output files") != std::string::npos){
-      std::vector<std::string> names = strings[i].getChoices();
-      names.push_back(strings[i].getValue());
-      for(unsigned int j = 0; j < names.size(); j++){
-        std::vector<std::string> split = SplitFileName(names[j]);
-        int n = split[1].size();
-        // if name is not already stamped
-        if(n < 18 || split[1][n-3] != '-' || split[1][n-6] != '-' ||
-           split[1][n-9] != '_'){
-          std::string old = names[j];
-          CreateSingleDir(split[0] + "archive/");
-          names[j] = split[0] + "archive/" + split[1] + stamp + split[2];
-          Msg::Info("Renaming '%s' into '%s'", old.c_str(), names[j].c_str());
-          rename(old.c_str(), names[j].c_str());
-        }
-      }
-      strings[i].setValue(names.back());
-      names.pop_back();
-      strings[i].setChoices(names);
-      onelab::server::instance()->set(strings[i]);
-    }
-  }
-
-  // save stamped db
-  {
-    std::vector<std::string> split = SplitFileName(fileName);
-    CreateSingleDir(split[0] + "archive/");
-    saveDb(split[0] + "archive/" + split[1] + stamp + split[2]);
-  }
-
-  FlGui::instance()->rebuildTree(true);
-}
-
-static void archiveSolutionFiles(const std::string &fileName)
-{
-  // extract tag from db fileName, use fileName as tag otherwise
-  std::vector<std::string> split = SplitFileName(fileName);
-  std::string dir = split[0] + "archive/";
-  std::string tag = split[1];
-  if (!tag.compare(0,6,"onelab"))
-    tag.assign(tag.substr(6)); // cut off 'onelab' if present
-
-  // add tag to all solution files in the db, and rename them on disk
-  std::vector<onelab::string> strings;
-  onelab::server::instance()->get(strings,"0Metamodel/9Solution files");
-  if(strings.size()){
-    std::vector<std::string> names = strings[0].getChoices();
-    if(names.size()){
-      for(unsigned int j = 0; j < names.size(); j++){
-	std::vector<std::string> split = SplitFileName(names[j]);
-	std::string old = names[j];
-	CreateSingleDir(dir);
-	names[j] = dir + split[1] + tag + split[2];
-	Msg::Info("Renaming '%s' into '%s'", old.c_str(), names[j].c_str());
-	rename(old.c_str(), names[j].c_str());
-      }
-      strings[0].setValue(names[0]);
-      strings[0].setChoices(names);
-      onelab::server::instance()->set(strings[0]);
-      FlGui::instance()->rebuildTree(true);
-    }
-  }
-}
-
-static void loadDb(const std::string &name)
-{
-  Msg::StatusBar(true, "Loading database '%s'...", name.c_str());
-  FILE *fp = Fopen(name.c_str(), "rb");
-  if(fp){
-    onelab::server::instance()->fromFile(fp);
-    fclose(fp);
-    Msg::StatusBar(true, "Done loading database '%s'", name.c_str());
-  }
-  else
-    Msg::Error("Could not load database '%s'", name.c_str());
-}
-
-static void resetDb(bool runGmshClient)
-{
-  Msg::Info("Resetting database");
-
-  // clear everything except persistent parameters
-  std::vector<onelab::number> allNumbers, persistentNumbers;
-  std::vector<onelab::string> allStrings, persistentStrings;
-  onelab::server::instance()->get(allNumbers);
-  onelab::server::instance()->get(allStrings);
-  for(unsigned int i = 0; i < allNumbers.size(); i++){
-    if(allNumbers[i].getAttribute("Persistent") == "1")
-      persistentNumbers.push_back(allNumbers[i]);
-  }
-  for(unsigned int i = 0; i < allStrings.size(); i++){
-    if(allStrings[i].getAttribute("Persistent") == "1")
-      persistentStrings.push_back(allStrings[i]);
-  }
-
-  // TODO FIXME: this will be removed once the new stable version of getdp is
-  // released
-  for(onelab::server::citer it = onelab::server::instance()->firstClient();
-      it != onelab::server::instance()->lastClient(); it++){
-    onelab::client *c = it->second;
-    std::vector<onelab::number> ps;
-    c->get(ps, c->getName() + "/UseCommandLine");
-    if(ps.size()) persistentNumbers.push_back(ps[0]);
-    c->get(ps, c->getName() + "/GuessModelName");
-    if(ps.size()) persistentNumbers.push_back(ps[0]);
-    std::vector<onelab::string> ps2;
-    c->get(ps2, c->getName() + "/FileExtension");
-    if(ps2.size()) persistentStrings.push_back(ps2[0]);
-  }
-  // END TODO
-
-  // clear the db
-  onelab::server::instance()->clear();
-
-  // run Gmsh client for non-python metamodels
-  if(runGmshClient && onelab::server::instance()->findClient("Gmsh") !=
-     onelab::server::instance()->lastClient())
-    onelabUtils::runGmshClient("reset", CTX::instance()->solver.autoMesh);
-
-  for(unsigned int i = 0; i < persistentNumbers.size(); i++){
-    Msg::Info("Restoring persistent parameter %s",
-              persistentNumbers[i].getName().c_str());
-    onelab::server::instance()->set(persistentNumbers[i]);
-  }
-  for(unsigned int i = 0; i < persistentStrings.size(); i++){
-    Msg::Info("Restoring persistent parameter %s",
-              persistentStrings[i].getName().c_str());
-    onelab::server::instance()->set(persistentStrings[i]);
-  }
-}
-
 void onelab_cb(Fl_Widget *w, void *data)
 {
   if(!data) return;
@@ -860,7 +105,7 @@ void onelab_cb(Fl_Widget *w, void *data)
     onelab::server::instance()->get(pn,"0Metamodel/9Use restored solution");
     if(pn.size()){
       restoreMode=pn[0].getValue();
-      pn[0].setValue(2); // special value 
+      pn[0].setValue(2); // special value
       onelab::server::instance()->set(pn[0]);
     }
 
@@ -2121,65 +1366,6 @@ void solver_cb(Fl_Widget *w, void *data)
   CTX::instance()->launchSolverAtStartup = -1;
 }
 
-void solver_batch_cb(Fl_Widget *w, void *data)
-{
-  int num = (intptr_t)data;
-  if(num < 0) return;
-  std::string name = opt_solver_name(num, GMSH_GET, "");
-  std::string exe = opt_solver_executable(num, GMSH_GET, "");
-  std::string host = opt_solver_remote_login(num, GMSH_GET, "");
-  if(exe.empty()){
-    Msg::Error("Solver executable name not provided");
-    return;
-  }
-
-  onelab::number n("0Metamodel/Batch", CTX::instance()->batch);
-  n.setVisible(false);
-  onelab::server::instance()->set(n);
-
-  // create client
-  onelab::localNetworkClient *c = new gmshLocalNetworkClient(name, exe, host);
-  c->setIndex(num);
-  onelab::string o(c->getName() + "/Action");
-
-  // initialize
-  onelabUtils::runGmshClient("initialize", CTX::instance()->solver.autoMesh);
-  o.setValue("initialize");
-  onelab::server::instance()->set(o);
-  c->run();
-
-  // load db
-  if(CTX::instance()->solver.autoSaveDatabase){
-    std::string db = SplitFileName(GModel::current()->getFileName())[0] + "onelab.db";
-    if(!StatFile(db)) loadDb(db);
-  }
-
-  // check
-  onelabUtils::runGmshClient("check", CTX::instance()->solver.autoMesh);
-  onelabUtils::guessModelName(c);
-  o.setValue("check");
-  onelab::server::instance()->set(o);
-  c->run();
-
-  // compute
-  initializeLoops();
-  do{
-    onelabUtils::runGmshClient("compute", CTX::instance()->solver.autoMesh);
-    onelabUtils::guessModelName(c);
-    o.setValue("compute");
-    onelab::server::instance()->set(o);
-    c->run();
-    onelab::server::instance()->setChanged(false, c->getName());
-  } while(incrementLoops());
-
-  if(CTX::instance()->solver.autoSaveDatabase ||
-     CTX::instance()->solver.autoArchiveOutputFiles){
-    std::string db = SplitFileName(GModel::current()->getFileName())[0] + "onelab.db";
-    if(CTX::instance()->solver.autoArchiveOutputFiles) archiveOutputFiles(db);
-    if(CTX::instance()->solver.autoSaveDatabase) saveDb(db);
-  }
-}
-
 void flgui_wait_cb(double time)
 {
   FlGui::instance()->wait(time);