Index: mythtv/libs/libmyth/mythcontext.cpp
===================================================================
--- mythtv/libs/libmyth/mythcontext.cpp	(revision 27319)
+++ mythtv/libs/libmyth/mythcontext.cpp	(working copy)
@@ -71,11 +71,6 @@
 
     void LoadDatabaseSettings(void);
 
-    bool LoadSettingsFile(void);
-    bool WriteSettingsFile(const DatabaseParams &params,
-                           bool overwrite = false);
-    bool FindSettingsProbs(void);
-
     bool    PromptForDatabaseParams(const QString &error);
     QString TestDBconnection(void);
     void    SilenceDBerrors(void);
@@ -464,31 +459,9 @@
  */
 void MythContextPrivate::LoadDatabaseSettings(void)
 {
-    if (!LoadSettingsFile())
-    {
-        VERBOSE(VB_IMPORTANT, "Unable to read configuration file mysql.txt");
+    gCoreContext->GetDB()->LoadDatabaseParamsFromDisk(m_DBparams, true);
+    gCoreContext->GetDB()->SetDatabaseParams(m_DBparams);
 
-        // Sensible connection defaults.
-        m_DBparams.dbHostName    = "localhost";
-        m_DBparams.dbHostPing    = true;
-        m_DBparams.dbPort        = 0;
-        m_DBparams.dbUserName    = "mythtv";
-        m_DBparams.dbPassword    = "mythtv";
-        m_DBparams.dbName        = "mythconverg";
-        m_DBparams.dbType        = "QMYSQL3";
-        m_DBparams.localEnabled  = false;
-        m_DBparams.localHostName = "my-unique-identifier-goes-here";
-        m_DBparams.wolEnabled    = false;
-        m_DBparams.wolReconnect  = 0;
-        m_DBparams.wolRetry      = 5;
-        m_DBparams.wolCommand    = "echo 'WOLsqlServerCommand not set'";
-        gCoreContext->GetDB()->SetDatabaseParams(m_DBparams);
-    }
-
-    // Even if we have loaded the settings file, it may be incomplete,
-    // so we check for missing values and warn user
-    FindSettingsProbs();
-
     QString hostname = m_DBparams.localHostName;
     if (hostname.isEmpty() ||
         hostname == "my-unique-identifier-goes-here")
@@ -509,173 +482,6 @@
     gCoreContext->SetLocalHostname(hostname);
 }
 
-/**
- * Load mysql.txt and parse its values into m_DBparams
- */
-bool MythContextPrivate::LoadSettingsFile(void)
-{
-    Settings *oldsettings = gCoreContext->GetDB()->GetOldSettings();
-
-    if (!oldsettings->LoadSettingsFiles("mysql.txt", GetInstallPrefix(),
-                                        GetConfDir()))
-        return false;
-
-    m_DBparams.dbHostName = oldsettings->GetSetting("DBHostName");
-    m_DBparams.dbHostPing = oldsettings->GetSetting("DBHostPing") != "no";
-    m_DBparams.dbPort     = oldsettings->GetNumSetting("DBPort");
-    m_DBparams.dbUserName = oldsettings->GetSetting("DBUserName");
-    m_DBparams.dbPassword = oldsettings->GetSetting("DBPassword");
-    m_DBparams.dbName     = oldsettings->GetSetting("DBName");
-    m_DBparams.dbType     = oldsettings->GetSetting("DBType");
-
-    m_DBparams.localHostName = oldsettings->GetSetting("LocalHostName");
-    m_DBparams.localEnabled  = m_DBparams.localHostName.length() > 0;
-
-    m_DBparams.wolReconnect
-        = oldsettings->GetNumSetting("WOLsqlReconnectWaitTime");
-    m_DBparams.wolEnabled = m_DBparams.wolReconnect > 0;
-
-    m_DBparams.wolRetry   = oldsettings->GetNumSetting("WOLsqlConnectRetry");
-    m_DBparams.wolCommand = oldsettings->GetSetting("WOLsqlCommand");
-    gCoreContext->GetDB()->SetDatabaseParams(m_DBparams);
-
-    return true;
-}
-
-bool MythContextPrivate::WriteSettingsFile(const DatabaseParams &params,
-                                           bool overwrite)
-{
-    QString path = GetConfDir() + "/mysql.txt";
-    QFile   * f  = new QFile(path);
-
-    if (!overwrite && f->exists())
-    {
-        delete f;
-        return false;
-    }
-
-    QString dirpath = GetConfDir();
-    QDir createDir(dirpath);
-
-    if (!createDir.exists())
-    {
-        if (!createDir.mkdir(dirpath))
-        {
-            VERBOSE(VB_IMPORTANT, QString("Could not create %1").arg(dirpath));
-            return false;
-        }
-    }
-
-    if (!f->open(QIODevice::WriteOnly))
-    {
-        VERBOSE(VB_IMPORTANT, QString("Could not open settings file %1 "
-                                      "for writing").arg(path));
-        return false;
-    }
-
-    VERBOSE(VB_IMPORTANT, QString("Writing settings file %1").arg(path));
-    QTextStream s(f);
-    s << "DBHostName=" << params.dbHostName << endl;
-
-    s << "\n"
-      << "# By default, MythTV tries to ping the DB host to see if it exists.\n"
-      << "# If your DB host or network doesn't accept pings, set this to no:\n"
-      << "#\n";
-
-    if (params.dbHostPing)
-        s << "#DBHostPing=no" << endl << endl;
-    else
-        s << "DBHostPing=no" << endl << endl;
-
-    if (params.dbPort)
-        s << "DBPort=" << params.dbPort << endl;
-
-    s << "DBUserName=" << params.dbUserName << endl
-      << "DBPassword=" << params.dbPassword << endl
-      << "DBName="     << params.dbName     << endl
-      << "DBType="     << params.dbType     << endl
-      << endl
-      << "# Set the following if you want to use something other than this\n"
-      << "# machine's real hostname for identifying settings in the database.\n"
-      << "# This is useful if your hostname changes often, as otherwise you\n"
-      << "# will need to reconfigure mythtv every time.\n"
-      << "# NO TWO HOSTS MAY USE THE SAME VALUE\n"
-      << "#\n";
-
-    if (params.localEnabled)
-        s << "LocalHostName=" << params.localHostName << endl;
-    else
-        s << "#LocalHostName=my-unique-identifier-goes-here\n";
-
-    s << endl
-      << "# If you want your frontend to be able to wake your MySQL server\n"
-      << "# using WakeOnLan, have a look at the following settings:\n"
-      << "#\n"
-      << "#\n"
-      << "# The time the frontend waits (in seconds) between reconnect tries.\n"
-      << "# This should be the rough time your MySQL server needs for startup\n"
-      << "#\n";
-
-    if (params.wolEnabled)
-        s << "WOLsqlReconnectWaitTime=" << params.wolReconnect << endl;
-    else
-        s << "#WOLsqlReconnectWaitTime=0\n";
-
-    s << "#\n"
-      << "#\n"
-      << "# This is the number of retries to wake the MySQL server\n"
-      << "# until the frontend gives up\n"
-      << "#\n";
-
-    if (params.wolEnabled)
-        s << "WOLsqlConnectRetry=" << params.wolRetry << endl;
-    else
-        s << "#WOLsqlConnectRetry=5\n";
-
-    s << "#\n"
-      << "#\n"
-      << "# This is the command executed to wake your MySQL server.\n"
-      << "#\n";
-
-    if (params.wolEnabled)
-        s << "WOLsqlCommand=" << params.wolCommand << endl;
-    else
-        s << "#WOLsqlCommand=echo 'WOLsqlServerCommand not set'\n";
-
-    f->close();
-    return true;
-}
-
-bool MythContextPrivate::FindSettingsProbs(void)
-{
-    bool problems = false;
-
-    if (m_DBparams.dbHostName.isEmpty())
-    {
-        problems = true;
-        VERBOSE(VB_IMPORTANT, "DBHostName is not set in mysql.txt");
-        VERBOSE(VB_IMPORTANT, "Assuming localhost");
-        m_DBparams.dbHostName = "localhost";
-    }
-    if (m_DBparams.dbUserName.isEmpty())
-    {
-        problems = true;
-        VERBOSE(VB_IMPORTANT, "DBUserName is not set in mysql.txt");
-    }
-    if (m_DBparams.dbPassword.isEmpty())
-    {
-        problems = true;
-        VERBOSE(VB_IMPORTANT, "DBPassword is not set in mysql.txt");
-    }
-    if (m_DBparams.dbName.isEmpty())
-    {
-        problems = true;
-        VERBOSE(VB_IMPORTANT, "DBName is not set in mysql.txt");
-    }
-    gCoreContext->GetDB()->SetDatabaseParams(m_DBparams);
-    return problems;
-}
-
 bool MythContextPrivate::PromptForDatabaseParams(const QString &error)
 {
     bool accepted = false;
@@ -974,11 +780,7 @@
     switch (selected)
     {
         case kDialogCodeButton0:
-            if (!WriteSettingsFile(m_DBparams, true))
-            {
-                VERBOSE(VB_IMPORTANT, "WriteSettingsFile failed.");
-                return -1;
-            }
+            MythDB::SaveDatabaseParamsToDisk(m_DBparams, GetConfDir(), true);
             // User prefers mysql.txt, so throw away default UPnP backend:
             m_XML->SetValue(kDefaultUSN, "");
             m_XML->Save();
@@ -1470,7 +1272,7 @@
           params.wolRetry      != cur_params.wolRetry     ||
           params.wolCommand    != cur_params.wolCommand)))
     {
-        ret = d->WriteSettingsFile(params, true);
+        ret = MythDB::SaveDatabaseParamsToDisk(params, GetConfDir(), true);
         if (ret)
         {
             // Save the new settings:
Index: mythtv/libs/libmythupnp/httprequest.cpp
===================================================================
--- mythtv/libs/libmythupnp/httprequest.cpp	(revision 27319)
+++ mythtv/libs/libmythupnp/httprequest.cpp	(working copy)
@@ -846,6 +846,7 @@
             {
                 sName  = QUrl::fromPercentEncoding(sName.toLatin1());
                 sValue = QUrl::fromPercentEncoding(sValue.toLatin1());
+                sValue.replace("+"," ");
 
                 mapParams.insert( sName.trimmed(), sValue );
                 nCount++;
Index: mythtv/libs/libmythdb/mythdb.cpp
===================================================================
--- mythtv/libs/libmythdb/mythdb.cpp	(revision 27319)
+++ mythtv/libs/libmythdb/mythdb.cpp	(working copy)
@@ -1,15 +1,18 @@
 #include <vector>
 using namespace std;
 
+#include <QReadWriteLock>
+#include <QSqlError>
 #include <QMutex>
-#include <QReadWriteLock>
+#include <QFile>
 #include <QHash>
-#include <QSqlError>
+#include <QDir>
 
 #include "mythdb.h"
 #include "mythdbcon.h"
 #include "mythverbose.h"
 #include "oldsettings.h"
+#include "mythdirs.h"
 
 static MythDB *mythdb = NULL;
 static QMutex dbLock;
@@ -845,6 +848,179 @@
     ClearSettingsCache();
 }
 
+bool MythDB::LoadDatabaseParamsFromDisk(
+    DatabaseParams &params, bool sanitize)
+{
+    Settings settings;
+    if (settings.LoadSettingsFiles(
+            "mysql.txt", GetInstallPrefix(), GetConfDir()))
+    {
+        params.dbHostName = settings.GetSetting("DBHostName");
+        params.dbHostPing = settings.GetSetting("DBHostPing") != "no";
+        params.dbPort     = settings.GetNumSetting("DBPort");
+        params.dbUserName = settings.GetSetting("DBUserName");
+        params.dbPassword = settings.GetSetting("DBPassword");
+        params.dbName     = settings.GetSetting("DBName");
+        params.dbType     = settings.GetSetting("DBType");
+
+        params.localHostName = settings.GetSetting("LocalHostName");
+        params.localEnabled  = !params.localHostName.isEmpty();
+
+        params.wolReconnect  =
+            settings.GetNumSetting("WOLsqlReconnectWaitTime");
+        params.wolEnabled = params.wolReconnect > 0;
+
+        params.wolRetry   = settings.GetNumSetting("WOLsqlConnectRetry");
+        params.wolCommand = settings.GetSetting("WOLsqlCommand");
+    }
+    else if (sanitize)
+    {
+        VERBOSE(VB_IMPORTANT, "Unable to read configuration file mysql.txt");
+
+        // Sensible connection defaults.
+        params.dbHostName    = "localhost";
+        params.dbHostPing    = true;
+        params.dbPort        = 0;
+        params.dbUserName    = "mythtv";
+        params.dbPassword    = "mythtv";
+        params.dbName        = "mythconverg";
+        params.dbType        = "QMYSQL3";
+        params.localEnabled  = false;
+        params.localHostName = "my-unique-identifier-goes-here";
+        params.wolEnabled    = false;
+        params.wolReconnect  = 0;
+        params.wolRetry      = 5;
+        params.wolCommand    = "echo 'WOLsqlServerCommand not set'";
+    }
+    else
+    {
+        return false;
+    }
+
+    // Print some warnings if things look fishy..
+
+    if (params.dbHostName.isEmpty())
+    {
+        VERBOSE(VB_IMPORTANT, "DBHostName is not set in mysql.txt");
+        VERBOSE(VB_IMPORTANT, "Assuming localhost");
+    }
+    if (params.dbUserName.isEmpty())
+        VERBOSE(VB_IMPORTANT, "DBUserName is not set in mysql.txt");
+    if (params.dbPassword.isEmpty())
+        VERBOSE(VB_IMPORTANT, "DBPassword is not set in mysql.txt");
+    if (params.dbName.isEmpty())
+        VERBOSE(VB_IMPORTANT, "DBName is not set in mysql.txt");
+
+    // If sanitize set, replace empty dbHostName with "localhost"
+    if (sanitize && params.dbHostName.isEmpty())
+        params.dbHostName = "localhost";
+
+    return true;
+}
+
+bool MythDB::SaveDatabaseParamsToDisk(
+    const DatabaseParams &params, const QString &confdir, bool overwrite)
+{
+    QString path = confdir + "/mysql.txt";
+    QFile   * f  = new QFile(path);
+
+    if (!overwrite && f->exists())
+    {
+        return false;
+    }
+
+    QString dirpath = confdir;
+    QDir createDir(dirpath);
+
+    if (!createDir.exists())
+    {
+        if (!createDir.mkdir(dirpath))
+        {
+            VERBOSE(VB_IMPORTANT, QString("Could not create %1").arg(dirpath));
+            return false;
+        }
+    }
+
+    if (!f->open(QIODevice::WriteOnly))
+    {
+        VERBOSE(VB_IMPORTANT, QString("Could not open settings file %1 "
+                                      "for writing").arg(path));
+        return false;
+    }
+
+    VERBOSE(VB_IMPORTANT, QString("Writing settings file %1").arg(path));
+    QTextStream s(f);
+    s << "DBHostName=" << params.dbHostName << endl;
+
+    s << "\n"
+      << "# By default, Myth tries to ping the DB host to see if it exists.\n"
+      << "# If your DB host or network doesn't accept pings, set this to no:\n"
+      << "#\n";
+
+    if (params.dbHostPing)
+        s << "#DBHostPing=no" << endl << endl;
+    else
+        s << "DBHostPing=no" << endl << endl;
+
+    if (params.dbPort)
+        s << "DBPort=" << params.dbPort << endl;
+
+    s << "DBUserName=" << params.dbUserName << endl
+      << "DBPassword=" << params.dbPassword << endl
+      << "DBName="     << params.dbName     << endl
+      << "DBType="     << params.dbType     << endl
+      << endl
+      << "# Set the following if you want to use something other than this\n"
+      << "# machine's real hostname for identifying settings in the database.\n"
+      << "# This is useful if your hostname changes often, as otherwise you\n"
+      << "# will need to reconfigure mythtv every time.\n"
+      << "# NO TWO HOSTS MAY USE THE SAME VALUE\n"
+      << "#\n";
+
+    if (params.localEnabled)
+        s << "LocalHostName=" << params.localHostName << endl;
+    else
+        s << "#LocalHostName=my-unique-identifier-goes-here\n";
+
+    s << endl
+      << "# If you want your frontend to be able to wake your MySQL server\n"
+      << "# using WakeOnLan, have a look at the following settings:\n"
+      << "#\n"
+      << "#\n"
+      << "# The time the frontend waits (in seconds) between reconnect tries.\n"
+      << "# This should be the rough time your MySQL server needs for startup\n"
+      << "#\n";
+
+    if (params.wolEnabled)
+        s << "WOLsqlReconnectWaitTime=" << params.wolReconnect << endl;
+    else
+        s << "#WOLsqlReconnectWaitTime=0\n";
+
+    s << "#\n"
+      << "#\n"
+      << "# This is the number of retries to wake the MySQL server\n"
+      << "# until the frontend gives up\n"
+      << "#\n";
+
+    if (params.wolEnabled)
+        s << "WOLsqlConnectRetry=" << params.wolRetry << endl;
+    else
+        s << "#WOLsqlConnectRetry=5\n";
+
+    s << "#\n"
+      << "#\n"
+      << "# This is the command executed to wake your MySQL server.\n"
+      << "#\n";
+
+    if (params.wolEnabled)
+        s << "WOLsqlCommand=" << params.wolCommand << endl;
+    else
+        s << "#WOLsqlCommand=echo 'WOLsqlServerCommand not set'\n";
+
+    f->close();
+    return true;
+}
+
 void MythDB::WriteDelayedSettings(void)
 {
     if (!HaveValidDatabase())
Index: mythtv/libs/libmythdb/mythdb.h
===================================================================
--- mythtv/libs/libmythdb/mythdb.h	(revision 27319)
+++ mythtv/libs/libmythdb/mythdb.h	(working copy)
@@ -82,6 +82,12 @@
     static void destroyMythDB();
     static QString toCommaList(const QMap<QString, QVariant> &bindings,
                                uint indent = 0, uint softMaxColumn = 80);
+
+    static bool LoadDatabaseParamsFromDisk(
+        DatabaseParams &params, bool sanitize);
+    static bool SaveDatabaseParamsToDisk(
+        const DatabaseParams &params, const QString &confdir, bool overwrite);
+
   protected:
     MythDB();
    ~MythDB();
Index: mythtv/programs/mythbackend/backendcontext.h
===================================================================
--- mythtv/programs/mythbackend/backendcontext.h	(revision 27319)
+++ mythtv/programs/mythbackend/backendcontext.h	(working copy)
@@ -20,4 +20,9 @@
 extern QString      pidfile;
 extern QString      logfile;
 
+class BackendContext
+{
+    
+};
+
 #endif // _BACKEND_CONTEXT_H_
Index: mythtv/programs/mythbackend/mediaserver.cpp
===================================================================
--- mythtv/programs/mythbackend/mediaserver.cpp	(revision 27319)
+++ mythtv/programs/mythbackend/mediaserver.cpp	(working copy)
@@ -9,6 +9,7 @@
 //////////////////////////////////////////////////////////////////////////////
 
 #include "mediaserver.h"
+#include "httpconfig.h"
 #include "mythxml.h"
 #include "mythdirs.h"
 
@@ -29,9 +30,11 @@
 //
 //////////////////////////////////////////////////////////////////////////////
 
-MediaServer::MediaServer( bool bIsMaster, bool bDisableUPnp /* = FALSE */ )
+MediaServer::MediaServer(void) :
+    m_pUPnpCDS(NULL), m_pUPnpCMGR(NULL), upnpMedia(NULL),
+    m_sSharePath(GetShareDir())
 {
-    VERBOSE(VB_UPNP, QString("MediaServer::Begin"));
+    VERBOSE(VB_UPNP, "MediaServer:ctor:Begin");
 
     // ----------------------------------------------------------------------
     // Initialize Configuration class (Database for Servers)
@@ -44,17 +47,7 @@
     // ----------------------------------------------------------------------
 
     int     nPort = g_pConfig->GetValue( "BackendStatusPort", 6544 );
-    QString sIP   = g_pConfig->GetValue( "BackendServerIP"  , ""   );
 
-    if (sIP.isEmpty())
-    {
-        VERBOSE(VB_IMPORTANT,
-                "MediaServer:: No BackendServerIP Address defined");
-        m_pHttpServer = NULL;
-        return;
-    }
-
-
     m_pHttpServer = new HttpServer();
 
     if (!m_pHttpServer->listen(QHostAddress::Any, nPort))
@@ -66,9 +59,18 @@
         return;
     }
 
-    m_sSharePath = GetShareDir();
     m_pHttpServer->m_sSharePath = m_sSharePath;
 
+    m_pHttpServer->RegisterExtension(new HttpConfig());
+
+    VERBOSE(VB_UPNP, "MediaServer:ctor:End");
+}
+
+void MediaServer::Init(bool bIsMaster, bool bDisableUPnp /* = FALSE */)
+{
+    VERBOSE(VB_UPNP, "MediaServer:Init:Begin");
+
+    int     nPort     = g_pConfig->GetValue( "BackendStatusPort", 6544 );
     QString sFileName = g_pConfig->GetValue( "upnpDescXmlPath",
                                                 m_sSharePath );
     QString sDeviceType;
@@ -101,8 +103,19 @@
 
     VERBOSE(VB_UPNP, "MediaServer::Registering MythXML Service." );
 
-    m_pHttpServer->RegisterExtension( new MythXML( pMythDevice , m_sSharePath));
+    if (m_pHttpServer)
+        m_pHttpServer->RegisterExtension(
+            new MythXML( pMythDevice , m_sSharePath));
 
+    QString sIP = g_pConfig->GetValue( "BackendServerIP"  , ""   );
+    if (sIP.isEmpty())
+    {
+        VERBOSE(VB_IMPORTANT,
+                "MediaServer:: No BackendServerIP Address defined - "
+                "Disabling UPnP");
+        return;
+    }
+
     if (sIP == "localhost" || sIP.startsWith("127."))
     {
         VERBOSE(VB_IMPORTANT, "MediaServer:: Loopback address specified - "
@@ -190,7 +203,7 @@
 
     }
 
-    VERBOSE(VB_UPNP, QString( "MediaServer::End" ));
+    VERBOSE(VB_UPNP, "MediaServer:Init:End");
 }
 
 //////////////////////////////////////////////////////////////////////////////
Index: mythtv/programs/mythbackend/mythsettings.h
===================================================================
--- mythtv/programs/mythbackend/mythsettings.h	(revision 0)
+++ mythtv/programs/mythbackend/mythsettings.h	(revision 0)
@@ -0,0 +1,119 @@
+// -*- Mode: c++ -*-
+
+#ifndef _MYTHSETTINGS_H_
+#define _MYTHSETTINGS_H_
+
+#include <QStringList>
+#include <QMap>
+
+class MythSettingBase
+{
+  public:
+    MythSettingBase() {}
+    virtual ~MythSettingBase() {}
+    virtual QString ToHTML(uint) const { return QString(); }
+};
+typedef QList<MythSettingBase*> MythSettingList;
+
+class MythSettingGroup : public MythSettingBase
+{
+  public:
+    MythSettingGroup(QString hlabel, QString ulabel,
+                     QString script = "") :
+        human_label(hlabel), unique_label(ulabel), ecma_script(script) {}
+
+    QString ToHTML(uint) const;
+
+  public:
+    QString human_label;
+    QString unique_label; ///< div name for stylesheets & javascript
+    MythSettingList settings;
+    QString ecma_script;
+};
+
+class MythSetting : public MythSettingBase
+{
+  public:
+    typedef enum {
+        kFile,
+        kHost,
+        kGlobal,
+        kInvalidSettingType,
+    } SettingType;
+
+    typedef enum {
+        kInteger,
+        kUnsignedInteger,
+        kIntegerRange,
+        kCheckBox,
+        kSelect,   ///< list where only data_list are valid
+        kComboBox, ///< list where user input is allowed
+        kTVFormat,
+        kFrequencyTable,
+        kFloat,
+        kIPAddress,
+        kLocalIPAddress,
+        kString,
+        kTimeOfDay,
+        kOther,
+        kInvalidDataType,
+    } DataType;
+
+    MythSetting(QString _value, QString _default_data, SettingType _stype,
+                QString _label, QString _help_text, DataType _dtype) :
+        value(_value), data(_default_data), default_data(_default_data),
+        stype(_stype), label(_label), help_text(_help_text), dtype(_dtype)
+    {
+    }
+
+    MythSetting(QString _value, QString _default_data, SettingType _stype,
+            QString _label, QString _help_text, DataType _dtype,
+            QStringList _data_list, QStringList _display_list) :
+        value(_value), data(_default_data), default_data(_default_data),
+        stype(_stype), label(_label), help_text(_help_text), dtype(_dtype),
+        data_list(_data_list), display_list(_display_list)
+    {
+    }
+
+    MythSetting(QString _value, QString _default_data, SettingType _stype,
+                QString _label, QString _help_text, DataType _dtype,
+                long long _range_min, long long _range_max) :
+        value(_value), data(_default_data), default_data(_default_data),
+        stype(_stype), label(_label), help_text(_help_text), dtype(_dtype),
+        range_min(_range_min), range_max(_range_max)
+    {
+    }
+
+    MythSetting(QString _value, QString _default_data, SettingType _stype,
+                QString _label, QString _help_text, DataType _dtype,
+                QStringList _data_list, QStringList _display_list,
+                long long _range_min, long long _range_max) :
+        value(_value), data(_default_data), default_data(_default_data),
+        stype(_stype), label(_label), help_text(_help_text), dtype(_dtype),
+        data_list(_data_list), display_list(_display_list),
+        range_min(_range_min), range_max(_range_max)
+    {
+    }
+
+    QString ToHTML(uint) const;
+
+  public:
+    QString value;
+    QString data;
+    QString default_data;
+    SettingType stype;
+    QString label;
+    QString help_text;
+    DataType dtype;
+    QStringList data_list;
+    QStringList display_list;
+    long long range_min;
+    long long range_max;
+};
+
+bool parse_settings(MythSettingList &settings, const QString &filename);
+bool load_settings(MythSettingList &settings, const QString &hostname);
+bool check_settings(MythSettingList &database_settings,
+                    const QMap<QString,QString> &params);
+
+#endif
Index: mythtv/programs/mythbackend/httpconfig.h
===================================================================
--- mythtv/programs/mythbackend/httpconfig.h	(revision 0)
+++ mythtv/programs/mythbackend/httpconfig.h	(revision 0)
@@ -0,0 +1,29 @@
+// -*- Mode: c++ -*-
+
+#ifndef _HTTPCONFIG_H_
+#define _HTTPCONFIG_H_
+
+#include "httpserver.h"
+#include "mythsettings.h"
+
+class QTextStream;
+
+class HttpConfig : public HttpServerExtension
+{
+  public:
+    HttpConfig();
+    virtual ~HttpConfig();
+
+    bool ProcessRequest(HttpWorkerThread *pThread, HTTPRequest *pRequest);
+
+  private:
+    static void PrintHeader(QTextStream&, const QString &form);
+    static void PrintFooter(QTextStream&);
+    static bool LoadSettings(MythSettingList&, const QString &hostname);
+    static void PrintSettings(QTextStream&, const MythSettingList&);
+
+    MythSettingList database_settings;
+    MythSettingList general_settings;
+};
+
+#endif
Index: mythtv/programs/mythbackend/main_helpers.h
===================================================================
--- mythtv/programs/mythbackend/main_helpers.h	(revision 27319)
+++ mythtv/programs/mythbackend/main_helpers.h	(working copy)
@@ -1,6 +1,3 @@
-#ifndef _MAIN_HELPERS_H_
-#define _MAIN_HELPERS_H_
-
 // C++ headers
 #include <iostream>
 #include <fstream>
@@ -16,8 +13,6 @@
 int log_rotate(int report_error);
 void log_rotate_handler(int);
 void upnp_rebuild(int);
-void showUsage(const MythCommandLineParser &cmdlineparser,
-               const QString &version);
 void setupLogfile(void);
 bool openPidfile(ofstream &pidfs, const QString &pidfilename);
 bool setUser(const QString &username);
@@ -48,4 +43,3 @@
     };
 }
 
-#endif // _MAIN_HELPERS_H_
Index: mythtv/programs/mythbackend/main.cpp
===================================================================
--- mythtv/programs/mythbackend/main.cpp	(revision 27319)
+++ mythtv/programs/mythbackend/main.cpp	(working copy)
@@ -1,62 +1,50 @@
-// POSIX headers
-#include <sys/time.h>     // for setpriority
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <libgen.h>
-#include <signal.h>
-
-#include "mythconfig.h"
-#if CONFIG_DARWIN
-    #include <sys/aio.h>    // O_SYNC
-#endif
-
-// C headers
-#include <cstdlib>
-#include <cerrno>
-
-// C++ headers
-#include <iostream>
-#include <fstream>
-using namespace std;
-
 #ifndef _WIN32
 #include <QCoreApplication>
 #else
 #include <QApplication>
 #endif
 
+#include <QFileInfo>
+#include <QRegExp>
+#include <QThread>
 #include <QFile>
-#include <QFileInfo>
 #include <QDir>
 #include <QMap>
-#include <QRegExp>
 
-#include "tv_rec.h"
+#include "mythcommandlineparser.h"
 #include "scheduledrecording.h"
+#include "previewgenerator.h"
+#include "mythcorecontext.h"
+#include "mythsystemevent.h"
+#include "backendcontext.h"
+#include "main_helpers.h"
+#include "storagegroup.h"
+#include "housekeeper.h"
+#include "mediaserver.h"
+#include "mythverbose.h"
+#include "mythversion.h"
+#include "programinfo.h"
 #include "autoexpire.h"
-#include "scheduler.h"
 #include "mainserver.h"
 #include "remoteutil.h"
-#include "housekeeper.h"
-
-#include "mythcorecontext.h"
-#include "mythverbose.h"
-#include "mythversion.h"
-#include "mythdb.h"
 #include "exitcodes.h"
+#include "scheduler.h"
+#include "jobqueue.h"
+#include "dbcheck.h"
 #include "compat.h"
+#include "mythdb.h"
+#include "tv_rec.h"
+
+/*
 #include "storagegroup.h"
 #include "programinfo.h"
 #include "dbcheck.h"
 #include "jobqueue.h"
 #include "mythcommandlineparser.h"
 #include "mythsystemevent.h"
+.r26134
+*/
 
-#include "backendcontext.h"
-#include "main_helpers.h"
-
 #define LOC      QString("MythBackend: ")
 #define LOC_WARN QString("MythBackend, Warning: ")
 #define LOC_ERR  QString("MythBackend, Error: ")
@@ -68,6 +56,21 @@
     #define UNUSED_FILENO 3
 #endif
 
+class MediaServerThread : public QThread
+{
+  public:
+    void run(void)
+    {
+        g_pUPnp = new MediaServer();
+        exec();
+    }
+
+    void BlockUntilReloadNeeded(void)
+    {
+        sleep(60); // TODO
+    }
+};
+
 int main(int argc, char **argv)
 {
     bool cmdline_err;
@@ -182,7 +185,22 @@
 
     ///////////////////////////////////////////
 
-    return run_backend(cmdline);
+    MediaServerThread *mst = new MediaServerThread();
+    mst->start();
+    while (!mst->isRunning())
+        usleep(25000);
+    while (!g_pUPnp)
+        usleep(25000);
+
+    ///////////////////////////////////////////
+
+    while (true)
+    {
+        exitCode = run_backend(cmdline);
+        mst->BlockUntilReloadNeeded();
+    }
+
+    return exitCode;
 }
 
 /* vim: set expandtab tabstop=4 shiftwidth=4: */
Index: mythtv/programs/mythbackend/config_backend_general.xml
===================================================================
--- mythtv/programs/mythbackend/config_backend_general.xml	(revision 0)
+++ mythtv/programs/mythbackend/config_backend_general.xml	(revision 0)
@@ -0,0 +1,857 @@
+<?xml version="1.0" encoding="utf-8"?>
+<config>
+  <group human_label="Host Address Backend Setup" unique_label="server">
+    <group human_label="Local Backend" unique_label="local_server">
+      <setting
+         value="BackendServerIP" default_data="127.0.0.1"
+         setting_type="host" label="IP address"
+         help_text="Enter the IP address of this machine.
+                    Use an externally accessible address (ie, not 
+                    127.0.0.1) if you are going to be running a frontend
+                    on a different machine than this one."
+         data_type="localipaddress" />
+      <setting
+         value="BackendServerPort" default_data="6543"
+         setting_type="host" label="Port"
+         help_text= "Unless you've got good reason to, don't change this."
+         data_type="integer_range"
+         range_min="0" range_max="0xffff" />
+      <setting
+         value="BackendStatusPort" default_data="6544"
+         setting_type="host" label="Status Port"
+         help_text="Port which the server will listen to for HTTP requests."
+         data_type="integer_range"
+         range_min="0" range_max="0xffff" />
+      <setting
+         value="SecurityPin" default_data=""
+         setting_type="host" label="Security Pin (Required)"
+         help_text="Pin code required for a frontend to connect
+                    to the backend. Blank prevents all connections,
+                    0000 allows any client to connect."
+         data_type="string" />
+    </group>
+    <group human_label="Master Backend" unique_label="master_server">
+      <setting
+         value="MasterServerIP" default_data="127.0.0.1"
+         setting_type="global" label="IP address"
+         help_text="The IP address of the master backend server. All
+                    frontend and non-master backend machines will connect
+                    to this server.  If you only have one backend,
+                    this should be the same IP address as above."
+         data_type="ipaddress" />
+      <setting
+         value="MasterServerPort" default_data="6543"
+         setting_type="global" label="Port"
+         help_text="Unless you've got good reason to, don't change this."
+         data_type="integer_range"
+         range_min="0" range_max="0xffff" />
+    </group>
+    <group human_label="Locale Settings" unique_label="locale_settings">
+      <setting
+         value="TVFormat" default_data="ntsc"
+         setting_type="global" label="TV format"
+         help_text="The TV standard to use for viewing TV."
+         data_type="tvformat" />
+      <setting value="VbiFormat" default_data="ntsc"
+               setting_type="global" label="VBI format"
+               help_text="VBI stands for Vertical Blanking Interrupt.
+                          VBI is used to carry Teletext and
+                          Closed Captioning data."
+               data_type="select">
+        <option display="None" data="none" />
+        <option display="PAL Teletext" data="pal" />
+        <option display="NTSC Closed Caption" data="ntsc" />
+      </setting>
+      <setting value="FreqTable" default_data="us-cable"
+               setting_type="global" label="Channel frequency table"
+               help_text="Select the appropriate frequency table for
+                          your system. If you have an antenna, use a 
+                          '-bcast' frequency."
+               data_type="frequency_table" />
+      <setting value="TimeOffset" default_data=""
+               setting_type="global" label="Your Local Timezone (for XMLTV)"
+               help_text="Used if the XMLTV data comes from a different
+                          timezone than your own. This adjust the times in
+                          the XMLTV EPG data to compensate. 'Auto' converts
+                          the XMLTV time to local time using your computer's
+                          timezone. 'None' ignores the XMLTV timezone,
+                          interpreting times as local."
+               data_type="select">
+        <option display="None" data="none" />
+        <option display="Auto" data="auto" />
+        <option display="+0030" data="+0030" />
+        <option display="+0100" data="+0100" />
+        <option display="+0130" data="+0130" />
+        <option display="+0200" data="+0200" />
+        <option display="+0230" data="+0230" />
+        <option display="+0300" data="+0300" />
+        <option display="+0330" data="+0330" />
+        <option display="+0400" data="+0400" />
+        <option display="+0430" data="+0430" />
+        <option display="+0500" data="+0500" />
+        <option display="+0530" data="+0530" />
+        <option display="+0600" data="+0600" />
+        <option display="+0630" data="+0630" />
+        <option display="+0700" data="+0700" />
+        <option display="+0730" data="+0730" />
+        <option display="+0800" data="+0800" />
+        <option display="+0830" data="+0830" />
+        <option display="+0900" data="+0900" />
+        <option display="+0930" data="+0930" />
+        <option display="+1000" data="+1000" />
+        <option display="+1030" data="+1030" />
+        <option display="+1100" data="+1100" />
+        <option display="+1130" data="+1130" />
+        <option display="+1200" data="+1200" />
+        <option display="-1100" data="-1100" />
+        <option display="-1030" data="-1030" />
+        <option display="-1000" data="-1000" />
+        <option display="-0930" data="-0930" />
+        <option display="-0900" data="-0900" />
+        <option display="-0830" data="-0830" />
+        <option display="-0800" data="-0800" />
+        <option display="-0730" data="-0730" />
+        <option display="-0700" data="-0700" />
+        <option display="-0630" data="-0630" />
+        <option display="-0600" data="-0600" />
+        <option display="-0530" data="-0530" />
+        <option display="-0500" data="-0500" />
+        <option display="-0430" data="-0430" />
+        <option display="-0400" data="-0400" />
+        <option display="-0330" data="-0330" />
+        <option display="-0300" data="-0300" />
+        <option display="-0230" data="-0230" />
+        <option display="-0200" data="-0200" />
+        <option display="-0130" data="-0130" />
+        <option display="-0100" data="-0100" />
+        <option display="-0030" data="-0030" />
+      </setting>
+    </group>
+    <group human_label="Miscellaneous Settings"
+           unique_label="miscellaneous_settings">
+      <group human_label="File Management Settings"
+             unique_label="file_management_settings">
+        <setting
+           value="MasterBackendOverride" default_data="1"
+           setting_type="global" label="Master Backend Override"
+           help_text="If enabled, the master backend will stream and
+                      delete files if it finds them in the video directory.
+                      Useful if you are using a central storage location, like
+                      a NFS share, and your slave backend isn't running."
+           data_type="checkbox" />
+        <setting
+           value="DeletesFollowLinks" default_data="0"
+           setting_type="global"
+           label="Follow symbolic links when deleting files"
+           help_text="This will cause Myth to follow symlinks
+                      when recordings and related files are deleted, instead
+                      of deleting the symlink and leaving the actual file."
+           data_type="checkbox" />
+        <setting
+           value="TruncateDeletesSlowly" default_data="0"
+           setting_type="global" label="Delete files slowly"
+           help_text="Some filesystems use a lot of resources when
+                      deleting large recording files.  This option makes Myth
+                      delete the file slowly on this backend to lessen the
+                      impact."
+           data_type="checkbox" />
+<!--
+        <setting
+           value="HDRingbufferSize" default_data="9400"
+           setting_type="global" label="HD Ringbuffer size (KB)"
+           help_text="The HD device ringbuffer allows the
+                      backend to weather moments of stress.
+                      The larger the ringbuffer, the longer
+                      the moments of stress can be. However,
+                      setting the size too large can cause
+                      swapping, which is detrimental."
+           data_type="integer_select"
+           range_min="4700" range_max="94000" step="4700" />
+-->
+        <setting
+           value="StorageScheduler" default_data="BalancedFreeSpace"
+           setting_type="global" label="Storage Group Disk Scheduler"
+           help_text="This setting controls how the Storage Group
+                      scheduling code will balance new recordings across
+                      directories. 'Balanced Free Space' is the recommended
+		      method for most users."
+           data_type="select">
+          <option display="Balanced Free Space" data="BalancedFreeSpace" />
+          <option display="Balanced Disk I/O" data="BalancedDiskIO" />
+          <option display="Combination" data="Combination" />
+        </setting>
+      </group>
+      <setting
+         value="MiscStatusScript" default_data=""
+         setting_type="global" label="Miscellaneous Status Application"
+         help_text="External application or script that outputs
+                    extra information for inclusion in the
+                    backend status page.  See
+                    contrib/info/misc_status_info/README"
+         data_type="string" />
+      <setting
+         value="DisableAutomaticBackup" default_data="0"
+         setting_type="global" label="Disable Automatic Database Backup"
+         help_text="This will prevent Myth from backing up the database
+                    before upgrades. If disabled, you should have your
+                    own backup strategy in place."
+         data_type="checkbox" />
+      <setting
+         value="DisableFirewireReset" default_data="0"
+         setting_type="global" label="Disable Firewire Reset"
+         help_text="By default MythTV will reset the firewire bus when a
+                    firewire recorder stops responding to commands. But
+                    if this causes problems you can disable this here for
+                    Linux firewire recorders."
+         data_type="checkbox" />
+    </group>
+    <group human_label="EIT Scanner Options"
+           unique_label="eit_scanner_options">
+<!--
+      <setting
+         value="EITTransportTimeout" default_data="5"
+         setting_type="global" label="EIT Transport Timeout (mins)"
+         help_text="Maximum time to spend waiting for listings
+                    data on one DTV channel before checking for
+                    new listings data on the next channel."
+         data_type="integer_select"
+         range_min="1" range_max="15" step="1" />
+-->
+      <setting
+         value="EITIgnoresSource" default_data="0"
+         setting_type="global" label="Cross Source EIT"
+         help_text="If enabled, listings data collected on one Video Source
+                    will be applied to the first matching DVB channel on
+                    any Video Source. This is sometimes useful for DVB-S,
+                    but may insert bogus data into any ATSC listings
+                    stored in the same database."
+         data_type="checkbox" />
+      <setting
+         value="EITCrawIdleStart" default_data="60"
+         setting_type="global"
+         label="Backend Idle Before EIT Crawl (seconds)"
+         help_text="The minimum number of seconds after a recorder
+                    becomes idle to wait before MythTV begins
+                    collecting EIT listings data."
+         data_type="select">
+        <option display="30" data="30" />
+        <option display="60" data="60" />
+        <option display="120" data="120" />
+        <option display="300" data="300" />
+        <option display="600" data="600" />
+        <option display="1200" data="1200" />
+        <option display="2400" data="2400" />
+        <option display="3600" data="3600" />
+        <option display="7200" data="7200" />
+      </setting>
+    </group>
+    <group human_label="Shutdown/Wakeup Options"
+           unique_label="shutdown_wakeup_options">
+      <setting data_type="string" value="startupCommand"
+               label="Startup command"
+               default_data=""
+               setting_type="global"
+               help_text="This command is executed right after starting
+                          the BE. As a parameter \'$status\' is replaced by either
+                          \'auto\' if the machine was started automatically or
+                          \'user\' if a user switched it on." />
+      <setting data_type="checkbox" value="blockSDWUwithoutClient"
+               label="Block shutdown before client connected"
+               default_data="1"
+               setting_type="global"
+               help_text="If set, the automatic shutdown routine will
+                          be disabled until a client connects." />
+      <setting data_type="select" value="idleTimeoutSecs"
+               label="Idle shutdown timeout (secs)"
+               default_data="0"
+               setting_type="global"
+               help_text="The amount of time the master backend idles
+                          before it shuts down all backends.">
+        <option display="Disabled" data="0" />
+        <option display="5" data="5" />
+        <option display="15" data="15" />
+        <option display="30" data="30" />
+        <option display="60" data="60" />
+        <option display="120" data="120" />
+        <option display="300" data="300" />
+        <option display="600" data="600" />
+        <option display="1200" data="1200" />
+      </setting>
+      <setting data_type="select" value="idleWaitForRecordingTime"
+               label="Max. wait for recording (min)"
+               default_data="15"
+               setting_type="global"
+               help_text="The amount of time the master backend waits
+                          for a recording.  If it's idle but a recording starts
+                          within this time period, the backends won't shut down.">
+        <option display="5" data="5" />
+        <option display="15" data="15" />
+        <option display="30" data="30" />
+        <option display="60" data="60" />
+        <option display="120" data="120" />
+      </setting>
+      <setting data_type="select" value="StartupSecsBeforeRecording"
+               label="Startup before rec. (secs)"
+               default_data="120"
+               setting_type="global"
+               help_text="The amount of time the master backend will be
+                          woken up before a recording starts.">
+        <option display="5" data="5" />
+        <option display="15" data="15" />
+        <option display="30" data="30" />
+        <option display="60" data="60" />
+        <option display="120" data="120" />
+        <option display="300" data="300" />
+        <option display="600" data="600" />
+        <option display="1200" data="1200" />
+      </setting>
+      <setting data_type="string" value="WakeupTimeFormat"
+               label="Wakeup time format"
+               default_data="hh:mm yyyy-MM-dd"
+               setting_type="global"
+               help_text="The format of the time string passed to the
+                          'setWakeuptime Command' as $time. See
+                          QT::QDateTime.toString() for details. Set to 'time_t' for
+                          seconds since epoch." />
+      <setting data_type="string" value="SetWakeuptimeCommand"
+               label="Command to set Wakeup Time"
+               default_data=""
+               setting_type="global"
+               help_text="The command used to set the wakeup time (passed as
+                          $time) for the Master Backend" />
+      <setting data_type="string" value="ServerHaltCommand"
+               label="Server halt command"
+               default_data="sudo /sbin/halt -p"
+               setting_type="global"
+               help_text="The command used to halt the backends." />
+      <setting data_type="string" value="preSDWUCheckCommand"
+               label="Pre Shutdown check-command"
+               default_data=""
+               setting_type="global"
+               help_text="A command executed before the backend would
+                          shutdown. The return value determines if
+                          the backend can shutdown. 0 - yes,
+                          1 - restart idling,
+                          2 - reset the backend to wait for a frontend." />
+    </group>
+    <group human_label="Backend Wakeup settings"
+           unique_label="backend_wakeup_settings">
+
+      <group human_label="Master Backends"
+             unique_label="backend_wakeup_settings_master_backends">
+        <setting data_type="select" value="WOLbackendReconnectWaitTime"
+                 label="Delay between wake attempts (secs)"
+                 default_data="0"
+                 setting_type="global"
+                 help_text="Length of time the frontend waits between
+                            tries to wake up the master backend. This should be the
+                            time your master backend needs to startup.">
+          <option display="Disabled" data="0" />
+          <option display="1" data="1" />
+          <option display="2" data="2" />
+          <option display="4" data="4" />
+          <option display="8" data="8" />
+          <option display="15" data="15" />
+          <option display="30" data="30" />
+          <option display="60" data="60" />
+          <option display="120" data="120" />
+          <option display="300" data="300" />
+          <option display="600" data="600" />
+          <option display="1200" data="1200" />
+        </setting>
+        <setting data_type="select" value="WOLbackendConnectRetry"
+                 label="Wake Attempts"
+                 setting_type="global"
+                 help_text="Number of times the frontend will try to wake
+                            up the master backend."
+                 default_data="5">
+          <option display="1" data="1" />
+          <option display="2" data="2" />
+          <option display="5" data="5" />
+          <option display="10" data="10" />
+          <option display="20" data="20" />
+          <option display="40" data="40" />
+          <option display="60" data="60" />
+        </setting>
+        <setting data_type="string" value="WOLbackendCommand"
+                 label="Wake Command"
+                 default_data=""
+                 setting_type="global"
+                 help_text="The command used to wake up your master
+                            backend server. For example
+                            'sudo /etc/init.d/mythtv-backend restart'." />
+      </group>
+
+      <group human_label="Slave Backends"
+             unique_label="backend_wakeup_settings_slave_backends">
+        <setting data_type="string" value="SleepCommand"
+                 label="Sleep Command"
+                 default_data=""
+                 setting_type="host"
+                 help_text="The command used to put this slave to sleep.
+                            If set, the master backend will use this
+                            command to put this slave to sleep when it
+                            is not needed for recording." />
+        <setting data_type="string" value="WakeUpCommand"
+                 label="Wake Command"
+                 default_data=""
+                 setting_type="host"
+                 help_text="The command used to wake up this slave from sleep.
+                            This setting is not used on the master backend." />
+      </group>
+    </group>
+    <group human_label="Backend Control"
+           unique_label="backend_control">
+      <setting data_type="string" value="BackendStopCommand"
+               label="Backend Stop Command"
+               default_data="killall mythbackend"
+               setting_type="global"
+               help_text="The command used to stop the backend
+                          when running on the master backend server.
+                          For example 'sudo /etc/init.d/mythtv-backend stop'." />
+      <setting data_type="string" value="BackendStartCommand"
+               label="Backend Start Command"
+               default_data="mythbackend"
+               setting_type="global"
+               help_text="The command used to start the backend
+                          when running on the master backend server.
+                          For example, 'sudo /etc/init.d/mythtv-backend start'." />
+    </group>
+    <group human_label="Job Queue (Backend-Specific)"
+           unique_label="job_queue_host">
+      <setting data_type="select" value="JobQueueMaxSimultaneousJobs"
+               label="Maximum simultaneous jobs on this backend"
+               setting_type="host"
+               help_text="The Job Queue will be limited to running
+                          this many simultaneous jobs on this backend."
+               default_data="1">
+        <option display="0" data="0" />
+        <option display="1" data="1" />
+        <option display="2" data="2" />
+        <option display="3" data="3" />
+        <option display="4" data="4" />
+        <option display="5" data="5" />
+        <option display="6" data="6" />
+        <option display="7" data="7" />
+        <option display="8" data="8" />
+        <option display="9" data="9" />
+        <option display="10" data="10" />
+      </setting>
+      <setting data_type="select" value="JobQueueCheckFrequency"
+               label="Job Queue Check frequency (in seconds)"
+               setting_type="host"
+               help_text="When looking for new jobs to process, the
+                          Job Queue will wait this long between checks."
+               default_data="60">
+        <option display="5" data="5" />
+        <option display="10" data="10" />
+        <option display="15" data="15" />
+        <option display="30" data="30" />
+        <option display="60" data="60" />
+        <option display="90" data="90" />
+        <option display="200" data="200" />
+        <option display="300" data="300" />
+      </setting>
+      <setting data_type="timeofday" value="JobQueueWindowStart"
+               default_value="00:00" label="Job Queue Start Time"
+               setting_type="host"
+               help_text="This setting controls the start of the Job Queue time
+                          window which determines when new jobs will be
+                          started." />
+      <setting data_type="timeofday" value="JobQueueWindowEnd"
+               default_value="23:59" label="Job Queue End Time"
+               setting_type="host"
+               help_text="This setting controls the end of the Job Queue time
+                          window which determines when new jobs will be
+                          started." />
+      <setting data_type="select" value="JobQueueCPU"
+               label="CPU Usage"
+               setting_type="host"
+               help_text="This setting controls approximately how
+                          much CPU jobs in the queue may consume.
+                          On 'High', all available CPU time may be used
+                          which could cause problems on slower systems.">
+        <option display="Low"    data="0" />
+        <option display="Medium" data="1" />
+        <option display="High"   data="2" />
+      </setting>
+      <setting data_type="checkbox" value="JobAllowCommFlag"
+               label="Allow Commercial Detection jobs"
+               default_data="true"
+               setting_type="host"
+               help_text="Allow jobs of this type to run on this backend." />
+      <setting data_type="checkbox" value="JobAllowTranscode"
+               label="Allow Transcoding jobs"
+               default_data="true"
+               setting_type="host"
+               help_text="Allow jobs of this type to run on this backend." />
+      <setting data_type="checkbox" value="JobAllowUserJob1"
+               label="Allow User Job #1 on this backend"
+               default_data="0"
+               setting_type="host"
+               help_text="Allow jobs of this type to run on this backend." />
+      <setting data_type="checkbox" value="JobAllowUserJob2"
+               label="Allow User Job #2 on this backend"
+               default_data="0"
+               setting_type="host"
+               help_text="Allow jobs of this type to run on this backend." />
+      <setting data_type="checkbox" value="JobAllowUserJob3"
+               label="Allow User Job #3 on this backend"
+               default_data="0"
+               setting_type="host"
+               help_text="Allow jobs of this type to run on this backend." />
+      <setting data_type="checkbox" value="JobAllowUserJob4"
+               label="Allow User Job #4 on this backend"
+               default_data="0"
+               setting_type="host"
+               help_text="Allow jobs of this type to run on this backend." />
+    </group>
+    <group human_label="Job Queue (Global)"
+           unique_label="job_queue_global">
+      <setting data_type="checkbox" value="JobsRunOnRecordHost"
+               label="Run Jobs only on original recording backend" default_data="0"
+               setting_type="global"
+               help_text="If set, jobs in the queue will be required
+                          to run on the backend that made the
+                          original recording." />
+      <setting data_type="checkbox" value="AutoCommflagWhileRecording"
+               label="Start Auto-Commercial Flagging jobs when the recording starts"
+               default_data="0"
+               setting_type="global"
+               help_text="If set and Auto Commercial Flagging is ON for
+                          a recording, the flagging job will be started
+                          as soon as the recording starts.  NOT
+                          recommended on underpowered systems." />
+      <setting data_type="string" value="JobQueueCommFlagCommand"
+               label="Commercial Flagger command"
+               default_data="mythcommflag"
+               setting_type="global"
+               help_text="The program used to detect commercials in a
+                          recording.  The default is 'mythcommflag'
+                          if this setting is empty." />
+      <setting data_type="string" value="JobQueueTranscodeCommand"
+               label="Transcoder command"
+               default_data="mythtranscode"
+               setting_type="global"
+               help_text="The program used to transcode recordings.
+                          The default is 'mythtranscode' if this
+                          setting is empty." />
+      <setting data_type="checkbox" value="AutoTranscodeBeforeAutoCommflag"
+               label="Run Transcode Jobs before Auto-Commercial Flagging"
+               default_data="0"
+               setting_type="global"
+               help_text="If set, if both auto-transcode and
+                          auto commercial flagging are turned ON for a
+                          recording, transcoding will run first,
+                          otherwise, commercial flagging runs first." />
+      <setting data_type="checkbox" value="SaveTranscoding"
+               label="Save original files after transcoding (globally)"
+               default_data="0"
+               setting_type="global"
+               help_text="When set and the transcoder is active, the
+                          original files will be renamed to .old once the
+                          transcoding is complete." />
+    </group>
+    <group human_label="Job Queue (Job Commands)"
+           unique_label="job_queue_job_commands">
+      <setting data_type="string" value="UserJobDesc1"
+               label="User Job #1 Description"
+               default_data="User Job #1"
+               setting_type="global"
+               help_text="The Description for this User Job."   />
+      <setting data_type="string" value="UserJob1"
+               label="User Job #1 Command"
+               default_data=""
+               setting_type="global"
+               help_text="The command to run whenever this User Job
+                          number is scheduled." />
+      <setting data_type="string" value="UserJobDesc2"
+               label="User Job #2 Description"
+               default_data="User Job #2"
+               setting_type="global"
+               help_text="The Description for this User Job."   />
+      <setting data_type="string" value="UserJob2"
+               label="User Job #2 Command"
+               default_data=""
+               setting_type="global"
+               help_text="The command to run whenever this User Job
+                          number is scheduled." />
+      <setting data_type="string" value="UserJobDesc3"
+               label="User Job #3 Description"
+               default_data="User Job #3"
+               setting_type="global"
+               help_text="The Description for this User Job."   />
+      <setting data_type="string" value="UserJob3"
+               label="User Job #3 Command"
+               default_data=""
+               setting_type="global"
+               help_text="The command to run whenever this User Job
+                          number is scheduled." />
+      <setting data_type="string" value="UserJobDesc4"
+               label="User Job #4 Description"
+               default_data="User Job #4"
+               setting_type="global"
+               help_text="The Description for this User Job."   />
+      <setting data_type="string" value="UserJob4"
+               label="User Job #4 Command"
+               default_data=""
+               setting_type="global"
+               help_text="The command to run whenever this User Job
+                          number is scheduled." />
+    </group>
+    <group human_label="UPNP Server Settings"
+           unique_label="upnp_server_settings">
+<!--
+      <setting data_type="checkbox" value="UPnP/RecordingsUnderVideos"
+               label="Include Recordings in Video List" default_data="0"
+               setting_type="global"
+               help_text="If enabled, the master backend will include the
+                          list of recorded shows in the list of videos
+                          This is mainly to accommodate UPnP players which do not
+                          allow more than 1 video section."  />
+-->
+      <setting data_type="select" value="UPnP/WMPSource"
+               label="Video content to show a WMP Client"
+               default_data="0"
+               setting_type="global"
+               help_text="This forces us to show WMP clients
+                          either the Recordings tree or the Video tree
+                          when they request a list of videos ">
+        <option display="Recordings" data="0" />
+        <option display="Videos" data="1" />
+      </setting>
+      <setting data_type="select" value="UPnP/RebuildDelay"
+               label="UPnP Media Update Time"
+               setting_type="host"
+               help_text="The number of minutes between mythbackend checking
+                          for new videos to serve via upnp. 0 = Off. "
+               default_data="30">
+                <option display="30" data="30" />
+        <option display="Off" data="0" />
+        <option display="1" data="1" />
+        <option display="5" data="5" />
+        <option display="15" data="15" />
+        <option display="30" data="30" />
+        <option display="60" data="60" />
+        <option display="120" data="120" />
+        <option display="300" data="300" />
+        <option display="600" data="600" />
+        <option display="1440" data="1440" />
+      </setting>
+    </group>
+    <group human_label="Database Logging"
+           unique_label="database_logging">
+      <setting data_type="checkbox" value="LogEnabled"
+               label="Log MythTV events to database"
+               default_data="0"
+               setting_type="global"
+               help_text="If enabled, MythTV modules will send event
+                          details to the database, where they can be viewed with
+                          MythLog or periodically emailed to the administrator." />
+      <setting data_type="select" value="LogPrintLevel"
+               label="Log Print Threshold"
+               setting_type="host" default_data="-1"
+               help_text="This controls what messages will be printed
+                          out as well as being logged to the database.">
+        <option display="All Messages" data="8" />
+        <option display="Debug and Higher" data="7" />
+        <option display="Info and Higher" data="6" />
+        <option display="Notice and Higher" data="5" />
+        <option display="Warning and Higher" data="4" />
+        <option display="Error and Higher" data="3" />
+        <option display="Critical and Higher" data="2" />
+        <option display="Alert and Higher" data="1" />
+        <option display="Emergency Only" data="0" />
+        <option display="Disable Printed Output" data="-1" />
+      </setting>
+      <setting data_type="checkbox" value="LogCleanEnabled"
+               label="Automatic Log Cleaning Enabled" default_data="0"
+               setting_type="host"
+               help_text="This enables the periodic cleanup of the
+                          events stored in the Myth database (see 'Log MythTV
+                          events to database')." />
+      <setting data_type="select" value="LogCleanPeriod"
+               label="Log Cleanup Frequency (Days)" default_data="14"
+               setting_type="host"
+               help_text="The number of days between log cleanup runs.">
+        <option display="Never cleanup" data="0" />
+        <option display="1" data="1" />
+        <option display="2" data="2" />
+        <option display="4" data="4" />
+        <option display="7" data="7" />
+        <option display="14" data="14" />
+        <option display="30" data="30" />
+        <option display="60" data="60" />
+      </setting>
+      <setting data_type="select" value="LogCleanDays"
+               label="Number of days to keep acknowledged log entries"
+               default_data="14"
+               setting_type="host"
+               help_text="The number of days before a log entry that has been
+                          acknowledged will be deleted by the log cleanup
+                          process.">
+        <option display="Never cleanup" data="0" />
+        <option display="1" data="1" />
+        <option display="2" data="2" />
+        <option display="4" data="4" />
+        <option display="7" data="7" />
+        <option display="14" data="14" />
+        <option display="30" data="30" />
+        <option display="60" data="60" />
+      </setting>
+      <setting data_type="select" value="LogCleanMax"
+               label="Number of days to keep unacknowledged log entries"
+               default_data="30"
+               setting_type="host"
+               help_text="The number of days before a log entry that
+                          has NOT been acknowledged will be deleted by the log
+                          cleanup process.">
+        <option display="Never cleanup" data="0" />
+        <option display="1" data="1" />
+        <option display="2" data="2" />
+        <option display="4" data="4" />
+        <option display="7" data="7" />
+        <option display="14" data="14" />
+        <option display="30" data="30" />
+        <option display="60" data="60" />
+      </setting>
+      <setting data_type="select" value="LogMaxCount"
+               label="Maximum Number of Entries per Module"
+               default_data="100"
+               setting_type="host"
+               help_text="If there are more than this number of entries for a
+                          module, the oldest log entries will be deleted to
+                          reduce the count to this number.  Set to 0 to disable.">
+        <option display="Disabled" data="0" />
+        <option display="10" data="10" />
+        <option display="25" data="25" />
+        <option display="50" data="50" />
+        <option display="100" data="100" />
+        <option display="250" data="250" />
+        <option display="500" data="500" />
+      </setting>
+    </group>
+    <group human_label="Program Schedule Downloading Options"
+           unique_label="program_schedule_downloading_options">
+      <setting data_type="checkbox" value="MythFillEnabled"
+               label="Automatically run mythfilldatabase"
+               default_data="1"
+               setting_type="global"
+               help_text="This enables the automatic execution of
+                          mythfilldatabase." />
+      <setting data_type="string" value="MythFillDatabasePath"
+               setting_type="global"
+               label="mythfilldatabase Program"
+               default_data="mythfilldatabase"
+               help_text="Use 'mythfilldatabase' or the name of a custom
+                          script that will populate the program guide info
+                          for all your video sources." />
+      <setting data_type="string" value="MythFillDatabaseArgs"
+               setting_type="global"
+               label="mythfilldatabase Arguments"
+               default_data=""
+               help_text="Any arguments you want passed to the
+                          mythfilldatabase program." />
+      <setting data_type="string" value="MythFillDatabaseLog"
+               setting_type="global"
+               label="mythfilldatabase Log Path"
+               default_data=""
+               help_text="File or directory to use for logging
+                          output from the mythfilldatabase program.
+                          Leave blank to disable logging." />
+      <setting data_type="select" value="MythFillPeriod"
+               label="mythfilldatabase Run Frequency (Days)"
+               default_data="1"
+               setting_type="global"
+               help_text="The number of days between mythfilldatabase runs.">
+        <option display="1" data="1" />
+        <option display="2" data="2" />
+        <option display="3" data="3" />
+        <option display="4" data="4" />
+        <option display="5" data="5" />
+        <option display="6" data="6" />
+        <option display="7" data="7" />
+        <option display="8" data="8" />
+        <option display="9" data="9" />
+        <option display="10" data="10" />
+        <option display="20" data="20" />
+        <option display="30" data="30" />
+      </setting>
+
+      <setting data_type="select" value="MythFillMinHour"
+               label="mythfilldatabase Execution Start"
+               default_data="2"
+               setting_type="global"
+               help_text="This setting and the following one define a
+                          time period when the mythfilldatabase process is
+                          allowed to run.">
+        <option display="12 AM" data="0" />
+        <option display="1 AM"  data="1" />
+        <option display="2 AM"  data="2" />
+        <option display="3 AM"  data="3" />
+        <option display="4 AM"  data="4" />
+        <option display="5 AM"  data="5" />
+        <option display="6 AM"  data="6" />
+        <option display="7 AM"  data="7" />
+        <option display="8 AM"  data="8" />
+        <option display="9 AM"  data="9" />
+        <option display="10 AM" data="10" />
+        <option display="11 AM" data="11" />
+        <option display="12 PM" data="12" />
+        <option display="1 PM"  data="13" />
+        <option display="2 PM"  data="14" />
+        <option display="3 PM"  data="15" />
+        <option display="4 PM"  data="16" />
+        <option display="5 PM"  data="17" />
+        <option display="6 PM"  data="18" />
+        <option display="7 PM"  data="19" />
+        <option display="8 PM"  data="20" />
+        <option display="9 PM"  data="21" />
+        <option display="10 PM" data="22" />
+        <option display="11 PM" data="23" />
+      </setting>
+
+      <setting data_type="select" value="MythFillMaxHour"
+               label="mythfilldatabase Execution End"
+               default_data="5"
+               setting_type="global"
+               help_text="This setting and the preceding one define a
+                          time period when the mythfilldatabase process is
+                          allowed to run.">
+        <option display="12 AM" data="0" />
+        <option display="1 AM"  data="1" />
+        <option display="2 AM"  data="2" />
+        <option display="3 AM"  data="3" />
+        <option display="4 AM"  data="4" />
+        <option display="5 AM"  data="5" />
+        <option display="6 AM"  data="6" />
+        <option display="7 AM"  data="7" />
+        <option display="8 AM"  data="8" />
+        <option display="9 AM"  data="9" />
+        <option display="10 AM" data="10" />
+        <option display="11 AM" data="11" />
+        <option display="12 PM" data="12" />
+        <option display="1 PM"  data="13" />
+        <option display="2 PM"  data="14" />
+        <option display="3 PM"  data="15" />
+        <option display="4 PM"  data="16" />
+        <option display="5 PM"  data="17" />
+        <option display="6 PM"  data="18" />
+        <option display="7 PM"  data="19" />
+        <option display="8 PM"  data="20" />
+        <option display="9 PM"  data="21" />
+        <option display="10 PM" data="22" />
+        <option display="11 PM" data="23" />
+      </setting>
+      <setting data_type="checkbox" value="MythFillGrabberSuggestsTime"
+               label="Run mythfilldatabase at time suggested by the grabber."
+               default_data="1"
+               setting_type="global"
+               help_text="This setting allows a DataDirect guide data provider
+                          to specify the next download time in order to
+                          distribute load on their servers. If this setting is
+                          enabled, mythfilldatabase Execution Start/End times
+                          are ignored." />
+    </group>
+  </group>
+</config>
Index: mythtv/programs/mythbackend/mythsettings.cpp
===================================================================
--- mythtv/programs/mythbackend/mythsettings.cpp	(revision 0)
+++ mythtv/programs/mythbackend/mythsettings.cpp	(revision 0)
@@ -0,0 +1,534 @@
+#include <QNetworkInterface>
+#include <QDomDocument>
+#include <QFile>
+
+#include "channelsettings.h" // for ChannelTVFormat::GetFormats()
+#include "mythsettings.h"
+#include "frequencies.h"
+#include "mythcontext.h"
+#include "mythdb.h"
+
+static QString indent(uint level)
+{
+    QString ret;
+    for (uint i = 0; i < level; i++)
+        ret += "    ";
+    return ret;
+}
+
+static QString extract_query_list(
+    const MythSettingList &settings, MythSetting::SettingType stype)
+{
+    QString list;
+
+    MythSettingList::const_iterator it = settings.begin();
+    for (; it != settings.end(); ++it)
+    {
+        const MythSettingGroup *group =
+            dynamic_cast<const MythSettingGroup*>(*it);
+        if (group)
+        {
+            list += extract_query_list(group->settings, stype);
+            continue;
+        }
+        const MythSetting *setting = dynamic_cast<const MythSetting*>(*it);
+        if (setting && (setting->stype == stype))
+            list += QString(",'%1'").arg(setting->value);
+    }
+    if (!list.isEmpty() && (list[0] == QChar(',')))
+        list = list.mid(1);
+
+    return list;
+}
+
+static void fill_setting(
+    MythSettingBase *sb, const QMap<QString,QString> &map,
+    MythSetting::SettingType stype)
+{
+    const MythSettingGroup *group =
+        dynamic_cast<const MythSettingGroup*>(sb);
+    if (group)
+    {
+        MythSettingList::const_iterator it = group->settings.begin();
+        for (; it != group->settings.end(); ++it)
+            fill_setting(*it, map, stype);
+        return;
+    }
+
+    MythSetting *setting = dynamic_cast<MythSetting*>(sb);
+    if (setting && (setting->stype == stype))
+    {
+        QMap<QString,QString>::const_iterator it = map.find(setting->value);
+        if (it != map.end())
+            setting->data = *it;
+
+        bool do_option_check = false;
+        if (MythSetting::kLocalIPAddress == setting->dtype)
+        {
+            setting->data_list.clear();
+            setting->display_list.clear();
+            QList<QHostAddress> list = QNetworkInterface::allAddresses();
+            for (uint i = 0; i < (uint)list.size(); i++)
+            {
+                if (list[i].toString().contains(":"))
+                    continue; // ignore IP6 addresses for now
+                setting->data_list.push_back(list[i].toString());
+                setting->display_list.push_back(setting->data_list.back());
+            }
+            if (setting->data_list.isEmpty())
+                setting->data_list.push_back("127.0.0.1");
+            do_option_check = true;
+        }
+        else if (MythSetting::kSelect == setting->dtype)
+        {
+            do_option_check = true;
+        }
+        else if (MythSetting::kTVFormat == setting->dtype)
+        {
+            setting->data_list = setting->display_list =
+                ChannelTVFormat::GetFormats();
+            do_option_check = true;
+        }
+        else if (MythSetting::kFrequencyTable == setting->dtype)
+        {
+            setting->data_list.clear();
+            for (uint i = 0; chanlists[i].name; i++)
+                setting->data_list.push_back(chanlists[i].name);
+            setting->display_list = setting->data_list;
+            do_option_check = true;
+        }
+
+        if (do_option_check)
+        {
+            if (!setting->data_list.empty() &&
+                !setting->data_list.contains(setting->data.toLower(),
+                                             Qt::CaseInsensitive))
+            {
+                bool ok;
+                long long idata = setting->data.toLongLong(&ok);
+                if (ok)
+                {
+                    uint sel = 0;
+                    for (uint i = setting->data_list.size(); i >= 0; i--)
+                    {
+                        if (idata < setting->data_list[i].toLongLong())
+                            break;
+                        sel = i;
+                    }
+                    setting->data = setting->data_list[sel];
+                }
+                else
+                {
+                    setting->data =
+                        (setting->data_list.contains(
+                            setting->default_data, Qt::CaseInsensitive)) ?
+                        setting->default_data : setting->data_list[0];
+                }
+            }
+        }
+    }
+}
+
+static void fill_settings(
+    MythSettingList &settings, MSqlQuery &query, MythSetting::SettingType stype)
+{
+    QMap<QString,QString> map;
+    while (query.next())
+        map[query.value(0).toString()] = query.value(1).toString();
+
+    MythSettingList::const_iterator it = settings.begin();
+    for (; it != settings.end(); ++it)
+        fill_setting(*it, map, stype);
+}
+
+QString MythSettingGroup::ToHTML(uint depth) const
+{
+    QString ret;
+
+    ret = indent(depth) +
+        QString("<div class=\"group\" id=\"%1\">\r\n").arg(unique_label);
+    if (!human_label.isEmpty())
+    {
+        ret += indent(depth+1) + QString("<h%1>%2</h%3>\r\n")
+            .arg(depth+1).arg(human_label).arg(depth+1);
+    }
+
+    MythSettingList::const_iterator it = settings.begin();
+    for (; it != settings.end(); ++it)
+        ret += (*it)->ToHTML(depth+1);
+
+    ret += indent(depth) +"</div>";
+
+    return ret;
+}
+
+QString MythSetting::ToHTML(uint level) const
+{
+    QString ret = indent(level) +
+        QString("<div class=\"setting\" id=\"%1_div\">\r\n").arg(value);
+
+    switch (dtype)
+    {
+        case kInteger:
+        case kUnsignedInteger:
+        case kIntegerRange:
+        case kFloat:
+        case kComboBox:
+        case kIPAddress:
+        case kString:
+        case kTimeOfDay:
+        case kOther:
+            ret += indent(level) +
+                "<div class=\"setting_label\">" + label + "</div>\r\n";
+            ret += indent(level) +
+                QString("<input name=\"%1\" id=\"%2_input\" type=\"text\""
+                        " value=\"%3\"/>\r\n")
+                .arg(value).arg(value).arg(data);
+            ret += indent(level) +
+                QString("<div style=\"display:none;"
+                        "position:absolute;left:-4000px\" "
+                        "id=\"%1_default\">%2</div>\r\n")
+                .arg(value).arg(default_data);
+            break;
+        case kCheckBox:
+            ret += indent(level) +
+                "<div class=\"setting_label\">" + label + "</div>\r\n";
+            ret += indent(level) +
+                QString("<input name=\"%1\" id=\"%2_input\" type=\"checkbox\""
+                        " value=\"1\" %3/>\r\n")
+                .arg(value).arg(value).arg((data.toUInt()) ? "checked" : "");
+            ret += indent(level) +
+                QString("<div style=\"display:none;"
+                        "position:absolute;left:-4000px\" "
+                        "id=\"%1_default\">%2</div>\r\n")
+                .arg(value).arg(default_data);
+            break;
+        case kLocalIPAddress:
+        case kTVFormat:
+        case kFrequencyTable:
+        case kSelect:
+            ret +=  indent(level) +
+                "<div class=\"setting_label\">" + label + "</div>\r\n";
+            ret +=  indent(level) +
+                QString("<select name=\"%1\" id=\"%2_input\">\r\n")
+                .arg(value).arg(value);
+            for (uint i = 0; (i < (uint)data_list.size()) &&
+                     (i < (uint)display_list.size()); i++)
+            {
+                ret += indent(level+1) +
+                    QString("<option value=\"%1\" %2>%3</option>\r\n")
+                    .arg(data_list[i])
+                    .arg((data_list[i].toLower() == data.toLower()) ?
+                         "selected" : "")
+                    .arg(display_list[i]);
+            }
+            ret += indent(level) + "</select>\r\n";
+            ret += indent(level) +
+                QString("<div style=\"display:none;"
+                        "position:absolute;left:-4000px\" "
+                        "id=\"%1_default\">%2</div>\r\n")
+                .arg(value).arg(default_data);
+            break;
+    }
+
+    ret += indent(level) + "</div>\r\n";
+
+    return ret;
+}
+
+MythSetting::SettingType parse_setting_type(const QString &str)
+{
+    QString s = str.toLower();
+    if (s=="file")
+        return MythSetting::kFile;
+    if (s=="host")
+        return MythSetting::kHost;
+    if (s=="global")
+        return MythSetting::kGlobal;
+    return MythSetting::kInvalidSettingType;
+}
+
+MythSetting::DataType parse_data_type(const QString &str)
+{
+    QString s = str.toLower();
+    if (s == "integer")
+        return MythSetting::kInteger;
+    if (s == "unsigned")
+        return MythSetting::kUnsignedInteger;
+    if (s == "integer_range")
+        return MythSetting::kIntegerRange;
+    if (s == "checkbox")
+        return MythSetting::kCheckBox;
+    if (s == "select")
+        return MythSetting::kSelect;
+    if (s == "combobox")
+        return MythSetting::kComboBox;
+    if (s == "tvformat")
+        return MythSetting::kTVFormat;
+    if (s == "frequency_table")
+        return MythSetting::kFrequencyTable;
+    if (s == "float")
+        return MythSetting::kFloat;
+    if (s == "ipaddress")
+        return MythSetting::kIPAddress;
+    if (s == "localipaddress")
+        return MythSetting::kLocalIPAddress;
+    if (s == "string")
+        return MythSetting::kString;
+    if (s == "timeofday")
+        return MythSetting::kTimeOfDay;
+    if (s == "other")
+        return MythSetting::kOther;
+    VERBOSE(VB_IMPORTANT, QString("Unknown type: %1").arg(str));
+    return MythSetting::kInvalidDataType;
+}
+
+bool parse_dom(MythSettingList &settings, const QDomElement &element,
+               const QString &filename)
+{
+#define LOC QString("parse_dom(%1@~%2), error: ") \
+            .arg(filename).arg(e.lineNumber())
+
+    QDomNode n = element.firstChild();
+    while (!n.isNull())
+    {
+        const QDomElement e = n.toElement();
+        if (e.isNull())
+        {
+            n = n.nextSibling();
+            continue;
+        }
+
+        if (e.tagName() == "group")
+        {
+            QString human_label  = e.attribute("human_label");
+            QString unique_label = e.attribute("unique_label");
+            QString ecma_script  = e.attribute("ecma_script");
+
+            MythSettingGroup *g = new MythSettingGroup(
+                human_label, unique_label, ecma_script);
+
+            if (e.hasChildNodes() && !parse_dom(g->settings, e, filename))
+                return false;
+
+            settings.push_back(g);
+        }
+        else if (e.tagName() == "setting")
+        {
+            QMap<QString,QString> m;
+            m["value"]        = e.attribute("value");
+            m["setting_type"] = e.attribute("setting_type");
+            m["label"]        = e.attribute("label");
+            m["help_text"]    = e.attribute("help_text");
+            m["data_type"]    = e.attribute("data_type");
+
+            MythSetting::DataType dtype = parse_data_type(m["data_type"]);
+            if (MythSetting::kInvalidDataType == dtype)
+            {
+                VERBOSE(VB_IMPORTANT, LOC +
+                        "Setting has invalid or missing data_type attribute.");
+                return false;
+            }
+
+            QStringList data_list;
+            QStringList display_list;
+            if ((MythSetting::kComboBox == dtype) ||
+                (MythSetting::kSelect   == dtype))
+            {
+                if (!e.hasChildNodes())
+                {
+                    VERBOSE(VB_IMPORTANT, LOC +
+                            "Setting missing selection items.");
+                    return false;
+                }
+
+                QDomNode n2 = e.firstChild();
+                while (!n2.isNull())
+                {
+                    const QDomElement e2 = n2.toElement();
+                    if (e2.tagName() != "option")
+                    {
+                        VERBOSE(VB_IMPORTANT, LOC +
+                                "Setting selection contains invalid tags.");
+                        return false;
+                    }
+                    QString display = e2.attribute("display");
+                    QString data    = e2.attribute("data");
+                    if (data.isEmpty())
+                    {
+                        VERBOSE(VB_IMPORTANT, LOC +
+                                "Setting selection item missing data.");
+                        return false;
+                    }
+                    display = (display.isEmpty()) ? data : display;
+                    data_list.push_back(data);
+                    display_list.push_back(display);
+
+                    n2 = n2.nextSibling();
+                }
+            }
+
+            if (MythSetting::kIntegerRange == dtype)
+            {
+                m["range_min"] = e.attribute("range_min");
+                m["range_max"] = e.attribute("range_max");
+            }
+
+            QMap<QString,QString>::const_iterator it = m.begin();
+            for (; it != m.end(); ++it)
+            {
+                if ((*it).isEmpty())
+                {
+                    VERBOSE(VB_IMPORTANT, LOC +
+                            QString("Setting has invalid or missing "
+                                    "%1 attribute")
+                            .arg(it.key()));
+                    return false;
+                }
+            }
+
+            m["default_data"] = e.attribute("default_data");
+
+            MythSetting::SettingType stype =
+                parse_setting_type(m["setting_type"]);
+            if (MythSetting::kInvalidSettingType == stype)
+            {
+                VERBOSE(VB_IMPORTANT, LOC +
+                        "Setting has invalid setting_type attribute.");
+                return false;
+            }
+
+            long long range_min = m["range_min"].toLongLong();
+            long long range_max = m["range_max"].toLongLong();
+            if (range_max < range_min)
+            {
+                VERBOSE(VB_IMPORTANT, LOC +
+                        "Setting has invalid range attributes");
+                return false;
+            }
+
+            MythSetting *s = new MythSetting(
+                m["value"], m["default_data"], stype,
+                m["label"], m["help_text"], dtype,
+                data_list, display_list, range_min, range_max);
+
+            settings.push_back(s);
+        }
+        else
+        {
+            VERBOSE(VB_IMPORTANT, LOC +
+                    QString("Unknown element: %1").arg(e.tagName()));
+            return false;
+        }
+        n = n.nextSibling();
+    }
+    return true;
+#undef LOC
+}
+
+bool parse_settings(MythSettingList &settings, const QString &filename)
+{
+    QDomDocument doc;
+    QFile f(filename);
+
+    if (!f.open(QIODevice::ReadOnly))
+    {
+        VERBOSE(VB_IMPORTANT, QString("parse_settings: Can't open: '%1'")
+                .arg(filename));
+        return false;
+    }
+
+    QString errorMsg;
+    int errorLine = 0;
+    int errorColumn = 0;
+
+    if (!doc.setContent(&f, false, &errorMsg, &errorLine, &errorColumn))
+    {
+        VERBOSE(VB_IMPORTANT, QString("parse_settings: ") +
+                QString("Parsing: %1 at line: %2 column: %3")
+                .arg(filename).arg(errorLine).arg(errorColumn) +
+                QString("\n\t\t\t%1").arg(errorMsg));
+        f.close();
+        return false;
+    }
+    f.close();
+
+    settings.clear();
+    return parse_dom(settings, doc.documentElement(), filename);
+}
+
+bool load_settings(MythSettingList &settings, const QString &hostname)
+{
+    MSqlQuery query(MSqlQuery::InitCon());
+
+    QString list = extract_query_list(settings, MythSetting::kFile);
+    if (!list.isEmpty())
+    {
+        DatabaseParams params;
+        bool ok = MythDB::LoadDatabaseParamsFromDisk(params, true);
+        if (!ok)
+            return false;
+
+        QMap<QString,QString> map;
+        map["host"]                = params.dbHostName;
+        map["port"] = QString::number(params.dbPort);
+        map["ping"] = QString::number(params.dbHostPing);
+        map["database"]            = params.dbName;
+        map["user"]                = params.dbUserName;
+        map["password"]            = params.dbPassword;
+        map["uniqueid"]            = params.localHostName;
+        map["wol_enabled"]         =
+            QString::number(params.wolEnabled);
+        map["wol_reconnect_count"] =
+            QString::number(params.wolReconnect);
+        map["wol_retry_count "]    =
+            QString::number(params.wolRetry);
+        map["wol_command"]         = params.wolCommand;
+
+        MythSettingList::const_iterator it = settings.begin();
+        for (; it != settings.end(); ++it)
+            fill_setting(*it, map, MythSetting::kFile);
+    }
+
+    list = extract_query_list(settings, MythSetting::kHost);
+    QString qstr =
+        "SELECT value, data "
+        "FROM settings "
+        "WHERE hostname = '" + hostname + "' AND "
+        "      value in (" + list + ")";
+
+    if (!list.isEmpty())
+    {
+        if (!query.exec(qstr))
+        {
+            MythDB::DBError("HttpConfig::LoadMythSettings() 1", query);
+            return false;
+        }
+        fill_settings(settings, query, MythSetting::kHost);
+    }
+
+    list = extract_query_list(settings, MythSetting::kGlobal);
+    qstr =
+        "SELECT value, data "
+        "FROM settings "
+        "WHERE hostname IS NULL AND "
+        "      value in (" + list + ")";
+    
+    if (!list.isEmpty())
+    {
+        if (!query.exec(qstr))
+        {
+            MythDB::DBError("HttpConfig::LoadMythSettings() 2", query);
+            return false;
+        }
+        fill_settings(settings, query, MythSetting::kGlobal);
+    }
+
+    return true;
+}
+
+bool check_settings(MythSettingList &database_settings,
+                    const QMap<QString,QString> &params)
+{
+    // TODO
+}
Index: mythtv/programs/mythbackend/httpconfig.cpp
===================================================================
--- mythtv/programs/mythbackend/httpconfig.cpp	(revision 0)
+++ mythtv/programs/mythbackend/httpconfig.cpp	(revision 0)
@@ -0,0 +1,168 @@
+// Qt headers
+#include <QTextStream>
+
+// MythTV headers
+#include "httpconfig.h"
+#include "backendutil.h"
+#include "mythxml.h"
+#include "mythcontext.h"
+#include "mythdb.h"
+#include "mythdirs.h"
+
+HttpConfig::HttpConfig() : HttpServerExtension("HttpConfig", QString())
+{
+}
+
+HttpConfig::~HttpConfig()
+{
+}
+
+bool HttpConfig::ProcessRequest(HttpWorkerThread*, HTTPRequest *request)
+{
+    if (!request)
+        return false;
+
+    VERBOSE(VB_IMPORTANT, QString("ProcessRequest '%1' '%2'")
+            .arg(request->m_sBaseUrl).arg(request->m_sMethod));
+
+    if (request->m_sBaseUrl != "/" &&
+        request->m_sBaseUrl.left(7) != "/config")
+    {
+        return false;
+    }
+
+    bool handled = false;
+    if (request->m_sMethod.toLower() == "save")
+    {
+        if (request->m_sBaseUrl.right(7) == "config" &&
+            !database_settings.empty())
+        {
+            PrintHeader(request->m_response, "config");
+            check_settings(database_settings, request->m_mapParams);
+            load_settings(database_settings, "");
+            PrintSettings(request->m_response, database_settings);
+            PrintFooter(request->m_response);
+            handled = true;
+        }
+        else
+        {
+            request->m_response << "<html><body><dl>";
+            QStringMap::const_iterator it = request->m_mapParams.begin();
+            for (; it!=request->m_mapParams.end(); ++it)
+            {
+                request->m_response << "<dt>"<<it.key()<<"</dt><dd>"
+                                    <<*it<<"</dd>\r\n";
+            }
+            request->m_response << "</dl></body></html>";
+            handled = true;
+        }
+    }
+
+    if ((request->m_sMethod.toLower() == "config") || (NULL == gContext))
+    {
+        PrintHeader(request->m_response, "config");
+        QString fn = GetShareDir() + "backend-config/"
+            "config_backend_database.xml";
+        parse_settings(database_settings, fn);
+        load_settings(database_settings, "");
+        PrintSettings(request->m_response, database_settings);
+        PrintFooter(request->m_response);
+        handled = true;
+    }
+    else if (request->m_sMethod.toLower() == "general")
+    {
+        PrintHeader(request->m_response, "config/general");
+        QString fn = GetShareDir() + "backend-config/"
+            "config_backend_general.xml";
+        parse_settings(general_settings, fn);
+        load_settings(general_settings, gCoreContext->GetHostName());
+        PrintSettings(request->m_response, general_settings);
+        PrintFooter(request->m_response);
+        handled = true;
+    }
+
+    if (handled)
+    {
+        request->m_eResponseType = ResponseTypeHTML;
+        request->m_mapRespHeaders[ "Cache-Control" ] =
+            "no-cache=\"Ext\", max-age = 0";
+    }
+
+    return handled;
+}
+
+void HttpConfig::PrintHeader(QTextStream &os, const QString &form)
+{
+    os.setCodec("UTF-8");
+
+    os << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
+       << "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n"
+       << "<html xmlns=\"http://www.w3.org/1999/xhtml\""
+       << " xml:lang=\"en\" lang=\"en\">\r\n"
+       << "<head>\r\n"
+       << "  <meta http-equiv=\"Content-Type\"\r\n"
+       << "        content=\"text/html; charset=UTF-8\" />\r\n"
+       << "  <style type=\"text/css\" title=\"Default\" media=\"all\">\r\n"
+       << "  body {\r\n"
+       << "    background-color:#fff;\r\n"
+       << "    font:11px verdana, arial, helvetica, sans-serif;\r\n"
+       << "    margin:20px;\r\n"
+       << "  }\r\n"
+       << "  h1 {\r\n"
+       << "    font-size:28px;\r\n"
+       << "    font-weight:900;\r\n"
+       << "    color:#ccc;\r\n"
+       << "    letter-spacing:0.5em;\r\n"
+       << "    margin-bottom:30px;\r\n"
+       << "    width:650px;\r\n"
+       << "    text-align:center;\r\n"
+       << "  }\r\n"
+       << "  h2 {\r\n"
+       << "    font-size:18px;\r\n"
+       << "    font-weight:800;\r\n"
+       << "    color:#360;\r\n"
+       << "    border:none;\r\n"
+       << "    letter-spacing:0.3em;\r\n"
+       << "    padding:0px;\r\n"
+       << "    margin-bottom:10px;\r\n"
+       << "    margin-top:0px;\r\n"
+       << "  }\r\n"
+       << "  h3 {\r\n"
+       << "    font-size:14px;\r\n"
+       << "    font-weight:800;\r\n"
+       << "    color:#360;\r\n"
+       << "    border:none;\r\n"
+       << "    letter-spacing:0.3em;\r\n"
+       << "    padding:0px;\r\n"
+       << "    margin-bottom:10px;\r\n"
+       << "    margin-top:0px;\r\n"
+       << "  }\r\n"
+       << "  </style>\r\n"
+       << "  <title>MythTV Config</title>"
+       << "</head>\r\n"
+       << "<body>\r\n\r\n"
+       << "  <h1>MythTV Configuration</h1>\r\n"
+       << "  <form action=\"/" << form << "/save\" method=\"POST\">\r\n"
+       << "    <div class=\"form_buttons_top\"\r\n"
+       << "         id=\"form_buttons_top\">\r\n"
+       << "      <input type=\"submit\" value=\"Save Changes\" />\r\n"
+       << "    </div>\r\n";
+}
+
+void HttpConfig::PrintFooter(QTextStream &os)
+{
+    os << "    <div class=\"form_buttons_bottom\"\r\n"
+       << "         id=\"form_buttons_bottom\">\r\n"
+       << "      <input type=\"submit\" value=\"Save Changes\" />\r\n"
+       << "    </div>\r\n"
+       << "  </form>\r\n"
+       << "</body>\r\n"
+       << "</html>\r\n";
+}
+
+void HttpConfig::PrintSettings(QTextStream &os, const MythSettingList &settings)
+{
+    MythSettingList::const_iterator it = settings.begin();
+    for (; it != settings.end(); ++it)
+        os << (*it)->ToHTML(1);
+}
Index: mythtv/programs/mythbackend/main_helpers.cpp
===================================================================
--- mythtv/programs/mythbackend/main_helpers.cpp	(revision 27319)
+++ mythtv/programs/mythbackend/main_helpers.cpp	(working copy)
@@ -312,17 +312,6 @@
 
 }
 
-void showUsage(const MythCommandLineParser &cmdlineparser, const QString &version)
-{
-    QString    help  = cmdlineparser.GetHelpString(false);
-    QByteArray ahelp = help.toLocal8Bit();
-
-    cerr << qPrintable(version) << endl <<
-    "Valid options are: " << endl <<
-    "-h or --help                   List valid command line parameters"
-         << endl << ahelp.constData() << endl;
-}
-
 void setupLogfile(void)
 {
     if (!logfile.isEmpty())
@@ -683,7 +672,7 @@
 
     bool ismaster = gCoreContext->IsMasterHost();
 
-    g_pUPnp = new MediaServer(ismaster, !cmdline.IsUPnPEnabled() );
+    g_pUPnp->Init(ismaster, cmdline.IsUPnPEnabled());
 
     if (!ismaster)
     {
Index: mythtv/programs/mythbackend/mythbackend.pro
===================================================================
--- mythtv/programs/mythbackend/mythbackend.pro	(revision 27319)
+++ mythtv/programs/mythbackend/mythbackend.pro	(working copy)
@@ -22,12 +22,14 @@
 HEADERS += playbacksock.h scheduler.h server.h housekeeper.h backendutil.h
 HEADERS += upnpcdstv.h upnpcdsmusic.h upnpcdsvideo.h mediaserver.h
 HEADERS += mythxml.h upnpmedia.h main_helpers.h backendcontext.h
+HEADERS += httpconfig.h mythsettings.h
 
 SOURCES += autoexpire.cpp encoderlink.cpp filetransfer.cpp httpstatus.cpp
 SOURCES += main.cpp mainserver.cpp playbacksock.cpp scheduler.cpp server.cpp
 SOURCES += housekeeper.cpp backendutil.cpp
 SOURCES += upnpcdstv.cpp upnpcdsmusic.cpp upnpcdsvideo.cpp mediaserver.cpp
 SOURCES += mythxml.cpp upnpmedia.cpp main_helpers.cpp backendcontext.cpp
+SOURCES += httpconfig.cpp mythsettings.cpp
 
 using_oss:DEFINES += USING_OSS
 
@@ -35,3 +37,7 @@
 
 using_valgrind:DEFINES += USING_VALGRIND
 
+xml_conf.path = $${PREFIX}/share/mythtv/backend-config/
+xml_conf.files = config_backend_general.xml config_backend_database.xml
+
+INSTALLS += xml_conf
Index: mythtv/programs/mythbackend/mediaserver.h
===================================================================
--- mythtv/programs/mythbackend/mediaserver.h	(revision 27319)
+++ mythtv/programs/mythbackend/mediaserver.h	(working copy)
@@ -39,7 +39,8 @@
         QString          m_sSharePath;
 
     public:
-        explicit MediaServer( bool bMaster, bool bDisableUPnp = false );
+        explicit MediaServer();
+        void Init(bool bMaster, bool bDisableUPnp = false);
 
         virtual ~MediaServer();
 
Index: mythtv/programs/mythbackend/mainserver.cpp
===================================================================
--- mythtv/programs/mythbackend/mainserver.cpp	(revision 27319)
+++ mythtv/programs/mythbackend/mainserver.cpp	(working copy)
@@ -521,6 +521,14 @@
         else
             HandleRecorderQuery(listline, tokens, pbs);
     }
+    else if (command == "QUERY_RECORDING_DEVICE")
+    {
+        // TODO
+    }
+    else if (command == "QUERY_RECORDING_DEVICES")
+    {
+        // TODO
+    }
     else if (command == "SET_NEXT_LIVETV_DIR")
     {
         if (tokens.size() != 3)
Index: mythtv/programs/mythbackend/config_backend_database.xml
===================================================================
--- mythtv/programs/mythbackend/config_backend_database.xml	(revision 0)
+++ mythtv/programs/mythbackend/config_backend_database.xml	(revision 0)
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<config>
+  <group human_label="Database Setup" unique_label="database">
+    <setting setting_type="file" value="host" default_data="localhost"
+             label="Host" data_type="string"
+             help_text="DNS name or IP of server containing database or
+                        'localhost' which will connect to the server using
+                        a unix pipe." />
+    <setting setting_type="file" value="port" default_data="3306" label="Port"
+             help_text="Port on which the remote database server listens."
+             data_type="integer_range" range_min="0" range_max="0xffff" />
+    <setting setting_type="file" value="ping" default_data="1" label="Ping"
+             help_text="Ping the remote server." data_type="checkbox" />
+    <setting setting_type="file" value="database" default_data="mythconverg"
+             label="Database" data_type="string"
+             help_text="Database containing MythTV tables." />
+    <setting setting_type="file" value="user" default_data="mythtv"
+             label="User" data_type="string"
+             help_text="Database user name with read and write
+                        access to MythTV tables" />
+    <setting setting_type="file" value="password" default_data="mythtv"
+             label="Password" data_type="string"
+             help_text="Password for database user." />
+    <group human_label="Database Wake on LAN" default_data="database_wol">
+      <setting setting_type="file" value="wol_enabled" default_data="1"
+               label="Enabled" data_type="checkbox"
+               help_text="If checked MythTV will attempt to wake the
+                          remote database host." />
+      <setting setting_type="file" value="wol_reconnect_count" default_data="0"
+               label="Reconnect Count"
+               data_type="integer_range" range_min="0" range_max="10"
+               help_text="How often to attempt reconnecting to the database." />
+      <setting setting_type="file" value="wol_retry_count" default_data="5"
+               label="Retry Count"
+               data_type="integer_range" range_min="0" range_max="10"
+               help_text="How often to attempt to wake the remote
+                          database host." />
+      <setting setting_type="file" value="wol_command"
+               default_data="echo 'WOLsqlServerCommand not set'"
+               label="Command" data_type="string"
+               help_text="Command to execute to wake the
+                          remote database host." />
+    </group>
+  </group>
+</config>
