!7 static int id = 1400000; concept FileMeta { int fileID; S name; S md5; bool authed; int redirectTo; *() {} *(int *fileID, S *name) { _doneLoading(); change(); } void _doneLoading() { //print("_doneLoading " + fileID); metaMap.put(fileID, this); } } static Map metaMap = synchroMap(); p { load("id"); dbIndexing(FileMeta, 'fileID, FileMeta, 'name, FileMeta, 'md5); } svoid setMD5(FileMeta meta) { if (nempty(meta.md5)) ret; S md5 = "error"; pcall { md5 = md5(fileFile(meta.fileID)); } cset(meta, +md5); } static File filesDir() { ret prepareProgramDir("files"); } synchronized html { print("uri: " + uri); uri = dropPrefix("/", uri); new Matches mm; if (eq(uri, "latest-id")) ret get fileID(highestByField created(list(FileMeta))); if (startsWith(uri, "info/", mm) && isInteger(mm.rest())) ret htitle("File #" + mm.rest()) + fileIDToHTML(parseInt(mm.rest())); if (startsWith(uri, "name/", mm) && isInteger(mm.rest())) { int id = parseInt(mm.rest()); FileMeta meta = metaMap.get(id); if (meta == null) ret subBot_serve404("ID not found: " + id); ret serveText(unnull(meta.name)); } S possibleID = beforeSlash_orAll(uri); if (isInteger(possibleID)) { // serve file int id = parseInt(possibleID); FileMeta c = findMetaWithRedirect(id); if (c == null) ret subBot_serve404("Not found"); if (nempty(params.get("remd5"))) { cset(c, md5 := null); setMD5(c); } File file = fileFile(c.fileID); S givenName = urldecode(afterSlash(uri)); S serveAs = or2(givenName, c.name); S mimeType = or2(params.get("contentType"), params.get("ct")); if (empty(mimeType)) mimeType = or2(extensionToMimeType(c.name), "application/binary"); print("givenName=" + givenName + ", serveAs=" + serveAs + ", mimeType=" + mimeType); ret addHeader("Content-Disposition", "attachment; filename=" + quote(serveAs), call(getMainBot(), 'serveFile_maxCache, file, mimeType)); } // Note: returns only authed files if (startsWith(uri, "latest-file-named/", mm)) { S name = urldecode(mm.get(0)); FileMeta m = first(findAuthedFiles(name)); ret struct(m == null ? null : ll(m.fileID, m.md5)); } if (!webAuthed(params)) ret ahref(relativeBotLink(#1002590), "please log in"); // AUTHED FROM HERE ON if (startsWith(uri, "delete/", mm) && isInteger(mm.rest())) { FileMeta m = conceptWhere(FileMeta, fileID := parseInt(mm.rest())); if (m == null) ret "Not found"; deleteFile(fileFile(m.fileID)); deleteConcept(m); ret "Deleted"; } if (uri.startsWith("md5/")) { uri = dropPrefix("md5/", uri); FileMeta meta = findConcept(FileMeta, md5 := uri); if (meta == null) ret subBot_serve404("Not found"); ret call(getMainBot(), "serveFile_maxCache", fileFile(meta.fileID), "application/binary"); } // finds a file by md5 if (uri.startsWith("checkmd5/")) { uri = dropPrefix("checkmd5/", uri); FileMeta meta = findConcept(FileMeta, md5 := uri); ret meta == null ? "Not found" : str(meta.fileID); } if (eq(uri, "setRedirect")) { int from = parseInt(params.get("from")); int to = parseInt(params.get("to")); FileMeta meta = findConcept(FileMeta, fileID := from); if (meta == null) ret "Not found"; cset(meta, redirectTo := to); ret "Redirected " + str(meta.fileID) + " to " + to; } if (eq(uri, "upload")) { print("upload called"); S name = params.get("name"); SS files = getUploadFiles(); print("got files: " + l(files)); int id = parseInt(params.get('id)); if (id != 0 && hasConcept(FileMeta, fileID := id)) ret "File exists: " + id; if (id == 0) id = newFileID(); S data = params.get("data"); if (data != null) { print("got data: " + l(data)); saveBinaryFile(fileFile(id), hexToBytes(data)); } else { String tmpfile = files.get("thefile"); String originalName = params.get("thefile"); name = or2(name, originalName); assertNotNull(tmpfile); File tmp = new File(tmpfile); long l = tmp.length(); if (l == 0) ret "Empty file, exiting"; copyFile(tmp, fileFile(id)); } FileMeta m = cregister(new FileMeta(id, unnull(name))); cset(m, authed := webAuthed(params)); setMD5(m); ret hrefresh(2, rawLink()) + p("OK:
" + ahref(rawLink(str(id)), fsI(id) + " - " + or2(name, "?"))) + ahref(rawLink(), "[back]"); } if (eq(uri, "uploadform")) ret htitle("Upload") + hmobilefix() + uploadform(); if (eq(uri, "ids-and-md5s")) ret struct(flattenList(map(list(FileMeta), func(FileMeta m) { ll(m.fileID, m.md5) }))); if (eq(uri, "typical-set")) { L l = findAuthedFiles( "Circles From tvejysmllsmz.gz", "Webs from program #1011161 on tvejysmllsmz.gz"); ret struct(flattenList(map(l, func(FileMeta m) { ll(m.fileID, m.md5) }))); } if (eq(uri, "")) { // main list S msg = ""; L ids = collect(conceptsSortedByFieldDesc(FileMeta, 'created), 'fileID); ret htitle("General File Server") + (nempty(msg) ? p(msg) : "") + h3("Upload") + uploadform() + "
" + p(n(ids, "File") + (empty(ids) ? "." : ":")) + ul(map(ids, func(int id) -> S { fileIDToHTML(id) })) //+ p(ahref(pageLink("/uploadform"), "Upload a file")) ; } null; } static synchronized int newFileID() { while (fileFile(id).exists()) ++id; int i = id++; save("id"); ret i; } static File fileFile(int id) { ret new File(filesDir(), str(id)); } sS uploadform() { ret huploadform( p("File to upload: " + hfileupload()) + p("Optional name: " + hinputfield("name")) + p(hsubmit("OK")), "action", rawLink("upload")); } static L findAuthedFiles(S... names) { new L l; for (S name : names) addIfNotNull(l, highestByField('id, conceptsWhere(FileMeta, +name, authed := true))); ret l; } sS fileIDToHTML(int id) { FileMeta meta = metaMap.get(id); S title = or2(getString(meta, "name"), "Untitled"); S linkText = "#" + id + " - " + htmlencode(title); //S dumbLink = rawLink(str(id)); S coolLink = "https://botcompany.de/files/" + id + "/" + urlencode(title); S s = ahref(coolLink, linkText); s += " " + n(fileSize(fileFile(id)), "byte"); if (meta != null) { s += " [" + formatDateGMT(meta.created) + ", md5: " + ahref(rawLink("md5/" + meta.md5), meta.md5) + "]"; if (meta.authed) s += " " + dottedSpan("*", "Authorized Upload"); if (meta.redirectTo != 0) s = "redirected to #" + meta.redirectTo + " - " + s; } ret s; } static FileMeta findMetaWithRedirect(int id) { FileMeta c = findConcept(FileMeta, fileID := id); if (c != null && c.redirectTo != 0) c = findConcept(FileMeta, fileID := c.redirectTo); ret c; }