00001
00002 #include <QByteArray>
00003 #include <QDir>
00004 #include <QFileInfo>
00005 #include <QTextStream>
00006 #include <QUrl>
00007
00008
00009 #include "httpconfig.h"
00010 #include "backendutil.h"
00011 #include "mythcontext.h"
00012 #include "mythdb.h"
00013 #include "mythdirs.h"
00014 #include "storagegroup.h"
00015 #include "mythdownloadmanager.h"
00016 #include "mythcoreutil.h"
00017
00018 HttpConfig::HttpConfig() : HttpServerExtension("HttpConfig", QString())
00019 {
00020 }
00021
00022 HttpConfig::~HttpConfig()
00023 {
00024 }
00025
00026 QStringList HttpConfig::GetBasePaths()
00027 {
00028 QStringList paths;
00029 paths << "/Config";
00030 paths << "/Config/Database";
00031 paths << "/Config/General";
00032 return paths;
00033 }
00034
00035 bool HttpConfig::ProcessRequest(HTTPRequest *request)
00036 {
00037 if (!request)
00038 return false;
00039
00040 LOG(VB_UPNP, LOG_INFO,
00041 QString("HttpConfig::ProcessRequest(): m_sBaseURL: '%1',"
00042 "m_sMethod: '%2'")
00043 .arg(request->m_sBaseUrl).arg(request->m_sMethod));
00044 if (!request->m_sBaseUrl.startsWith("/Config"))
00045 {
00046 return false;
00047 }
00048
00049 bool handled = false;
00050 if (request->m_sMethod == "Save")
00051 {
00052 {
00053
00054
00055 QTextStream os(&request->m_response);
00056 os << "<html>\r\n"
00057 " <head>\r\n"
00058 " <title>Saving is Disabled</title>\r\n"
00059 " </head>\r\n"
00060 " <body>\r\n"
00061 " <b>Saving is Disabled</b><br>\r\n"
00062 " </body>\r\n"
00063 "</html>\r\n";
00064
00065 request->m_eResponseType = ResponseTypeHTML;
00066 request->m_mapRespHeaders[ "Cache-Control" ] =
00067 "no-cache=\"Ext\", max-age = 0";
00068
00069 return true;
00070
00071
00072 }
00073
00074
00075 if (request->m_sBaseUrl.right(7) == "config" &&
00076 !database_settings.empty())
00077 {
00078 QString checkResult;
00079 PrintHeader(request->m_response, "/Config/Database");
00080 check_settings(database_settings, request->m_mapParams,
00081 checkResult);
00082 load_settings(database_settings, "");
00083 PrintSettings(request->m_response, database_settings);
00084 PrintFooter(request->m_response);
00085 handled = true;
00086 }
00087 else
00088 {
00089 bool okToSave = false;
00090 QString checkResult;
00091 QString fn = GetShareDir() + "backend-config/";
00092
00093 if (request->m_sBaseUrl == "/Config/Database")
00094 {
00095 if (check_settings(database_settings, request->m_mapParams,
00096 checkResult))
00097 okToSave = true;
00098 }
00099 else if (request->m_sBaseUrl == "/Config/General")
00100 {
00101 if (check_settings(general_settings, request->m_mapParams,
00102 checkResult))
00103 okToSave = true;
00104 }
00105
00106 if (okToSave)
00107 LOG(VB_UPNP, LOG_INFO, "HTTP method 'Save' called, but not handled");
00108 #if 0
00109 QTextStream os(&request->m_response);
00110 os << "<html><body><h3>The Save function for this screen is "
00111 << "not hooked up yet</h3><dl>";
00112 QStringMap::const_iterator it = request->m_mapParams.begin();
00113 for (; it!=request->m_mapParams.end(); ++it)
00114 {
00115 if (it.key() == "__group__")
00116 continue;
00117
00118 os << "<dt>"<<it.key()<<"</dt><dd>"
00119 <<*it<<"</dd>\r\n";
00120 }
00121 os << "</dl></body></html>";
00122 handled = true;
00123 #else
00124 QTextStream os(&request->m_response);
00125 os << checkResult;
00126 request->m_eResponseType = ResponseTypeOther;
00127 request->m_sResponseTypeText = "application/json";
00128 request->m_mapRespHeaders[ "Cache-Control" ] =
00129 "no-cache=\"Ext\", max-age = 0";
00130
00131 return true;
00132 #endif
00133 }
00134 }
00135 else if (request->m_sMethod == "Settings")
00136 {
00137 QString result = "{ \"Error\": \"Unknown Settings List\" }";
00138 QString fn = GetShareDir() + "backend-config/";
00139
00140 if (request->m_sBaseUrl == "/Config/Database")
00141 {
00142 fn += "config_backend_database.xml";
00143 parse_settings(database_settings, fn);
00144 result = StringMapToJSON(
00145 GetSettingsMap(database_settings, gCoreContext->GetHostName()));
00146 }
00147 else if (request->m_sBaseUrl == "/Config/General")
00148 {
00149 fn += "config_backend_general.xml";
00150 parse_settings(general_settings, fn);
00151 result = StringMapToJSON(
00152 GetSettingsMap(general_settings, gCoreContext->GetHostName()));
00153 }
00154
00155 QTextStream os(&request->m_response);
00156 os << result;
00157 request->m_eResponseType = ResponseTypeOther;
00158 request->m_sResponseTypeText = "application/json";
00159 request->m_mapRespHeaders[ "Cache-Control" ] =
00160 "no-cache=\"Ext\", max-age = 0";
00161
00162 return true;
00163 }
00164 else if (request->m_sMethod == "XML")
00165 {
00166 QString fn = GetShareDir() + "backend-config/";
00167
00168 if (request->m_sBaseUrl == "/Config/Database")
00169 fn += "config_backend_database.xml";
00170 else if (request->m_sBaseUrl == "/Config/General")
00171 fn += "config_backend_general.xml";
00172
00173 request->FormatFileResponse(fn);
00174 return true;
00175 }
00176 else if ((request->m_sMethod == "InstallPackage") &&
00177 (request->m_mapParams.contains("package")))
00178 {
00179 QString package = QUrl::fromPercentEncoding(request->m_mapParams["package"].toUtf8());
00180 QString url = QString("http://www.mythtv.org/ftp/3rdParty/%1").arg(package);
00181 StorageGroup tmpGroup("Temp", gCoreContext->GetHostName());
00182 QString tmpFile = tmpGroup.GetFirstDir(true) + "package.zip";
00183 StorageGroup destGroup("3rdParty", gCoreContext->GetHostName());
00184 QString outDir = destGroup.GetFirstDir();
00185
00186 QString result = "false";
00187 if ((GetMythDownloadManager()->download(url, tmpFile)) &&
00188 (extractZIP(tmpFile, outDir)))
00189 {
00190 result = "true";
00191 }
00192
00193 QTextStream os(&request->m_response);
00194 os << StringListToJSON("Result", QStringList(result));
00195
00196 request->m_eResponseType = ResponseTypeOther;
00197 request->m_sResponseTypeText = "application/json";
00198 request->m_mapRespHeaders[ "Cache-Control" ] =
00199 "no-cache=\"Ext\", max-age = 0";
00200
00201 return true;
00202 }
00203 else if ((request->m_sMethod == "FileBrowser") &&
00204 (request->m_mapParams.contains("dir")))
00205 {
00206 QString startingDir = QUrl::fromPercentEncoding(request->m_mapParams["dir"].toUtf8());
00207 if (startingDir.startsWith("myth://"))
00208 {
00209 QUrl qurl(startingDir);
00210 QString dir;
00211
00212 QString host = qurl.host();
00213 int port = qurl.port();
00214
00215 dir = qurl.path();
00216
00217 QString storageGroup = qurl.userName();
00218
00219 StorageGroup sgroup(storageGroup);
00220 QStringList entries = sgroup.GetFileInfoList(dir);
00221
00222 if ((entries.size() == 1) &&
00223 (entries[0].startsWith("sgdir::")))
00224 {
00225 QStringList parts = entries[0].split("::");
00226 entries = sgroup.GetFileInfoList(parts[1]);
00227 }
00228
00229 if (entries.size())
00230 {
00231 QTextStream os(&request->m_response);
00232 os << "<ul class=\"jqueryFileTree\" style=\"display: none;\">\r\n";
00233
00234 for (QStringList::iterator it = entries.begin();
00235 it != entries.end(); ++it)
00236 {
00237 QString entry = *it;
00238 QStringList parts = entry.split("::");
00239 QFileInfo fi(parts[1]);
00240 if (dir == "/")
00241 dir = "";
00242 QString path =
00243 gCoreContext->GenMythURL(host,
00244 port,
00245 dir + parts[1],
00246 storageGroup);
00247 if (entry.startsWith("sgdir::"))
00248 {
00249 os << " <li class=\"directory collapsed\"><a href=\"#\" rel=\""
00250 << path << "/\">" << parts[1] << "</a></li>\r\n";
00251 }
00252 else if (entry.startsWith("dir::"))
00253 {
00254 os << " <li class=\"directory collapsed\"><a href=\"#\" rel=\""
00255 << path << "/\">" << fi.fileName() << "</a></li>\r\n";
00256 }
00257 else if (entry.startsWith("file::"))
00258 {
00259 os << " <li class=\"file ext_" << fi.suffix() << "\"><a href=\"#\" rel=\""
00260 << parts[3] << "\">" << fi.fileName() << "</a></li>\r\n";
00261 }
00262 }
00263 os << "</ul>\r\n";
00264
00265 handled = true;
00266 }
00267 } else {
00268 QDir dir(startingDir);
00269 if (dir.exists())
00270 {
00271 QTextStream os(&request->m_response);
00272 os << "<ul class=\"jqueryFileTree\" style=\"display: none;\">\r\n";
00273
00274 QFileInfoList infoList = dir.entryInfoList();
00275 for (QFileInfoList::iterator it = infoList.begin();
00276 it != infoList.end();
00277 ++it )
00278 {
00279 QFileInfo &fi = *it;
00280 if (!fi.isDir())
00281 continue;
00282 if (fi.fileName().startsWith("."))
00283 continue;
00284
00285 os << " <li class=\"directory collapsed\"><a href=\"#\" rel=\""
00286 << fi.absoluteFilePath() << "/\">" << fi.fileName() << "</a></li>\r\n";
00287 }
00288
00289 bool dirsOnly = true;
00290 if (request->m_mapParams.contains("dirsOnly"))
00291 dirsOnly = request->m_mapParams["dirsOnly"].toInt();
00292
00293 if (!dirsOnly)
00294 {
00295 for (QFileInfoList::iterator it = infoList.begin();
00296 it != infoList.end();
00297 ++it )
00298 {
00299 QFileInfo &fi = *it;
00300 if (fi.isDir())
00301 continue;
00302 if (fi.fileName().startsWith("."))
00303 continue;
00304
00305 os << " <li class=\"file ext_" << fi.suffix() << "\"><a href=\"#\" rel=\""
00306 << fi.absoluteFilePath() << "\">" << fi.fileName() << "</a></li>\r\n";
00307 }
00308 }
00309 os << "</ul>\r\n";
00310
00311 handled = true;
00312 }
00313 }
00314 }
00315 else if ((request->m_sMethod == "GetValueList") &&
00316 (request->m_mapParams.contains("List")))
00317 {
00318 QString key = request->m_mapParams["List"];
00319 QStringList sList = GetSettingValueList(key);
00320 QTextStream os(&request->m_response);
00321 os << StringListToJSON(key, sList);
00322
00323 request->m_eResponseType = ResponseTypeOther;
00324 request->m_sResponseTypeText = "application/json";
00325 request->m_mapRespHeaders[ "Cache-Control" ] =
00326 "no-cache=\"Ext\", max-age = 0";
00327
00328 return true;
00329 }
00330 else if ((request->m_sMethod == "Database") || (NULL == gContext))
00331 {
00332 QString fn = GetShareDir() + "backend-config/"
00333 "config_backend_database.xml";
00334 QString group;
00335 QString form("/Config/Database/Save");
00336
00337 if (request->m_mapParams.contains("__group__"))
00338 group = request->m_mapParams["__group__"];
00339
00340 if (group.isEmpty())
00341 PrintHeader(request->m_response, form);
00342 else
00343 OpenForm(request->m_response, form, group);
00344
00345 parse_settings(general_settings, fn, group);
00346 load_settings(general_settings, gCoreContext->GetHostName());
00347 PrintSettings(request->m_response, general_settings);
00348
00349 if (group.isEmpty())
00350 PrintFooter(request->m_response);
00351 else
00352 CloseForm(request->m_response, group);
00353
00354 handled = true;
00355 }
00356 else if (request->m_sMethod == "General")
00357 {
00358 QString fn = GetShareDir() + "backend-config/"
00359 "config_backend_general.xml";
00360 QString group;
00361 QString form("/Config/General/Save");
00362
00363 if (request->m_mapParams.contains("__group__"))
00364 group = request->m_mapParams["__group__"];
00365
00366 if (group.isEmpty())
00367 PrintHeader(request->m_response, form);
00368 else
00369 OpenForm(request->m_response, form, group);
00370
00371 parse_settings(general_settings, fn, group);
00372 load_settings(general_settings, gCoreContext->GetHostName());
00373 PrintSettings(request->m_response, general_settings);
00374
00375 if (group.isEmpty())
00376 PrintFooter(request->m_response);
00377 else
00378 CloseForm(request->m_response, group);
00379
00380 handled = true;
00381 }
00382
00383 if (handled)
00384 {
00385 request->m_eResponseType = ResponseTypeHTML;
00386 request->m_mapRespHeaders[ "Cache-Control" ] =
00387 "no-cache=\"Ext\", max-age = 0";
00388 }
00389
00390 return handled;
00391 }
00392
00393 void HttpConfig::PrintHeader(QBuffer &buffer, const QString &form,
00394 const QString &group)
00395 {
00396 QTextStream os(&buffer);
00397
00398 os.setCodec("UTF-8");
00399
00400 os << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
00401 << "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n"
00402 << "<html xmlns=\"http://www.w3.org/1999/xhtml\""
00403 << " xml:lang=\"en\" lang=\"en\">\r\n"
00404 << "<head>\r\n"
00405 << " <meta http-equiv=\"Content-Type\"\r\n"
00406 << " content=\"text/html; charset=UTF-8\" />\r\n"
00407 << " <link rel=\"stylesheet\" href=\"/setup/css/Config.css\" type=\"text/css\">\r\n"
00408 << " <title>MythTV Config</title>"
00409 << "</head>\r\n"
00410 << "<body>\r\n\r\n"
00411 << "<div class=\"config\">\r\n"
00412 << " <h1 class=\"config\">MythTV Configuration</h1>\r\n";
00413
00414 OpenForm(buffer, form, group);
00415 }
00416
00417 void HttpConfig::OpenForm(QBuffer &buffer, const QString &form,
00418 const QString &group)
00419 {
00420 QTextStream os(&buffer);
00421
00422 os.setCodec("UTF-8");
00423
00424 os << " <form id=\"config_form_" << group << "\">\r\n"
00425 << " <input type=\"hidden\" id=\"__config_form_action__\" value=\"" << form << "\" />\r\n"
00426 << " <input type=\"hidden\" id=\"__group__\" value=\"" << group << "\" />\r\n";
00427 }
00428
00429 void HttpConfig::CloseForm(QBuffer &buffer, const QString &group)
00430 {
00431 QTextStream os(&buffer);
00432
00433
00434
00435 os << " <input type=\"button\" value=\"Save Changes\" onClick=\"javascript:submitConfigForm('" << group << "')\" />\r\n"
00436
00437 << " </form>\r\n";
00438 }
00439
00440 void HttpConfig::PrintFooter(QBuffer &buffer, const QString &group)
00441 {
00442 CloseForm(buffer, group);
00443
00444 QTextStream os(&buffer);
00445
00446 os << "</div>\r\n"
00447 << "</body>\r\n"
00448 << "</html>\r\n";
00449 }
00450
00451 void HttpConfig::PrintSettings(QBuffer &buffer, const MythSettingList &settings)
00452 {
00453 QTextStream os(&buffer);
00454
00455 MythSettingList::const_iterator it = settings.begin();
00456 for (; it != settings.end(); ++it)
00457 os << (*it)->ToHTML(1);
00458 }