00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "backends/networking/sdl_net/handlers/filespagehandler.h"
00024 #include "backends/networking/sdl_net/handlerutils.h"
00025 #include "backends/networking/sdl_net/localwebserver.h"
00026 #include "common/config-manager.h"
00027 #include "common/translation.h"
00028
00029 namespace Networking {
00030
00031 #define INDEX_PAGE_NAME ".index.html"
00032 #define FILES_PAGE_NAME ".files.html"
00033
00034 FilesPageHandler::FilesPageHandler() {}
00035
00036 FilesPageHandler::~FilesPageHandler() {}
00037
00038 namespace {
00039 Common::String encodeDoubleQuotes(Common::String s) {
00040 Common::String result = "";
00041 for (uint32 i = 0; i < s.size(); ++i)
00042 if (s[i] == '"') {
00043 result += "\\\"";
00044 } else {
00045 result += s[i];
00046 }
00047 return result;
00048 }
00049
00050 Common::String encodeHtmlEntities(Common::String s) {
00051 Common::String result = "";
00052 for (uint32 i = 0; i < s.size(); ++i)
00053 if (s[i] == '<')
00054 result += "<";
00055 else if (s[i] == '>')
00056 result += ">";
00057 else if (s[i] == '&')
00058 result += "&";
00059 else if (s[i] > (byte)0x7F)
00060 result += Common::String::format("&#%d;", (int)s[i]);
00061 else result += s[i];
00062 return result;
00063 }
00064
00065 Common::String getDisplayPath(Common::String s) {
00066 Common::String result = "";
00067 for (uint32 i = 0; i < s.size(); ++i)
00068 if (s[i] == '\\')
00069 result += '/';
00070 else
00071 result += s[i];
00072 if (result == "")
00073 return "/";
00074 return result;
00075 }
00076 }
00077
00078 bool FilesPageHandler::listDirectory(Common::String path, Common::String &content, const Common::String &itemTemplate) {
00079 if (path == "" || path == "/") {
00080 if (ConfMan.hasKey("rootpath", "cloud"))
00081 addItem(content, itemTemplate, IT_DIRECTORY, "/root/", _("File system root"));
00082 addItem(content, itemTemplate, IT_DIRECTORY, "/saves/", _("Saved games"));
00083 return true;
00084 }
00085
00086 if (HandlerUtils::hasForbiddenCombinations(path))
00087 return false;
00088
00089 Common::String prefixToRemove = "", prefixToAdd = "";
00090 if (!transformPath(path, prefixToRemove, prefixToAdd))
00091 return false;
00092
00093 Common::FSNode node = Common::FSNode(path);
00094 if (path == "/")
00095 node = node.getParent();
00096
00097 if (!HandlerUtils::permittedPath(node.getPath()))
00098 return false;
00099
00100 if (!node.isDirectory())
00101 return false;
00102
00103
00104 Common::FSList _nodeContent;
00105 if (!node.getChildren(_nodeContent, Common::FSNode::kListAll, false))
00106 _nodeContent.clear();
00107 else
00108 Common::sort(_nodeContent.begin(), _nodeContent.end());
00109
00110
00111 {
00112 Common::String filePath = path;
00113 if (filePath.hasPrefix(prefixToRemove))
00114 filePath.erase(0, prefixToRemove.size());
00115 if (filePath == "" || filePath == "/" || filePath == "\\")
00116 filePath = "/";
00117 else
00118 filePath = parentPath(prefixToAdd + filePath);
00119 addItem(content, itemTemplate, IT_PARENT_DIRECTORY, filePath, _("Parent directory"));
00120 }
00121
00122
00123 for (Common::FSList::iterator i = _nodeContent.begin(); i != _nodeContent.end(); ++i) {
00124 Common::String name = i->getDisplayName();
00125 if (i->isDirectory())
00126 name += "/";
00127
00128 Common::String filePath = i->getPath();
00129 if (filePath.hasPrefix(prefixToRemove))
00130 filePath.erase(0, prefixToRemove.size());
00131 filePath = prefixToAdd + filePath;
00132
00133 addItem(content, itemTemplate, detectType(i->isDirectory(), name), filePath, name);
00134 }
00135
00136 return true;
00137 }
00138
00139 FilesPageHandler::ItemType FilesPageHandler::detectType(bool isDirectory, const Common::String &name) {
00140 if (isDirectory)
00141 return IT_DIRECTORY;
00142 if (name.hasSuffix(".txt"))
00143 return IT_TXT;
00144 if (name.hasSuffix(".zip"))
00145 return IT_ZIP;
00146 if (name.hasSuffix(".7z"))
00147 return IT_7Z;
00148 return IT_UNKNOWN;
00149 }
00150
00151 void FilesPageHandler::addItem(Common::String &content, const Common::String &itemTemplate, ItemType itemType, Common::String path, Common::String name, Common::String size) const {
00152 Common::String item = itemTemplate, icon;
00153 bool isDirectory = (itemType == IT_DIRECTORY || itemType == IT_PARENT_DIRECTORY);
00154 switch (itemType) {
00155 case IT_DIRECTORY:
00156 icon = "dir.png";
00157 break;
00158 case IT_PARENT_DIRECTORY:
00159 icon = "up.png";
00160 break;
00161 case IT_TXT:
00162 icon = "txt.png";
00163 break;
00164 case IT_ZIP:
00165 icon = "zip.png";
00166 break;
00167 case IT_7Z:
00168 icon = "7z.png";
00169 break;
00170 default:
00171 icon = "unk.png";
00172 }
00173 replace(item, "{icon}", icon);
00174 replace(item, "{link}", (isDirectory ? "files?path=" : "download?path=") + LocalWebserver::urlEncodeQueryParameterValue(path));
00175 replace(item, "{name}", encodeHtmlEntities(name));
00176 replace(item, "{size}", size);
00177 content += item;
00178 }
00179
00181
00182 void FilesPageHandler::handle(Client &client) {
00183 Common::String response =
00184 "<html>" \
00185 "<head><title>ScummVM</title></head>" \
00186 "<body>" \
00187 "<p>{create_directory_desc}</p>" \
00188 "<form action=\"create\">" \
00189 "<input type=\"hidden\" name=\"path\" value=\"{path}\"/>" \
00190 "<input type=\"text\" name=\"directory_name\" value=\"\"/>" \
00191 "<input type=\"submit\" value=\"{create_directory_button}\"/>" \
00192 "</form>" \
00193 "<hr/>" \
00194 "<p>{upload_file_desc}</p>" \
00195 "<form action=\"upload?path={path}\" method=\"post\" enctype=\"multipart/form-data\">" \
00196 "<input type=\"file\" name=\"upload_file-f\" allowdirs multiple/>" \
00197 "<span>{or_upload_directory_desc}</span>" \
00198 "<input type=\"file\" name=\"upload_file-d\" directory webkitdirectory multiple/>" \
00199 "<input type=\"submit\" value=\"{upload_file_button}\"/>" \
00200 "</form>"
00201 "<hr/>" \
00202 "<h1>{index_of_directory}</h1>" \
00203 "<table>{content}</table>" \
00204 "</body>" \
00205 "</html>";
00206 Common::String itemTemplate = "<tr><td><img src=\"icons/{icon}\"/></td><td><a href=\"{link}\">{name}</a></td><td>{size}</td></tr>\n";
00207
00208
00209 Common::SeekableReadStream *const stream = HandlerUtils::getArchiveFile(FILES_PAGE_NAME);
00210 if (stream)
00211 response = HandlerUtils::readEverythingFromStream(stream);
00212
00213 Common::String path = client.queryParameter("path");
00214 Common::String content = "";
00215
00216
00217 if (!listDirectory(path, content, itemTemplate)) {
00218 HandlerUtils::setFilesManagerErrorMessageHandler(client, _("ScummVM couldn't list the directory you specified."));
00219 return;
00220 }
00221
00222
00223 replace(response, "{create_directory_button}", _("Create directory"));
00224 replace(response, "{create_directory_button}", _("Create directory"));
00225 replace(response, "{path}", encodeDoubleQuotes(client.queryParameter("path")));
00226 replace(response, "{path}", encodeDoubleQuotes(client.queryParameter("path")));
00227 replace(response, "{upload_files_button}", _("Upload files"));
00228 replace(response, "{upload_file_button}", _("Upload files"));
00229 replace(response, "{create_directory_desc}", _("Type new directory name:"));
00230 replace(response, "{upload_file_desc}", _("Select a file to upload:"));
00231 replace(response, "{or_upload_directory_desc}", _("Or select a directory (works in Chrome only):"));
00232 replace(response, "{index_of_directory}", Common::String::format(_("Index of %s"), encodeHtmlEntities(getDisplayPath(client.queryParameter("path"))).c_str()));
00233 replace(response, "{content}", content);
00234 LocalWebserver::setClientGetHandler(client, response);
00235 }
00236
00237 }