Index: /trunk/FACT++/src/DimServerList.cc
===================================================================
--- /trunk/FACT++/src/DimServerList.cc	(revision 10378)
+++ /trunk/FACT++/src/DimServerList.cc	(revision 10378)
@@ -0,0 +1,127 @@
+// **************************************************************************
+/** @class DimServerList
+
+@brief Maintains a list of all servers based on DIS_DNS/SERVER_LIST
+
+This class describes to the service DIS_DNS/SERVER_LIST of the name server.
+Thus it always contains an up-to-date list of all servers connected
+to the dns server.
+
+Whenever a server is added or removed, or all servers are removed from the
+#list (the dns itself went offline), the follwoing virtual functions are
+called:
+
+- virtual void AddServer(const std::string &)
+- virtual void RemoveServer(const std::string &)
+- virtual void RemoveAllServers()
+
+If overwritten the implementations of the base class doesn't need to be
+called, because it's empty.
+
+*/
+// **************************************************************************
+#include "DimServerList.h"
+
+#include <sstream>
+#include <algorithm>
+#include <stdexcept>
+
+using namespace std;
+
+// --------------------------------------------------------------------------
+//
+//! Constructs the DimServerList. Subscribes a DimInfo to
+//! DIS_DNS/SERVER_LIST.
+//
+DimServerList::DimServerList() :
+    fDimServers("DIS_DNS/SERVER_LIST", const_cast<char*>(""), this)
+{
+}
+
+// --------------------------------------------------------------------------
+//
+//! Whenever the service with the server list is updated this functions
+//! changes the contents of the list and calls RemoveAllServers(),
+//! RemoveServer() and AddServer() where appropriate.
+//
+void DimServerList::infoHandler()
+{
+    if (getInfo()!=&fDimServers)
+        return;
+
+    // Get the received string from the handler
+    const string str = fDimServers.getString();
+
+    // Check if it starts with + or -
+    if (str[0]!='-' && str[0]!='+')
+    {
+        RemoveAllServers();
+        fServerList.clear();
+    }
+
+    // Create a stringstream to tokenize the received string
+    stringstream stream(str);
+
+    // Loop over the seperating tokens
+    string buffer;
+    while (getline(stream, buffer, '|'))
+    {
+        // The first part before the first @ is the server name
+        const string server = buffer.substr(0, buffer.find_first_of('@'));
+        if (server.empty())
+            continue;
+
+        // If it starts with a - we have to remove an entry
+        if (server[0]=='-')
+        {
+            const string trunc = server.substr(1);
+
+            // Check if this server is not found in the list.
+            // This should never happen if Dim works reliable
+            const ServerList::iterator v = find(fServerList.begin(), fServerList.end(), trunc);
+            if (v==fServerList.end())
+            {
+                stringstream err;
+                err << "Server '" << trunc << "' not in list as it ought to be.";
+                throw runtime_error(err.str());
+            }
+
+            RemoveServer(trunc);
+            fServerList.erase(v);
+
+            continue;
+        }
+
+        // If it starts with a + we have to add an entry
+        if (server[0]=='+')
+        {
+            const string trunc = server.substr(1);
+
+            // Check if this server is already in the list.
+            // This should never happen if Dim works reliable
+            const ServerList::iterator v = find(fServerList.begin(), fServerList.end(), trunc);
+            if (v!=fServerList.end())
+            {
+                stringstream err;
+                err << "Server '" << trunc << "' in list not as it ought to be.";
+                throw runtime_error(err.str());
+            }
+
+            fServerList.push_back(trunc);
+            AddServer(trunc);
+
+            continue;
+        }
+
+        // In any other case we just add the entry to the list
+        fServerList.push_back(server);
+        AddServer(server);
+    }
+}
+
+// --------------------------------------------------------------------------
+//
+bool DimServerList::HasServer(const std::string &server) const
+{
+    return find(fServerList.begin(), fServerList.end(), server)!=fServerList.end();
+}
Index: /trunk/FACT++/src/DimServerList.h
===================================================================
--- /trunk/FACT++/src/DimServerList.h	(revision 10378)
+++ /trunk/FACT++/src/DimServerList.h	(revision 10378)
@@ -0,0 +1,36 @@
+#ifndef FACT_DimServerList
+#define FACT_DimServerList
+
+#include <vector>
+#include <string>
+
+#include "dic.hxx"
+
+class DimServerList : public DimClient
+{
+public:
+    typedef std::vector<std::string> ServerList;
+
+private:
+    DimInfo    fDimServers;  /// A DimInfo to retrieve the SERVER_LIST from teh DNS server
+    ServerList fServerList;  /// A list with the available servers
+
+    virtual void AddServer(const std::string &) { };
+    virtual void RemoveServer(const std::string &) { };
+    virtual void RemoveAllServers() { };
+
+protected:
+    void infoHandler();
+
+public:
+    DimServerList();
+
+    /// @returns a reference to the list of servers
+    const ServerList &GetServerList() const { return fServerList; }
+
+    /// @returns whether the given server is in the list or not
+    /// @param server string with the server which availability should be checked
+    bool HasServer(const std::string &server) const;
+};
+
+#endif
Index: /trunk/FACT++/src/DimServiceInfoList.cc
===================================================================
--- /trunk/FACT++/src/DimServiceInfoList.cc	(revision 10378)
+++ /trunk/FACT++/src/DimServiceInfoList.cc	(revision 10378)
@@ -0,0 +1,729 @@
+// **************************************************************************
+/** @class DimServiceInfoList
+
+@brief Maintains a list of all services available in the Dim network
+
+The idea of this class is to maintain a list of services available
+in the Dim network as well as state descriptions if available.
+
+Therefore, it subscribes to the SERVICE_LIST, SERVICE_DESC and STATE_LIST
+services of all servers.
+
+To maintain the list it derives from DimServerList which maintains
+a list of all servers.
+
+To maintain the subscriptions it overwrites:
+
+- void DimServerList::AddServer(const std::string &s)
+- void DimServerList::RemoveServer(const std::string &s)
+- void DimServerList::RemoveAllServers()
+
+If a derived class also overwrites these functions it must be ensured that
+the member functions of DimServiceInfoList are still called properly.
+
+Whenever a service is added or removed, or all services of one server
+is removed the following virtual functions are called:
+
+- virtual void AddService(const std::string &server, const std::string &service, const std::string &fmt, bool iscmd)
+- virtual void RemoveService(const std::string &server, const std::string &service, bool iscmd)
+- virtual void RemoveAllServices(const std::string &server)
+
+Note, that these functions are not called from the RemoveServer() and
+RemoveAllServer() functions. It might be a difference whether all services
+were removed but the server is still online or the server went offline.
+
+If a description or a state was added, this is signaled though:
+
+- virtual void AddDescription(const std::string &server, const std::string &service, const std::vector<Description> &vec)
+- virtual void AddStates(const std::string &server, const std::vector<State> &vec)
+
+Note, that Descriptions and States are never removed except a service or
+server goes offline. It is expected that if a service comes online also
+the list of descritions is sent again.
+
+*/
+// **************************************************************************
+#include "DimServiceInfoList.h"
+
+#include <sstream>
+
+#include "WindowLog.h"
+#include "Converter.h"
+
+#include "tools.h"
+#include "Time.h"
+
+using namespace std;
+
+// --------------------------------------------------------------------------
+//
+//! A helper to shorten the call to create a DimInfo.
+//!
+//! @param str
+//!    name of the server to which we want to subscribe
+//!
+//! @param svc
+//!    name of the servic on the server to which we want to subscribe
+//!
+//! @returns
+//!    a pointer to the newly created DimInfo
+//!
+DimInfo *DimServiceInfoList::CreateDimInfo(const string &str, const string &svc) const
+{
+    return new DimInfo((str+'/'+svc).c_str(),
+                       const_cast<char*>(""),
+                       const_cast<DimServiceInfoList*>(this));
+}
+
+// --------------------------------------------------------------------------
+//
+//! Adds the service subscription for SERVICE_LIST, SERVICE_DESC and
+//! STATE_LIST for the given server. Don't forget to call this function
+//! if it is overwritten in a derived class.
+//!
+//! @throws
+//!     a runtime_error is the server is already in the list
+//
+void DimServiceInfoList::AddServer(const string &s)
+{
+    // Check if this server is already in the list.
+    // This should never happen if Dim works reliable
+    const ServiceInfoList::iterator v = fServiceInfoList.find(s);
+    if (v!=fServiceInfoList.end())
+    {
+        stringstream err;
+        err << "Server '" << s << "' in list not as it ought to be.";
+        throw runtime_error(err.str());
+    }
+
+    fServiceInfoList[s].push_back(CreateSL(s));
+    fServiceInfoList[s].push_back(CreateFMT(s));
+    fServiceInfoList[s].push_back(CreateDS(s));
+}
+
+// --------------------------------------------------------------------------
+//
+//! Removes the service subscription for SERVICE_LIST, SERVICE_DESC and
+//! STATE_LIST for the given server, as well as the stored informations.
+//! Don't forget to call this function if it is overwritten in a derived
+//! class.
+//!
+//! @throws
+//!     a runtime_error is the server to be removed is not in the list
+//
+void DimServiceInfoList::RemoveServer(const string &s)
+{
+    const ServiceInfoList::iterator v = fServiceInfoList.find(s);
+    if (v==fServiceInfoList.end())
+    {
+        stringstream err;
+        err << "Server '" << s << "' not in list as it ought to be.";
+        throw runtime_error(err.str());
+    }
+
+    // Remove the server from the server list
+    delete v->second[0];
+    delete v->second[1];
+    delete v->second[2];
+
+    fServiceInfoList.erase(v);
+    fServiceList.erase(fServiceList.find(s));
+}
+
+// --------------------------------------------------------------------------
+//
+//! Removes the service subscription for SERVICE_LIST, SERVICE_DESC and
+//! STATE_LIST for all servers, as well as all stored informations.
+//! Don't forget to call this function if it is overwritten in a derived
+//! class.
+//!
+void DimServiceInfoList::RemoveAllServers()
+{
+    for (ServiceInfoList::iterator i=fServiceInfoList.begin();
+         i!=fServiceInfoList.end(); i++)
+    {
+        delete i->second[0];
+        delete i->second[1];
+        delete i->second[2];
+    }
+
+    fServiceInfoList.clear();
+    fServiceList.clear();
+}
+
+
+// --------------------------------------------------------------------------
+//
+//! This function processes the update of the SERVICE_LIST, SERVICE_DESC,
+//! and STATE_LIST updates.
+//!
+//! Whenever a service is added or removed or all services of a server are
+//! removed (the list is newly sent completely) the virtual functions
+//! AddService(), RemoveService() and RemoveAllServices() aee called.
+//!
+//! If a new description or a new state is added, the virtual functions
+//! AddDescription() and AddStates() respectively are called.
+//
+void DimServiceInfoList::infoHandler()
+{
+    // Get the name of the service
+    const string svc = getInfo()->getName();
+
+    // Get the server name from the service name
+    const string server  = svc.substr(0, svc.find_first_of('/'));
+    const string service = svc.substr(svc.find_first_of('/')+1);
+
+    if (service=="SERVICE_LIST")
+    {
+        // For easy and fast access get the corresponding reference
+        TypeList &list = fServiceList[server].first;
+
+        const string str = getInfo()->getString();
+
+        // WHAT's THIS???
+        if (str.length()==0)
+            return;
+
+        // Initialize the entry with an empty list
+        if (str[0]!='+' && str[0]!='-')
+        {
+            RemoveAllServices(server);
+            list.clear();
+        }
+
+        string buffer;
+
+        // Tokenize the stream into lines
+        stringstream stream(str);
+        while (getline(stream, buffer, '\n'))
+        {
+            if (buffer.empty())
+                continue;
+
+            // Get the type and compare it with fType
+            const string type = buffer.substr(buffer.find_last_of('|')+1);
+
+            /*
+            const bool iscmd = type=="CMD";
+            if (type!=fType && fType!="*")
+                continue;
+                */
+
+            // Get format, name and command name
+            const string fmt  = buffer.substr(buffer.find_first_of('|')+1, buffer.find_last_of('|')-buffer.find_first_of('|')-1);
+            const string name = buffer.substr(buffer.find_first_of('/')+1, buffer.find_first_of('|')-buffer.find_first_of('/')-1);
+            //const string cmd  = buffer.substr(0, buffer.find_first_of('|'));
+
+            const bool iscmd = type=="CMD";
+
+            // FIXME: Do we need to check that the buffer starts with SERVER ?
+
+            if (buffer[0]=='-')
+            {
+                // Check if this server is not found in the list.
+                // This should never happen if Dim works reliable
+                const TypeList::iterator v = list.find(name);
+                if (v==list.end())
+                {
+                    stringstream err;
+                    err << "Service '" << server << "/" << name << "' not in list as it ought to be.";
+                    throw runtime_error(err.str());
+                }
+
+                RemoveService(server, name, iscmd);
+                list.erase(v);
+
+                continue;
+            }
+
+            if (buffer[0]=='+')
+            {
+                // Check if this server is not found in the list.
+                // This should never happen if Dim works reliable
+                const TypeList::iterator v = list.find(name);
+                if (v!=list.end())
+                {
+                    stringstream err;
+                    err << "Service '" << server << "/" << name << "' already in list not as it ought to be.";
+                    throw runtime_error(err.str());
+                }
+
+                list[name] = make_pair(fmt, iscmd);
+                AddService(server, name, fmt, iscmd);
+
+                continue;
+            }
+
+            // Add name the the list
+            list[name] = make_pair(fmt, iscmd);
+            AddService(server, name, fmt, iscmd);
+        }
+
+        return;
+    }
+
+    if (service=="SERVICE_DESC")
+    {
+        // For easy and fast access get the corresponding reference
+        DescriptionList &list = fServiceList[server].second;
+
+        list.clear();
+
+        string buffer;
+
+        stringstream stream(getInfo()->getString());
+        while (getline(stream, buffer, '\n'))
+        {
+            if (buffer.empty())
+                continue;
+
+            const vector<Description> v = Description::SplitDescription(buffer);
+
+            const string name    = v[0].name.substr(v[0].name.find_first_of('/')+1);
+            const string comment = v[0].comment;
+
+            list[name] = make_pair(comment, vector<Description>(v.begin()+1, v.end()));
+
+            AddDescription(server, name, v);
+        }
+
+        return;
+    }
+
+    if (service=="STATE_LIST")
+    {
+        vector<State> &vec = fServiceList[server].third;
+        vec = State::SplitStates(getInfo()->getString());
+        AddStates(server, vec);
+
+        return;
+    }
+
+    DimServerList::infoHandler();
+}
+
+// --------------------------------------------------------------------------
+//
+//! Returns a list of all services available for the given server.
+//! Depending on iscmd either only services or only commands are returned.
+//!
+//! @param server
+//!     server for which the list should be returned
+//! 
+//! @param iscmd
+//!     true if only commands should be returned, false for services
+//!
+//! @returns
+//!     a vector<string> which contains all the service or command names for
+//!     the given server. The names returned are always SERVER/SERVICE
+//!     If the server was not fund an empty vector is returned.
+//
+vector<string> DimServiceInfoList::GetServiceList(const std::string &server, bool iscmd) const
+{
+    const ServiceList::const_iterator m = fServiceList.find(server);
+    if (m==fServiceList.end())
+        return vector<string>();
+
+    const TypeList &list = m->second.first;
+
+    vector<string> vec;
+    for (TypeList::const_iterator i=list.begin(); i!=list.end(); i++)
+        if (i->second.second==iscmd)
+            vec.push_back(server+'/'+i->first);
+
+    return vec;
+}
+
+// --------------------------------------------------------------------------
+//
+//! Returns a list of all services available in the network.
+//! Depending on iscmd either only services or only commands are returned.
+//!
+//! @param iscmd
+//!     true if only commands should be returned, false for services
+//!
+//! @returns
+//!     a vector<string> which contains all the service or command names in
+//!     the network. The names returned are always SERVER/SERVICE
+//
+vector<string> DimServiceInfoList::GetServiceList(bool iscmd) const
+{
+    vector<string> vec;
+    for (ServiceList::const_iterator m=fServiceList.begin(); m!=fServiceList.end(); m++)
+    {
+        const TypeList &list = m->second.first;
+
+        for (TypeList::const_iterator i=list.begin(); i!=list.end(); i++)
+            if (i->second.second==iscmd)
+                vec.push_back(m->first+'/'+i->first);
+    }
+
+    return vec;
+}
+
+// --------------------------------------------------------------------------
+//
+//! Returns a list of all descriptions for the given service on the
+//! given server. Service in this context can also be a command.
+//!
+//! @param server
+//!     Server name to look for
+//!
+//! @param service
+//!     Service/command name to look for
+//!
+//! @returns
+//!     a vector<Description> which contains all argument descriptions for
+//!     the given service or command. The first entry contains the name
+//!     and the general description for the given service. If the server
+//!     or service was not found an empty vector is returned.
+//
+std::vector<Description> DimServiceInfoList::GetDescription(const std::string &server, const std::string &service) const
+{
+    const ServiceList::const_iterator s = fServiceList.find(server);
+    if (s==fServiceList.end())
+        return vector<Description>();
+
+    const DescriptionList &descs = s->second.second;
+
+    const DescriptionList::const_iterator d = descs.find(service);
+    if (d==descs.end())
+        return vector<Description>();
+
+    vector<Description> vec;
+    vec.push_back(Description(service, d->second.first));
+    vec.insert(vec.end(), d->second.second.begin(), d->second.second.end());
+
+    return vec;
+}
+
+// --------------------------------------------------------------------------
+//
+//! Returns a list of all states associated with the given server.
+//!
+//! @param server
+//!     Server name to look for
+//!
+//! @returns
+//!     a vector<State> which contains all state descriptions for
+//!     the given server. If the server or service was not found an
+//!     empty vector is returned.
+//
+vector<State> DimServiceInfoList::GetStates(const std::string &server) const
+{
+    const ServiceList::const_iterator s = fServiceList.find(server);
+    if (s==fServiceList.end())
+        return vector<State>();
+
+    return s->second.third;
+}
+
+// --------------------------------------------------------------------------
+//
+//! Returns the Description of the state as defined by the arguments.
+//! given server. Service in this context can also be a command.
+//!
+//! @param server
+//!     Server name to look for
+//!
+//! @param state
+//!     The state index to look for (e.g. 1)
+//!
+//! @returns
+//!     The State object containing the description. If teh server was
+//!     not found the State object will contain the index -3, if the
+//!     state was not found -2.
+//
+State DimServiceInfoList::GetState(const std::string &server, int state) const
+{
+    const ServiceList::const_iterator s = fServiceList.find(server);
+    if (s==fServiceList.end())
+        return State(-3, "", "");
+
+    const std::vector<State> &v = s->second.third;
+
+    for (vector<State>::const_iterator i=v.begin(); i!=v.end(); i++)
+        if (i->index==state)
+            return *i;
+
+    return State(-2, "", "");
+}
+
+// --------------------------------------------------------------------------
+//
+//! Returns whether the given service on the given server is a command
+//! or not.
+//!
+//! @param server
+//!     Server name to look for
+//!
+//! @param service
+//!     The service name to look for
+//!
+//! @returns
+//!     1 if it is a command, 0 if it is a service, -1 if the service
+//!     was not found on the server, -2 if the server was not found.
+//
+int DimServiceInfoList::IsCommand(const std::string &server, const std::string &service) const
+{
+    const ServiceList::const_iterator s = fServiceList.find(server);
+    if (s==fServiceList.end())
+        return -2;
+
+    const TypeList &list = s->second.first;
+
+    const TypeList::const_iterator t = list.find(service);
+    if (t==list.end())
+        return -1;
+
+    return t->second.second;
+}
+
+
+// --------------------------------------------------------------------------
+//
+//! Print the full available documentation (description) of all available
+//! services or comments to the the given stream.
+//!
+//! @param out
+//!    ostream to which the output is send.
+//!
+//! @param iscmd
+//!   true if all commands should be printed, false for services.
+//!
+//! @param serv
+//!    if a server is given, only the information for this server is printed
+//!
+//! @param service
+//!    if a service is given, only information for this service is printed
+//!
+//! @returns
+//!    the number of descriptions found
+//
+int DimServiceInfoList::PrintDescription(std::ostream &out, bool iscmd, const string &serv, const string &service) const
+{
+    int rc = 0;
+    for (ServiceList::const_iterator i=fServiceList.begin(); i!=fServiceList.end(); i++)
+    {
+        const string &server = i->first;
+
+        if (!serv.empty() && server!=serv)
+            continue;
+
+        out << kRed << "----- " << server << " -----" << endl;
+
+        const TypeList        &types = i->second.first;
+        const DescriptionList &descs = i->second.second;
+
+        for (TypeList::const_iterator t=types.begin(); t!=types.end(); t++)
+        {
+            if (!service.empty() && t->first!=service)
+                continue;
+
+            if (t->second.second!=iscmd)
+                continue;
+
+            rc++;
+
+            out << " " << t->first;
+
+            // Check t->second->first for command or service
+            const string fmt = t->second.first;
+            if (!fmt.empty())
+                out << '[' << fmt << ']';
+
+            const DescriptionList::const_iterator d = descs.find(t->first);
+            if (d==descs.end())
+            {
+                out << endl;
+                continue;
+            }
+
+            const string comment         = d->second.first;
+            const vector<Description> &v = d->second.second;
+
+            for (vector<Description>::const_iterator j=v.begin(); j!=v.end(); j++)
+                out << " <" << j->name << ">";
+            out << endl;
+
+            if (!comment.empty())
+                out << "    " << comment << endl;
+
+            for (vector<Description>::const_iterator j=v.begin(); j!=v.end(); j++)
+            {
+                out << "    " << kGreen << j->name;
+                if (!j->comment.empty())
+                    out << kReset << ": " << kBlue << j->comment;
+                if (!j->unit.empty())
+                    out << kYellow << " [" << j->unit << "]";
+                out << endl;
+            }
+        }
+        out << endl;
+    }
+
+    return rc;
+}
+
+// --------------------------------------------------------------------------
+//
+//! Print the full list of stated for the given server.
+//!
+//! @param out
+//!    ostream to which the output is send.
+//!
+//! @param serv
+//!    if a server is given, only the information for this server is printed
+//!
+//! @returns
+//!    the number of states found
+//
+int DimServiceInfoList::PrintStates(std::ostream &out, const string &serv) const
+{
+    int rc = 0;
+    for (ServiceList::const_iterator i=fServiceList.begin(); i!=fServiceList.end(); i++)
+    {
+        const string &server = i->first;
+
+        if (!serv.empty() && server!=serv)
+            continue;
+
+        out << kRed << "----- " << server << " -----" << endl;
+
+        const vector<State> &v = i->second.third;
+
+        if (v.size()==0)
+            out << "   <no states>" << endl;
+        else
+            rc++;
+
+        for (vector<State>::const_iterator s=v.begin(); s!=v.end(); s++)
+        {
+            out << kBold   << setw(5) << s->index << kReset << ": ";
+            out << kYellow << s->name;
+            out << kBlue   << " (" << s->comment << ")" << endl;
+        }
+        out << endl;
+    }
+
+    return rc;
+}
+
+
+// --------------------------------------------------------------------------
+//
+//! Tries to send a dim command according to the arguments.
+//! The command given is evaluated according to the available format string.
+//!
+//! @param server
+//!    The name of the server to which the command should be send, e.g. DRIVE
+//!
+//! @param str
+//!    Command and data, eg "TRACK 12.5 13.8"
+//!
+//! @param lout
+//!    the ostream to which errors and debug output is redirected
+//!
+//! @throws
+//!    runtime_error if the server or command was not found, or if the
+//!    format associated with the command could not be properly parsed,
+//!    or if the command could not successfully be emitted.
+//!
+void DimServiceInfoList::SendDimCommand(const string &server, string str, ostream &lout) const
+{
+    str = Trim(str);
+
+    // Find the delimiter between the command name and the data
+    size_t p0 = str.find_first_of(' ');
+    if (p0==string::npos)
+        p0 = str.length();
+
+    // Get just the command name separated from the data
+    const string name = str.substr(0, p0);
+
+    // Compile the command which will be sent to the state-machine
+    const string cmd = server + '/' + name;
+
+    const ServiceList::const_iterator m = fServiceList.find(server);
+    if (m==fServiceList.end())
+        throw runtime_error("Unkown server '"+server+"'");
+
+    const TypeList &services = m->second.first;
+
+    const TypeList::const_iterator t = services.find(name);
+    if (t==services.end())
+        throw runtime_error("Command '"+name+"' not known on server '"+server+"'");
+
+    if (!t->second.second)
+        throw runtime_error("'"+server+"/"+name+" not a command.");
+
+    // Get the format of the event data
+    const string fmt = t->second.first;
+
+    // Convert the user entered data according to the format string
+    // into a data block which will be attached to the event
+    const Converter conv(lout, fmt, false);
+    if (!conv)
+        throw runtime_error("Couldn't properly parse the format... ignored.");
+
+    lout << kBlue << cmd;
+    const vector<char> v = conv.GetVector(str.substr(p0));
+    lout << endl;
+
+    const int rc = DimClient::sendCommand(cmd.c_str(), (void*)v.data(), v.size());
+    if (!rc)
+        throw runtime_error("ERROR - Sending command "+cmd+" failed.");
+}
+
+// --------------------------------------------------------------------------
+//
+//! Catches the runtime_erros thrown by
+//!    SendDimCommand(const string &, string, ostream &)
+//! and redirects the error message to the output stream.
+//!
+//! @param lout
+//!    the ostream to which errors and debug output is redirected
+//!
+//! @param server
+//!    The name of the server to which the command should be send, e.g. DRIVE
+//!
+//! @param str
+//!    Command and data, eg "TRACK 12.5 13.8"
+//!
+//! @returns
+//!    true if SendDimComment didn't throw an exception, false otherwise
+//!
+bool DimServiceInfoList::SendDimCommand(ostream &lout, const string &server, const string &str) const
+{
+    try
+    {
+        SendDimCommand(server, str, lout);
+        lout << kGreen << "Command emitted successfully to " << server << "." << endl;
+        return true;
+    }
+    catch (const runtime_error &e)
+    {
+        lout << kRed << e.what() << endl;
+        return false;
+    }
+}
+
+// --------------------------------------------------------------------------
+//
+//! Calls SendDimCommand(const string &, string, ostream &) and dumps
+//! the output.
+//!
+//! @param server
+//!    The name of the server to which the command should be send, e.g. DRIVE
+//!
+//! @param str
+//!    Command and data, eg "TRACK 12.5 13.8"
+//!
+//! @throws
+//!    see SendDimCommand(const string &, string, ostream &)
+//
+void DimServiceInfoList::SendDimCommand(const std::string &server, const std::string &str) const
+{
+    ostringstream dummy;
+    SendDimCommand(server, str, dummy);
+}
Index: /trunk/FACT++/src/DimServiceInfoList.h
===================================================================
--- /trunk/FACT++/src/DimServiceInfoList.h	(revision 10378)
+++ /trunk/FACT++/src/DimServiceInfoList.h	(revision 10378)
@@ -0,0 +1,98 @@
+#ifndef FACT_DimServiceInfoList
+#define FACT_DimServiceInfoList
+
+#include <map>
+#include <vector>
+#include <string>
+
+#include "State.h"
+#include "Description.h"
+#include "DimServerList.h"
+
+class DimInfo;
+
+class DimServiceInfoList : public DimServerList
+{
+public:
+
+    typedef std::map<const std::string, std::vector<DimInfo*>> ServiceInfoList;
+
+    //                   Format   IsCmd
+    typedef std::pair<std::string, bool> ServiceType;
+
+    //                 name of service  Format/description
+    typedef std::map<const std::string, ServiceType> TypeList;
+
+    //                 ServiceName                 comment      list of descriptions
+    typedef std::map<const std::string, std::pair<std::string, std::vector<Description>>> DescriptionList;
+
+    struct ServerInfo
+    {
+        TypeList           first;   /// Format and description of the service
+        DescriptionList    second;  /// Description of the arguments
+        std::vector<State> third;   /// Available states of teh server
+    };
+
+    //                   Server         ServerInfo
+    typedef std::map<const std::string, ServerInfo> ServiceList;
+
+private:
+    ServiceInfoList fServiceInfoList; /// A map storing the service description to retrieve all informations
+    ServiceList     fServiceList;     /// A mal containing all the available informations
+
+    DimInfo *CreateDimInfo(const std::string &str, const std::string &svc) const;
+    DimInfo *CreateSL(const std::string &str) const { return CreateDimInfo(str, "SERVICE_LIST"); }
+    DimInfo *CreateFMT(const std::string &str) const { return CreateDimInfo(str, "SERVICE_DESC"); }
+    DimInfo *CreateDS(const std::string &str) const { return CreateDimInfo(str, "STATE_LIST"); }
+
+protected:
+    void AddServer(const std::string &s);
+    void RemoveServer(const std::string &s);
+    void RemoveAllServers();
+
+    virtual void AddService(const std::string &server, const std::string &service, const std::string &fmt, bool iscmd)
+    {
+    }
+    virtual void RemoveService(const std::string &server, const std::string &service, bool iscmd)
+    {
+    }
+    virtual void RemoveAllServices(const std::string &server)
+    {
+    }
+
+    virtual void AddDescription(const std::string &server, const std::string &service, const std::vector<Description> &vec)
+    {
+    }
+
+    virtual void AddStates(const std::string &server, const std::vector<State> &vec)
+    {
+    }
+
+protected:
+    void infoHandler();
+
+public:
+    DimServiceInfoList() { }
+    ~DimServiceInfoList() { RemoveAllServers(); }
+
+    std::vector<std::string> GetServiceList(bool iscmd=false) const;
+    std::vector<std::string> GetServiceList(const std::string &server, bool iscmd=false) const;
+
+    std::vector<std::string> GetCommandList() const { return GetServiceList(true); }
+    std::vector<std::string> GetCommandList(const std::string &server) const { return GetServiceList(server, true); }
+
+    std::vector<Description> GetDescription(const std::string &server, const std::string &service) const;
+    std::vector<State>       GetStates(const std::string &server) const;
+    State                    GetState(const std::string &server, int state) const;
+
+    int IsCommand(const std::string &server, const std::string &service) const;
+
+    int PrintDescription(std::ostream &out, bool iscmd, const std::string &serv="", const std::string &svc="") const;
+    int PrintStates(std::ostream &out, const std::string &serv="") const;
+
+    bool SendDimCommand(std::ostream &lout, const std::string &server, const std::string &str) const;
+    void SendDimCommand(const std::string &server, std::string str, std::ostream &lout) const;
+    void SendDimCommand(const std::string &server, const std::string &str) const;
+};
+
+#endif
