commit b654228675cdd273d1cf1bc3d68fc213d1ac1cff Author: Massimo Melina Date: Sat May 2 19:04:16 2020 +0200 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4f2fd81 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +tmp/ +__history/ +__recovery/ +win32/ +*.vfs +*.dcu +*.exe +*.map +hfs.ini +*.tmp +*.bak +*.*- +*.corrupted \ No newline at end of file diff --git a/WindowsXP.manifest b/WindowsXP.manifest new file mode 100644 index 0000000..84283b0 --- /dev/null +++ b/WindowsXP.manifest @@ -0,0 +1,21 @@ + + + +Windows Shell + + + + + + diff --git a/alias.txt b/alias.txt new file mode 100644 index 0000000..14e597b --- /dev/null +++ b/alias.txt @@ -0,0 +1,11 @@ +var length=length|var=$1 +cache=trim|{.set|#cache.tmp|{.from table|$1|$2.}.} {.if not|{.^#cache.tmp.}|{:{.set|#cache.tmp|{.dequote|$3.}.}{.set table|$1|$2={.^#cache.tmp.}.}:}.} {.^#cache.tmp.} {.set|#cache.tmp.} +is substring=pos|$1|$2 +set append=set|$1|$2|mode=append +123 if 2=if|$2|$1$2$3 +between=if|{.$1 < $3.}|{:{.and|{.$1 <= $2.}|{.$2 <= $3.}:}|{:{.and|{.$3 <= $2.}|{.$2 <= $1.}:} +between!=if|{.$1 < $3.}|{:{.and|{.$1 < $2.}|{.$2 < $3.}:}|{:{.and|{.$3 < $2.}|{.$2 < $1.}:} +file changed=if| {.{.filetime|$1.} > {.^#file changed.$1.}.}|{: {.set|#file changed.$1|{.filetime|$1.}.} {.if|$2|{:{.load|$1|var=$2.}:}.} 1:} +play system event=play +redirect=add header|Location: $1 +chop={.cut|{.calc|{.pos|$2|var=$1.}+{.length|$2.}.}||var=$1|remainder=#chop.tmp.}{.^#chop.tmp.} \ No newline at end of file diff --git a/classesLib.pas b/classesLib.pas new file mode 100644 index 0000000..05f060a --- /dev/null +++ b/classesLib.pas @@ -0,0 +1,1213 @@ +{ +Copyright (C) 2002-2012 Massimo Melina (www.rejetto.com) + +This file is part of HFS ~ HTTP File Server. + + HFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + HFS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with HFS; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +} +{$INCLUDE defs.inc } +unit classesLib; + +interface + +uses + iniFiles, types, hslib, strUtils, sysUtils, classes, math; + +type + TfastStringAppend = class + protected + buff: string; + n: integer; + public + function length():integer; + function reset():string; + function get():string; + function append(s:string):integer; + end; + + PcachedIcon = ^TcachedIcon; + TcachedIcon = record + data: ansistring; + idx: integer; + time: Tdatetime; + end; + + TiconsCache = class + n: integer; + icons: array of TcachedIcon; + function get(data:ansistring):PcachedIcon; + procedure put(data:ansistring; idx:integer; time:Tdatetime); + procedure clear(); + procedure purge(olderThan:Tdatetime); + function idxOf(data:shortstring):integer; + end; + + TusersInVFS = class + protected + users: TstringDynArray; + pwds: array of TstringDynArray; + public + procedure reset(); + procedure track(usr, pwd:string); overload; + procedure drop(usr, pwd:string); overload; + function match(usr, pwd:string):boolean; overload; + function empty():boolean; + end; + + TarchiveStream = class(Tstream) + protected + pos, cachedTotal: int64; + cur: integer; + + procedure invalidate(); + procedure calculate(); virtual; abstract; + function getTotal():int64; + public + flist: array of record + src, // full path of the file on the disk + dst: ansistring; // full path of the file in the archive + firstByte, // offset of the file inside the archive + mtime, + size: int64; + data: Tobject; // extra data + end; + onDestroy: TNotifyEvent; + + constructor create; + destructor Destroy; override; + function addFile(src:ansistring; dst:ansistring=''; data:Tobject=NIL):boolean; virtual; + function count():integer; + procedure reset(); virtual; + property totalSize:int64 read getTotal; + property current:integer read cur; + end; // TarchiveStream + + TtarStreamWhere = (TW_HEADER, TW_FILE, TW_PAD); + + TtarStream = class(TarchiveStream) + protected + fs: TFileStream; + block: TStringStream; + lastSeekFake: int64; + where: TtarStreamWhere; + function fsInit():boolean; + procedure headerInit(); // fill block with header + procedure padInit(full:boolean=FALSE); // fill block with pad + function headerLengthForFilename(fn:ansistring):integer; + procedure calculate(); override; + public + fileNamesOEM: boolean; + constructor create; + destructor Destroy; override; + function Read(var Buffer; Count: Longint): Longint; override; + function Write(const Buffer; Count: Longint): Longint; override; + function Seek(const Offset: Int64; Origin: TSeekOrigin=soBeginning): Int64; override; + + procedure reset(); override; + end; // TtarStream + + Thasher = class(TstringList) + procedure loadFrom(path:string); + function getHashFor(fn:string):string; + end; + + TstringToIntHash = class(ThashedStringList) + constructor create; + function getInt(s:string):integer; + function getIntByIdx(idx:integer):integer; + function incInt(s:string):integer; + procedure setInt(s:string; int:integer); + end; + + PtplSection = ^TtplSection; + TtplSection = record + name, txt: string; + nolog, nourl, cache: boolean; + ts: Tdatetime; + end; + + Ttpl = class + protected + src: string; + lastExt, // cache for getTxtByExt() + last: record section:string; idx:integer; end; // cache for getIdx() + fileExts: TStringDynArray; + strTable: THashedStringList; + fUTF8: boolean; + fOver: Ttpl; + function getIdx(section:string):integer; + function getTxt(section:string):string; + function newSection(section:string):PtplSection; + procedure fromString(txt:string); + procedure setOver(v:Ttpl); + procedure updateUTF8(); + public + onChange: TNotifyEvent; + sections: array of TtplSection; + constructor create(txt:string=''; over:Ttpl=NIL); + destructor Destroy; override; + property txt[section:string]:string read getTxt; default; + property fullText:string read src write fromString; + property utf8:boolean read fUTF8; + property over:Ttpl read fOver write setOver; + function sectionExist(section:string):boolean; + function getTxtByExt(fileExt:string):string; + function getSection(section:string):PtplSection; + function getSections():TStringDynArray; + procedure appendString(txt:string); + function getStrByID(id:string):string; + function me():Ttpl; + end; // Ttpl + + TcachedTplObj = class + ts: Tdatetime; + tpl: Ttpl; + end; + + TcachedTpls = class(THashedStringList) + public + function getTplFor(fn:string):Ttpl; + destructor Destroy; override; + end; // TcachedTpls + + TperIp = class // for every different address, we have an object of this class. These objects are never freed until hfs is closed. + public + limiter: TspeedLimiter; + customizedLimiter: boolean; + constructor create(); + destructor Destroy; override; + end; + + Ttlv = class + protected + cur, bound: integer; + whole, lastValue: ansistring; + stack: array of integer; + stackTop: integer; + public + procedure parse(data:ansistring); + function pop(var value:ansistring):integer; + function down():boolean; + function up():boolean; + function getTotal():integer; + function getCursor():integer; + function getPerc():real; + function isOver():boolean; + function getTheRest():ansistring; + end; + +implementation + +uses + utilLib, main, windows, dateUtils, forms; + +constructor TperIp.create(); +begin +limiter:=TspeedLimiter.create(); +srv.limiters.add(limiter); +end; + +destructor TperIp.Destroy; +begin +srv.limiters.remove(limiter); +limiter.free; +end; + +//////////// TcachedTpls + +destructor TcachedTpls.Destroy; +var + i: integer; +begin +for i:=0 to count-1 do + objects[i].free; +end; + +function TcachedTpls.getTplFor(fn:string):Ttpl; +var + i: integer; + o: TcachedTplObj; + s: string; +begin +fn:=trim(lowercase(fn)); +i:=indexOf(fn); +if i >= 0 then + o:=objects[i] as TcachedTplObj +else + begin + o:=TcachedTplObj.create(); + if addObject(fn, o) > 100 then + delete(0); + end; +result:=o.tpl; +if getMtime(fn) = o.ts then exit; +o.ts:=getMtime(fn); +s:=loadTextFile(fn); +if o.tpl = NIL then + begin + result:=Ttpl.create(); + o.tpl:=result; + end; +o.tpl.fromString(s); +end; // getTplFor + +//////////// TusersInVFS + +function TusersInVFS.empty():boolean; +begin result:= users = NIL end; + +procedure TusersInVFS.reset(); +begin +users:=NIL; +pwds:=NIL; +end; // reset + +procedure TusersInVFS.track(usr, pwd: string); +var + i: integer; +begin +if usr = '' then exit; +i:=idxOf(usr, users); +if i < 0 then i:=addString(usr, users); +if i >= length(pwds) then setLength(pwds, i+1); +addString(pwd, pwds[i]); +end; // track + +procedure TusersInVFS.drop(usr, pwd: string); +var + i, j: integer; +begin +i:=idxOf(usr, users); +if i < 0 then exit; +j:=AnsiIndexStr(pwd, pwds[i]); +if j < 0 then exit; +removeString(pwds[i], j); +if assigned(pwds[i]) then exit; +// this username does not exist with any password +removeString(users, i); +while i+1 < length(pwds) do + begin + pwds[i]:=pwds[i+1]; + inc(i); + end; +setLength(pwds, i); +end; // drop + +function TusersInVFS.match(usr, pwd:string):boolean; +var + i: integer; +begin +result:=FALSE; +i:=idxOf(usr, users); +if i < 0 then exit; +result:= 0 <= AnsiIndexStr(pwd, pwds[i]); +end; // match + +//////////// TiconsCache + +function TiconsCache.idxOf(data:shortstring):integer; +var + b, e, c: integer; +begin +result:=0; +if n = 0 then exit; +// binary search +b:=0; +e:=n-1; + repeat + result:=(b+e) div 2; + c:=compareStr(data, icons[result].data); + if c = 0 then exit; + if c < 0 then e:=result-1; + if c > 0 then b:=result+1; + until b > e; +result:=b; +end; // idxOf + +function TiconsCache.get(data:ansistring):PcachedIcon; +var + i: integer; +begin +result:=NIL; +i:=idxOf(data); +if (i >= 0) and (i < n) and (icons[i].data = data) then + result:=@icons[i]; +end; // get + +procedure TiconsCache.put(data:ansistring; idx:integer; time:Tdatetime); +var + i, w: integer; +begin +if length(icons) <= n then setlength(icons, n+50); +w:=idxOf(data); +for i:=n downto w+1 do icons[i]:=icons[i-1]; // shift +icons[w].data:=data; +icons[w].idx:=idx; +icons[w].time:=time; +inc(n); +end; // put + +procedure TiconsCache.clear(); +begin +icons:=NIL; +n:=0; +end; // clear + +procedure TiconsCache.purge(olderThan:Tdatetime); +var + i, m: integer; +begin +exit; +m:=0; +for i:=0 to n-1 do + if icons[i].time < olderThan then dec(n) // this does not shorten the loop + else + begin + if m < i then icons[m]:=icons[i]; + inc(m); + end; +end; // purge + +//////////// TfastStringAppend + +function TfastStringAppend.length():integer; +begin result:=n end; + +function TfastStringAppend.get():string; +begin +setlength(buff, n); +result:=buff; +end; // get + +function TfastStringAppend.reset():string; +begin +result:=get(); +buff:=''; +n:=0; +end; // reset + +function TfastStringAppend.append(s:string):integer; +var + ls, lb: integer; +begin +ls:=system.length(s); +lb:=system.length(buff); +if n+ls > lb then setlength(buff, lb+ls+20000); +moveChars(s[1], buff[n+1], ls); +inc(n, ls); +result:=n; +end; // append + +//////////// TarchiveStream + +function TarchiveStream.getTotal():int64; +begin +if cachedTotal < 0 then calculate(); +result:=cachedTotal; +end; // getTotal + +function TarchiveStream.addFile(src:ansistring; dst:ansistring=''; data:Tobject=NIL):boolean; + + function getMtime(fh:Thandle):int64; + var + ctime, atime, mtime: Tfiletime; + st: TSystemTime; + begin + getFileTime(fh, @ctime, @atime, @mtime); + fileTimeToSystemTime(mtime, st); + result:=dateTimeToUnix(SystemTimeToDateTime(st)); + end; // getMtime + +var + i, fh: integer; +begin +result:=FALSE; +fh:=fileopen(src, fmOpenRead+fmShareDenyNone); +if fh = -1 then exit; +result:=TRUE; +if dst = '' then + dst:=extractFileName(src); +i:=length(flist); +setLength(flist, i+1); +flist[i].src:=src; +flist[i].dst:=dst; +flist[i].data:=data; +flist[i].size:=sizeOfFile(fh); +flist[i].mtime:=getMtime(fh); +flist[i].firstByte:=-1; +fileClose(fh); +invalidate(); +end; // addFile + +procedure TarchiveStream.invalidate(); +begin cachedTotal:=-1 end; + +constructor TarchiveStream.create; +begin +inherited; +reset(); +end; // create + +destructor TarchiveStream.destroy; +begin +if assigned(onDestroy) then onDestroy(self); +inherited; +end; // destroy + +procedure TarchiveStream.reset(); +begin +flist:=NIL; +cur:=0; +pos:=0; +invalidate(); +end; // reset + +function TarchiveStream.count():integer; +begin result:=length(flist) end; + +//////////// TtarStream + +constructor TtarStream.create; +begin +block:=TStringStream.create(''); +lastSeekFake:=-1; +where:=TW_HEADER; +fileNamesOEM:=FALSE; +inherited; +end; // create + +destructor TtarStream.destroy; +begin +freeAndNIL(fs); +inherited; +end; // destroy + +procedure TtarStream.reset(); +begin +inherited; +block.size:=0; +end; // reset + +function TtarStream.fsInit():boolean; +begin +if assigned(fs) and (fs.FileName = flist[cur].src) then + begin + result:=TRUE; + exit; + end; +result:=FALSE; +try + freeAndNIL(fs); + fs:=TfileStream.Create(flist[cur].src, fmOpenRead+fmShareDenyWrite); + result:=TRUE; +except + fs:=NIL; + end; +end; // fsInit + +procedure TtarStream.headerInit(); + + function num(i:int64; fieldLength:integer):ansistring; + const + CHARS : array [0..7] of ansichar = '01234567'; + var + d: integer; + begin + d:=fieldLength-1; + result:=ansistring(dupeString('0', d))+#0; + while d > 0 do + begin + result[d]:=CHARS[i and 7]; + dec(d); + i:=i shr 3; + if i = 0 then break; + end; + end; // num + + function str(s:ansistring; fieldLength:integer; fill:ansistring=#0):ansistring; + begin + setLength(s, min(length(s), fieldLength-1)); + result:=s+ansistring( dupeString(fill, fieldLength-length(s)) ); + end; // str + + function sum(s:ansistring):integer; + var + i: integer; + begin + result:=0; + for i:=1 to length(s) do + inc(result, ord(s[i])); + end; // sum + + procedure applyChecksum(var s:ansistring); + var + chk: ansistring; + begin + chk:=num(sum(s), 7)+' '; + chk[7]:=#0; + move(chk[1], s[100+24+12+12+1], length(chk)); + end; // applyChecksum + +const + FAKE_CHECKSUM = ' '; + USTAR = 'ustar'#0'00'; + PERM = '0100777'#0'0000000'#0'0000000'#0; // file mode, uid, gid +var + fn, s, pre: ansistring; +begin +fn:=ansistring(replaceStr(flist[cur].dst,'\','/')); +if fileNamesOEM then + CharToOem(pWideChar(string(fn)), pAnsiChar(fn)); +pre:=''; +if length(fn) >= 100 then + begin + pre:=str('././@LongLink', 100)+PERM + +num(length(fn)+1, 12)+num(flist[cur].mtime, 12) + +FAKE_CHECKSUM+'L'; + pre:=str(pre, 256)+str(#0+USTAR,256); + applyChecksum(pre); + pre:=pre+str(fn, 512); + end; +s:=str(fn, 100)+PERM + +num(flist[cur].size, 12) // file size + +num(flist[cur].mtime, 12) // mtime + +FAKE_CHECKSUM + +'0'+str('', 100) // link properties + +USTAR; +applyChecksum(s); +s:=str(s, 512); // pad +block.Size:=0; +block.WriteString(pre+s); +block.seek(0, soBeginning); +end; // headerInit + +function TtarStream.write(const Buffer; Count: Longint): Longint; +begin raise EWriteError.Create('write unsupproted') end; + +function gap512(i:int64):word; inline; +begin +result:=i and 511; +if result > 0 then result:=512-result; +end; // gap512 + +procedure TtarStream.padInit(full:boolean=FALSE); +begin +block.Size:=0; +block.WriteString(dupeString(#0, if_(full,512,gap512(pos)) )); +block.Seek(0, soBeginning); +end; // padInit + +function TtarStream.headerLengthForFilename(fn:ansistring):integer; +begin +result:=length(fn); +result:=512*if_(result<100, 1, 3+result div 512); +end; // headerLengthForFilename + +procedure TtarStream.calculate(); +var + pos: int64; + i: integer; +begin +pos:=0; +for i:=0 to length(flist)-1 do + with flist[i] do + begin + firstByte:=pos; + inc(pos, size+headerLengthForFilename(dst)); + inc(pos, gap512(pos)); + end; +inc(pos, 512); // last empty block +cachedTotal:=pos; +end; // calculate + +function TtarStream.seek(const Offset: Int64; Origin: TSeekOrigin): Int64; + + function left():int64; + begin result:=offset-pos end; + + procedure fineSeek(s:Tstream); + begin inc(pos, s.seek(left(), soBeginning)) end; + + function skipMoreThan(size:int64):boolean; + begin + result:=left() > size; + if result then inc(pos, size); + end; + +var + bak: int64; + prevCur: integer; +begin +{ The lastSeekFake trick is a way to fastly manage a sequence of + seek(0,soCurrent); seek(0,soEnd); seek(0,soBeginning); + such sequence called very often, while it is used to just read + the size of the stream, no real seeking requirement. +} +bak:=lastSeekFake; +lastSeekFake:=-1; +if (origin = soCurrent) and (offset <> 0) then + seek(pos+offset, soBeginning); +if origin = soEnd then + if offset < 0 then + seek(totalSize+offset, soBeginning) + else + begin + lastSeekFake:=pos; + pos:=totalsize; + end; +result:=pos; +if origin <> soBeginning then exit; +if bak >= 0 then + begin + pos:=bak; + exit; + end; + +// here starts the normal seeking algo + +prevCur:=cur; +cur:=0; // flist index +pos:=0; // current position in the file +block.size:=0; +while (left() > 0) and (cur < length(flist)) do + begin + // are we seeking inside this header? + if not skipMoreThan(headerLengthForFilename(flist[cur].dst)) then + begin + if (prevCur <> cur) or (where <> TW_HEADER) or eos(block) then + headerInit(); + fineSeek(block); + where:=TW_HEADER; + break; + end; + // are we seeking inside this file? + if not skipMoreThan(flist[cur].size) then + begin + if not fsInit() then + raise Exception.Create('TtarStream.seek: cannot open '+flist[cur].src); + fineSeek(fs); + where:=TW_FILE; + break; + end; + // are we seeking inside this pad? + if not skipMoreThan(gap512(pos)) then + begin + padInit(); + fineSeek(block); + where:=TW_PAD; + break; + end; + inc(cur); + end;//while +if left() > 0 then + begin + padInit(TRUE); + fineSeek(block); + end; +result:=pos; +end; // seek + +function TtarStream.read(var Buffer; Count: Longint): Longint; +var + p: Pbyte; + + procedure goForth(d: int64); + begin + dec(count, d); + inc(pos, d); + inc(p, d); + end; // goForth + + procedure goRead(s:Tstream); + begin goForth( s.read(p^, count) ) end; + +var + i, posBak: int64; +begin +posBak:=pos; +p:=@buffer; +while (count > 0) and (cur < length(flist)) do + case where of + TW_HEADER: + begin + if block.size = 0 then + headerInit(); + goRead(block); + if not eos(block) then continue; + where:=TW_FILE; + freeAndNIL(fs); // in case the same files appear twice in a row, we must be sure to reinitialize the reader stream + block.size:=0; + end; + TW_FILE: + begin + fsInit(); + if assigned(fs) then + goRead(fs); + { We reserved a fixed space for this file in the archive, but the file + may not exist anymore, or its size may be shorter than expected, + so we can't rely on eos(fs) to know if we are done in this section. + Lets calculate how far we are from the theoretical end of the file, + and decide after it. + } + i:=headerLengthForFilename(flist[cur].dst); + i:=flist[cur].firstByte+i+flist[cur].size-pos; + if count >= i then + where:=TW_PAD; + // In case the file is shorter, we pad the rest with NUL bytes + i:=min(count, max(0,i)); + fillChar(p^,i,0); + goForth(i); + end; + TW_PAD: + begin + if block.size = 0 then padInit(); + goRead(block); + if not eos(block) then continue; + where:=TW_HEADER; + block.size:=0; + inc(cur); + end; + end;//case + +// last empty block +if count > 0 then + begin + padInit(TRUE); + goRead(block); + end; +result:=pos-posBak; +end; // read + +//////////// Thasher + +procedure Thasher.loadFrom(path:string); +var + sr: TsearchRec; + s, l, h: string; +begin +if path='' then exit; +path:=includeTrailingPathDelimiter(lowercase(path)); +if findFirst(path+'*.md5', faAnyFile-faDirectory, sr) <> 0 then exit; + repeat + s:=loadTextfile(path+sr.name); + while s > '' do + begin + l:=chopline(s); + h:=trim(chop('*',l)); + if h = '' then break; + if l = '' then + // assume it is referring to the filename without the extention + l:=copy(sr.name, 1, length(sr.name)-4); + add(path+lowercase(l)+'='+h); + end; + until findnext(sr) <> 0; +sysutils.findClose(sr); +end; // loadFrom + +function Thasher.getHashFor(fn:string):string; +begin +try result:=values[lowercase(fn)] +except result:='' end +end; + +//////////// TstringToIntHash + +constructor TstringToIntHash.create; +begin +inherited create; +sorted:=TRUE; +duplicates:=dupIgnore; +end; // create + +function TstringToIntHash.getIntByIdx(idx:integer):integer; +begin if idx < 0 then result:=0 else result:=integer(objects[idx]) end; + +function TstringToIntHash.getInt(s:string):integer; +begin result:=getIntByIdx(indexOf(s)) end; + +procedure TstringToIntHash.setInt(s:string; int:integer); +begin +beginUpdate(); +objects[add(s)]:=Tobject(int); +endUpdate(); +end; // setInt + +function TstringToIntHash.incInt(s:string):integer; +var + i: integer; +begin +beginUpdate(); +i:=add(s); +result:=integer(objects[i]); +inc(result); +objects[i]:=Tobject(result); +endUpdate(); +end; // autoupdatedFiles_getCounter + +//////////// Ttpl + +constructor Ttpl.create(txt:string=''; over:Ttpl=NIL); +begin +fullText:=txt; +self.over:=over; +end; + +destructor Ttpl.destroy; +begin +freeAndNIL(strTable); +inherited; +end; // destroy + +function Ttpl.getStrByID(id:string):string; +begin +if strTable = NIL then + begin + strTable:=THashedStringList.create; + strTable.text:=txt['special:strings']; + end; +result:=strTable.values[id]; +if (result = '') and assigned(over) then + result:=over.getStrByID(id) +end; // getStrByID + +function Ttpl.getIdx(section:string):integer; +begin +if section <> last.section then + begin + last.section:=section; + for result:=0 to length(sections)-1 do + if sameText(sections[result].name, section) then + begin + last.idx:=result; + exit; + end; + last.idx:=-1; + end; +result:=last.idx +end; // getIdx + +function Ttpl.newSection(section:string):PtplSection; +var + i: integer; +begin +// add +i:=length(sections); +setLength(sections, i+1); +result:=@sections[i]; +result.name:=section; +// getIdx just filled 'last' with not-found, so we must update +last.section:=section; +last.idx:=i; +// manage file.EXT sections +if not ansiStartsText('file.', section) then exit; +i:=length(fileExts); +setLength(fileExts, i+2); +delete(section, 1, 4); +fileExts[i]:=section; +fileExts[i+1]:=str_(last.idx); +lastExt.section:=section; +lastExt.idx:=last.idx; +end; // newSection + +function Ttpl.sectionExist(section:string):boolean; +begin +result:=getIdx(section)>=0; +if not result and assigned(over) then + result:=over.sectionExist(section); +end; + +function Ttpl.getSection(section:string):PtplSection; +var + i: integer; +begin +result:=NIL; +i:=getIdx(section); +if i >= 0 then result:=@sections[i]; +if assigned(over) and ((result = NIL) or (trim(result.txt) = '')) then + result:=over.getSection(section); +end; // getSection + +function Ttpl.getTxt(section:string):string; +var + i: integer; +begin +i:=getIdx(section); +if i >= 0 then + result:=sections[i].txt +else if assigned(over) then + result:=over[section] +else + result:='' +end; // getTxt + +function Ttpl.getTxtByExt(fileExt:string):string; +var + i: integer; +begin +result:=''; +if (lastExt.section > '') and (fileExt = lastExt.section) then + begin + if lastExt.idx >= 0 then result:=sections[lastExt.idx].txt; + exit; + end; +i:=idxOf(fileExt, fileExts); +if (i < 0) and assigned(over) then + begin + result:=over.getTxtByExt(fileExt); + if result > '' then exit; + end; +lastExt.section:=fileExt; +lastExt.idx:=i; +if i < 0 then exit; +i:=int_(fileExts[i+1]); +lastExt.idx:=i; +result:=sections[i].txt; +end; // getTxtByExt + +procedure Ttpl.fromString(txt:string); +begin +src:=''; +sections:=NIL; +fileExts:=NIL; +last.section:=#255'null'; // '' is a valid (and often used) section name. This is a better null value. +freeAndNIL(strTable); // mod by mars + +appendString(txt); +end; // fromString + +procedure Ttpl.appendString(txt:string); +var + ptxt, bos: Pchar; + cur_section, next_section: string; + + function pred(p:pchar):pchar; inline; + begin + result:=p; + if p <> NIL then + dec(result); + end; + + function succ(p:pchar):pchar; inline; + begin + result:=p; + if p <> NIL then + inc(result); + end; + + procedure findNextSection(); + begin + // find start + bos:=ptxt; + repeat + if bos^ <> '[' then bos:=ansiStrPos(bos, #10'['); + if bos = NIL then exit; + if bos^ = #10 then inc(bos); + if getSectionAt(bos, next_section) then + exit; + inc(bos); + until false; + end; // findNextSection + + procedure saveInSection(); + var + ss: TStringDynArray; + s: string; + i, si: integer; + base: TtplSection; + till: pchar; + append: boolean; + sect, from: PtplSection; + begin + till:=pred(bos); + if till = NIL then till:=pred(strEnd(ptxt)); + if till^ = #10 then dec(till); + if till^ = #13 then dec(till); + + base.txt:=getStr(ptxt, till); + // there may be flags after | + s:=cur_section; + cur_section:=chop('|', s); + base.nolog:=ansiPos('no log', s) > 0; + base.nourl:=ansiPos('private', s) > 0; + base.cache:=ansiPos('cache', s) > 0; + base.ts:=now(); + + s:=cur_section; + append:=ansiStartsStr('+', s); + if append then + delete(s,1,1); + + // there may be several section names separated by = + ss:=split('=', s); + // handle the main section specific case + if ss = NIL then addString('', ss); + // assign to every name the same txt + for i:=0 to length(ss)-1 do + begin + s:=trim(ss[i]); + si:=getIdx(s); + from:=NIL; + if si < 0 then // not found + begin + if append then + from:=getSection(s); + sect:=newSection(s); + end + else + begin + sect:=@sections[si]; + if append then + from:=sect; + end; + if from<>NIL then + begin // inherit from it + sect.txt:=from.txt+base.txt; + sect.nolog:=from.nolog or base.nolog; + sect.nourl:=from.nourl or base.nourl; + continue; + end; + sect^:=base; + sect.name:=s; // restore this lost attribute + end; + end; // saveInSection + +const + BOM = #$EF#$BB#$BF; +var + first: boolean; +begin +// this is used by some unicode files. at the moment we just ignore it. +if ansiStartsStr(BOM, txt) then + delete(txt, 1, length(BOM)); + +if txt = '' then exit; +src:=src+txt; +cur_section:=''; +ptxt:=@txt[1]; +first:=TRUE; + repeat + findNextSection(); + if not first or (trim(getStr(ptxt, pred(bos))) > '') then + saveInSection(); + if bos = NIL then break; + cur_section:=next_section; + inc(bos, length(cur_section)); // get faster to the end of line + ptxt:=succ(ansiStrPos(bos, #10)); // get to the end of line (and then beyond) + first:=FALSE; + until ptxt = NIL; +updateUTF8(); +if assigned(onChange) then + onChange(self); +end; // appendString + +procedure Ttpl.setOver(v:Ttpl); +begin +fOver:=v; +updateUTF8(); +end; // setOver + +procedure Ttpl.updateUTF8(); +begin fUTF8:=assigned(over) and over.utf8 or utf8test(fullText) end; + +function Ttpl.getSections():TStringDynArray; +var + i: integer; +begin +i:=length(sections); +setLength(result, i); +for i:=0 to i-1 do + result[i]:=sections[i].name; +end; + +function Ttpl.me():Ttpl; +begin result:=self end; + + + +procedure Ttlv.parse(data:ansistring); +begin +whole:=data; +cur:=1; +bound:=length(data); +stackTop:=0; +end; // parse + +function Ttlv.pop(var value:ansistring):integer; +var + n: integer; +begin +result:=-1; +if isOver() then exit; // finished +result:=integer((@whole[cur])^); +n:=Pinteger(@whole[cur+4])^; +value:=copy(whole, cur+8, n); +lastValue:=value; +inc(cur, 8+n); +end; // pop + +function Ttlv.down():boolean; +begin +// do we have anything to recur on? +if (cur = 1) then + begin + result:=false; + exit; + end; +// push into the stack +if (stackTop = length(stack)) then // space over + setLength(stack, stackTop+10); // make space +stack[stackTop]:=cur; +inc(stackTop); +stack[stackTop]:=bound; +inc(stackTop); + +bound:=cur; +dec(cur, length(lastValue)); +result:=true; +end; // down + +function Ttlv.up():boolean; +begin +if stackTop = 0 then + begin + result:=false; + exit; + end; +dec(stackTop); +bound:=stack[stackTop]; +dec(stackTop); +cur:=stack[stackTop]; +result:=true; +end; // up + +function Ttlv.getTotal():integer; +begin result:=length(whole) end; + +function Ttlv.getCursor():integer; +begin result:=cur end; + +function Ttlv.getPerc():real; +begin +if length(whole) = 0 then result:=0 +else result:=cur/length(whole) +end; // getPerc + +function Ttlv.isOver():boolean; +begin result:=(cur+8 > bound) end; + +function Ttlv.getTheRest():ansistring; +begin result:=copy(whole, cur, bound-cur+1) end; + +end. diff --git a/copyright.txt b/copyright.txt new file mode 100644 index 0000000..7055b61 --- /dev/null +++ b/copyright.txt @@ -0,0 +1,6 @@ +HFS version %s, Copyright (C) 2002-2020 Massimo Melina (www.rejetto.com) +HFS comes with ABSOLUTELY NO WARRANTY; for details click Menu -> Web links -> License +This is FREE software, and you are welcome to redistribute it +under certain conditions. + +Build #%s diff --git a/country.cache b/country.cache new file mode 100644 index 0000000..c570154 --- /dev/null +++ b/country.cache @@ -0,0 +1 @@ +127.0.0.1=(Private Address) (XX) \ No newline at end of file diff --git a/data.RES b/data.RES new file mode 100644 index 0000000..f882cec Binary files /dev/null and b/data.RES differ diff --git a/data.rc b/data.rc new file mode 100644 index 0000000..f3ce7e6 --- /dev/null +++ b/data.rc @@ -0,0 +1,12 @@ +1 24 "WindowsXP.manifest" +defaultTpl TEXT default.tpl +copyright TEXT copyright.txt +dmBrowserTpl TEXT dmBrowser.tpl +invertban TEXT invertban.txt +filelistTpl TEXT filelist.tpl +uploadDisabled TEXT upload_disabled.txt +uploadHowTo TEXT upload_how.txt +alias TEXT alias.txt +shell GIF shell.gif +IPservices TEXT ipservices.txt +jquery TEXT jquery.min.js diff --git a/default.tpl b/default.tpl new file mode 100644 index 0000000..d4610e1 --- /dev/null +++ b/default.tpl @@ -0,0 +1,1155 @@ +Welcome! This is the default template for HFS 2.4 +template revision TR3. + +Here below you'll find some options affecting the template. +Consider 1 is used for "yes", and 0 is used for "no". + +DO NOT EDIT this template just to change options. It's a very bad way to do it, and you'll pay for it! +Correct way: in Virtual file system, right click on home/root, properties, diff template, +put this text [+special:strings] +and following all the options you want to change, using the same syntax you see here. + +[+special:strings] + +option.newfolder=1 +option.move=1 +option.comment=1 +option.rename=1 +COMMENT with these you can disable some features of the template. Please note this is not about user permissions, this is global! + +[common-head] + + + + + + + + +[] +{.$common-head.} + {.!HFS.} %folder% + + + + + + +
+

WARNING: this template is only to be used with HFS 2.3 (and macros enabled)

+ {.$menu panel.} + {.$folder panel.} + {.$list panel.} +
+ + + + +[list panel] +{.if not| %number% |{: +
{.!{.if|{.length|{.?search.}.}|No results|No files.}.}
+:}|{: +
+ %list% +
+:}.} +
+ {.!Uptime.}: %uptime% +
+ + +[menu panel] + + + + +[title-bar] + {.!title.} + + + + +[folder panel] +
+ {.breadcrumbs|{: {.if|{.length|%bread-name%.}|/ %bread-name%|.}:} .} +
+{.if|%number%| +
+ %number-folders% {.!folders.}, %number-files% {.!files.}, {.add bytes|%total-size%.} +
+.} +{.123 if 2|
|{.commentNL|%folder-item-comment%.}|
.} + +[upload panel] + + +[search panel] +
+
+ {.!Search.} +
{.!this folder and sub-folders.} +
{.!this folder only.} +
{.!entire server.} + +
+
+ + + +[+special:strings] +title=HTTP File Server +max s dl msg=There is a limit on the number of simultaneous downloads on this server.
This limit has been reached. Retry later. +retry later=Please, retry later. +item folder=in folder +no files=No files in this folder +no results=No items match your search query +confirm=Are you sure? + +[icons.css|no log] +@font-face { font-family: 'fontello'; + src: url('data:application/x-font-woff;base64,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') format('woff'); +} +.fa { font-family: "fontello"; font-style: normal; font-weight: normal; } +.fa-asterisk::before { content:"\e800" } +.fa-check-circled::before { content:"\e801" } +.fa-user::before { content:"\e802" } +.fa-clock-o::before { content:"\e803" } +.fa-download::before { content:"\e804" } +.fa-ban::before { content:"\e805" } +.fa-edit::before { content:"\e806" } +.fa-check-square::before { content:"\e807" } +.fa-folder::before { content:"\e808" } +.fa-globe::before { content:"\e809" } +.fa-home::before { content:"\e80a" } +.fa-key::before { content:"\e80b" } +.fa-lock::before { content:"\e80c" } +.fa-refresh::before { content:"\e80d" } +.fa-retweet::before { content:"\e80e" } +.fa-search::before { content:"\e80f" } +.fa-star::before { content:"\e810" } +.fa-cancel-circled::before { content:"\e811"; } +.fa-truck::before { content:"\e812" } +.fa-upload::before { content:"\e813" } +.fa-bars::before { content:"\f0c9" } +.fa-coffee::before { content:"\f0f4" } +.fa-quote-left::before { content:"\f10d" } +.fa-file-archive-o::before { content:"\f1c6" } +.fa-trash::before { content:"\f1f8" } +.fa-user-circle::before { content:"\f2bd" } +.fa-lightbulb:before { content: '\f0eb' } +.fa-sort:before { content: '\f0dc' } +.fa-sort-alt-up:before { content: '\f160' } +.fa-sort-alt-down:before { content: '\f161' } + +[style.css|no log|cache] +/*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none} + +{.$icons.css.} + +.pure-button { + background-color: #cde; padding: .5em 1em; color: #444; color: rgba(0,0,0,.8); border: 1px solid #999; border: transparent; text-decoration: none; box-sizing: border-box; + border-radius: 2px; display: inline-block; zoom: 1; white-space: nowrap; vertical-align: middle; text-align: center; cursor: pointer; user-select: none; +} +body { font-family:tahoma, verdana, arial, helvetica, sans; transition:background-color 1s ease; } +a { text-decoration:none; color:#26c; border:1px solid transparent; padding:0 0.1em; } +#folder-path { float:left; margin-bottom: 0.2em; } +#folder-path a { padding: .5em; } +#folder-path a:first-child { padding:.28em } #folder-path i.fa { font-size:135% } +button i.fa { font-size:110% } +.item { margin-bottom:.3em; padding:.3em .8em; border-top:1px solid #ddd; } +.item:hover { background:#f8f8f8; } +.item-props { float:right; font-size:90%; margin-left:12px; color:#777; margin-top:.2em; } +.item-link { float:left; word-break:break-word; /* fix long names without spaces on mobile */ } +.item img { vertical-align: text-bottom; margin:0 0.2em; } +.item .fa-lock { margin-right: 0.2em; } +.item .clearer { clear:both } +.comment { color:#666; padding:.1em .5em .2em; background-color: #f5f5f5; border-radius: 1em; margin-top: 0.1em; } +.comment>i { margin-right:0.5em; } +.item-size { margin-left:.3em } +.selector { float:left; width: 1.2em; height:1.2em; margin-right: .5em;} +.item-menu { padding:0.1em 0.3em; border-radius:0.6em; border: 1px outset; position: relative; top: -0.1em;} +.dialog-content .buttons { margin-top:1.5em } +.dialog-content .buttons button { margin:.5em auto; min-width: 9em; display:block; } +.dialog-content.error { background: #fcc; } +.dialog-content.error h2 { text-align:center } +.dialog-content.error button { background-color: #f77; color: white; } +#wrapper { max-width:60em; margin:auto; } /* not too wide or it will be harder to follow rows */ +#serverinfo { font-size:80%; text-align:center; margin: 1.5em 0 0.5em; } +#selection-panel { text-align:center; } +#selection-panel label { margin-right:0.8em } +#selection-panel button { vertical-align:baseline; } +#selection-panel .buttons { white-space:nowrap } + +.item-menu { display:none } +.can-comment .item-menu, +.can-rename .item-menu, +.can-delete .item-menu { display:inline-block; display:initial; } + +#folder-stats { font-size:90%; padding:.1em .3em; margin:.5em; float:right; } +#files,#nothing { clear:both } +#nothing { padding:1em } + +.dialog-overlay { background:rgba(0,0,0,.75); position:fixed; top:0; left:0; width:100%; height:100%; z-index:100; } +.dialog-content { position: absolute; top: 50%; left: 50%; + transform: translate(-50%, -50%); + -webkit-transform: translate(-50%, -50%); + -moz-transform: translate(-50%, -50%); + -ms-transform: translate(-50%, -50%); + -o-transform: translate(-50%, -50%); + background:#fff; border-radius: 1em; padding: 1em; text-align:center; min-width: 10em; +} +.ask input { border:1px solid rgba(0,0,0,0.5); padding: .2em; margin-top: .5em; } +.ask .close { float: right; font-size: 1.2em; color: red; position: relative; top: -0.4em; right: -0.3em; } + +#additional-panels input { color: #555; padding: .1em 0.3em; border-radius: 0.4em; } + +.additional-panel { position:relative; max-height: calc(100vh - 5em); text-align:left; margin: 0.5em 1em; padding: 0.5em 1em; border-radius: 1em; background-color:#555; border: 2px solid #aaa; color:#fff; line-height: 1.5em; display:inline-block; } +.additional-panel .close { position: absolute; right: -0.8em; top: -0.2em; color: #aaa; font-size: 130%; } + +body.dark-theme { background:#222; color:#aaa; } +body.dark-theme #title-bar { color:#bbb } +body.dark-theme a { color:#79b } +body.dark-theme a.pure-button { color:#444 } +body.dark-theme .item:hover { background:#111; } +body.dark-theme .pure-button { background:#89a; } +body.dark-theme .item .comment { background-color:#444; color:#888; } +body.dark-theme #foldercomment { background-color:#333; color:#999; } +body.dark-theme .dialog-overlay { background:rgba(100,100,100,.5) } +body.dark-theme .dialog-content { background:#222; color:#888; } +body.dark-theme input, +body.dark-theme textarea, +body.dark-theme select, +body.dark-theme #additional-panels input +{ background: #111; color: #aaa; } + +#msgs { display:none; } +#msgs li:first-child { font-weight:bold; } + +#menu-panel { position:fixed; top:0; left:0; width: 100%; background:#555; text-align:center; +position: -webkit-sticky; position: -moz-sticky; position: -ms-sticky; position: -o-sticky; position: sticky; margin-bottom:0.3em; +z-index:1; /* without this .item-menu will be over*/ } +#menu-panel button span { margin-left:.8em } +#user-panel button { padding:0.3em 0.6em; font-size:smaller; margin-left:1em; } +#user-panel span { position: relative; top: 0.1em; } +#menu-bar { padding:0.2em 0 } + +@media (min-width: 50em) { +#toggleTs { display: none } +} +@media (max-width: 50em) { +#menu-panel button { padding: .4em .6em; } +.additional-panel button span, +#menu-bar button span { display:none } /* icons only */ +#menu-bar i { font-size:120%; } /* bigger icons */ +#menu-bar button { width: 3em; max-width:10.7vw; padding: .4em 0; } +.hideTs .item-ts { display:none } +} + +#upload-panel { font-size: 88%;} +#upload-progress { margin-top:.5em; display:none; } +#upload-progress progress { width:10em; position:relative; top:.1em; } +#progress-text { position: absolute; color: #000; font-size: 80%; margin-left:.5em; z-index:1; } +#upload-results a { color:#b0c2d4; } +#upload-results>* { display:block; word-break: break-all; } +#upload-results>span { margin-left:.15em; } /* better alignment */ +#upload-results { max-height: calc(100vh - 11em); overflow: auto;} +#upload-panel>button { margin: auto; display: block; margin-top:.8em;} /* center it*/ + + +[file=folder=link|private] +
+ +
+ {.cut||-3|%item-modified%.} +[+file] + %item-size%B +[+file=folder=link] + {.if|{.get|is new.}|.} +[+file=folder] + +[+file=folder=link] +
+
+[+file=folder=link] + {.if| {.length|{.?search.}.} |{:{.123 if 2|
{.!item folder.} |{.breadcrumbs|{:%bread-name%/:}|from={.count substring|/|%folder%.}/breadcrumbs.}|
.}:} .} + {.123 if 2|
|{.commentNL|%item-comment%.}|
.} +
+ +[error-page] + + + + + + + + +%content% +
+
+HFS - %timestamp% +
+ + + +[not found] +

{.!Not found.}

+{.!go to root.} + +[overload] +

{.!Server Too Busy.}

+{.!The server is too busy to handle your request at this time. Retry later.} + +[max contemp downloads] +

{.!Download limit.}

+{.!max s dl msg.} +
({.disconnection reason.}) + +[unauthorized] +

{.!Unauthorized.}

+{.!Either your user name and password do not match, or you are not permitted to access this resource..} + +[deny] +

{.!Forbidden.}

+{.or|%reason%|{.!This resource is not accessible..}.} + +[ban] +

{.!You are banned.}

+%reason% + +[upload] + +[upload-file] + +[upload-results] +[{.cut|1|-1|%uploaded-files%.} +] + +[upload-success] +{ +"url":"%item-url%", +"name":"%item-name%", +"size":"%item-size%", +"speed":"%smart-speed%" +}, +{.if| {.length|%user%.} |{: + {.set item|{.force ansi|%folder%%item-name%.}|comment={.!uploaded by.} %user%.} +:}.} + +[upload-failed] +{ "err":"{.!%reason%.}", "name":"%item-name%" }, + +[progress|no log] + + + +[progress-nofiles] +{.!No file exchange in progress..} + +[progress-upload-file] +{.if not|{.{.?only.} = down.}|{: +
  • {.!Uploading.} %total% @ %speed-kb% KB/s +
    %filename% +
    {.!Time left.} %time-left%" +
    %perc%% +:}.} + +[progress-download-file] +{.if not|{.{.?only.} = up.}|{: +
  • {.!Downloading.} %total% @ %speed-kb% KB/s +
    %filename% +
    {.!Time left.} %time-left%" +
    %perc%% +:}.} + +[ajax.mkdir|no log] +{.check session.} +{.set|x|{.postvar|name.}.} +{.break|if={.pos|\|var=x.}{.pos|/|var=x.}|result=forbidden.} +{.break|if={.not|{.can mkdir.}.}|result=not authorized.} +{.set|x|{.force ansi|%folder%{.^x.}.}.} +{.break|if={.exists|{.^x.}.}|result=exists.} +{.break|if={.not|{.length|{.mkdir|{.^x.}.}.}.}|result=failed.} +{.add to log|{.!User.} %user% {.!created folder.} "{.^x.}".} +{.pipe|ok.} + +[ajax.rename|no log] +{.check session.} +{.break|if={.not|{.can rename.}.}|result=forbidden.} +{.break|if={.is file protected|{.postvar|from.}.}|result=forbidden.} +{.break|if={.is file protected|{.postvar|to.}.}|result=forbidden.} +{.set|x|{.force ansi|%folder%{.postvar|from.}.}.} +{.set|yn|{.force ansi|{.postvar|to.}.}.} +{.set|y|{.force ansi|%folder%.}{.^yn.}.} +{.break|if={.not|{.exists|{.^x.}.}.}|result=not found.} +{.break|if={.exists|{.^y.}.}|result=exists.} +{.set|comment| {.get item|{.^x.}|comment.} .} +{.set item|{.^x.}|comment=.} +{.break|if={.not|{.length|{.rename|{.^x.}|{.^yn.}.}.}.}|result=failed.} +{.set item|{.^x.}|resource={.filepath|{.get item|{.^x.}|resource.}.}{.^yn.}.} +{.set item|{.^x.}|name={.^yn.}.} +{.set item|{.^y.}|comment={.^comment.}.} +{.add to log|{.if|%user%|{.!User.} %user%|{.!Anonymous.}.} {.!renamed.} "{.^x.}" {.!to.} "{.^yn.}".} +{.pipe|ok.} + +[ajax.move|no log] +{.check session.} +{.set|dst|{.force ansi|{.postvar|dst.}.}.} +{.break|if={.not|{.and|{.can move.}|{.get|can delete.}|{.get|can upload|path={.^dst.}.}/and.}.} |result=forbidden.} +{.set|log|{.!Moving items to.} {.^dst.}.} +{.for each|fn|{.replace|:|{.no pipe||.}|{.force ansi|{.postvar|files.}.}.}|{: + {.break|if={.is file protected|var=fn.}|result=forbidden.} + {.set|x|{.force ansi|%folder%.}{.^fn.}.} + {.set|y|{.^dst.}/{.^fn.}.} + {.if not |{.exists|{.^x.}.}|{.^x.}: {.!not found.}|{: + {.if|{.exists|{.^y.}.}|{.^y.}: {.!already exists.}|{: + {.set|comment| {.get item|{.^x.}|comment.} .} + {.set item|{.^x.}|comment=.} {.comment| this must be done before moving, or it will fail.} + {.if|{.length|{.move|{.^x.}|{.^y.}.}.} |{: + {.move|{.^x.}.md5|{.^y.}.md5.} + {.set|log|{.chr|13.}{.^fn.}|mode=append.} + {.set item|{.^y.}|comment={.^comment.}.} + :} | {: + {.set|log|{.chr|13.}{.^fn.} (failed)|mode=append.} + {.maybe utf8|{.^fn.}.}: {.!not moved.} + :}/if.} + :}/if.} + :}.} + ; +:}.} +{.add to log|{.^log.}.} + +[ajax.comment|no log] +{.check session.} +{.break|if={.not|{.can comment.}.} |result=forbidden.} +{.for each|fn|{.replace|:|{.no pipe||.}|{.postvar|files.}.}|{: + {.break|if={.is file protected|var=fn.}|result=forbidden.} + {.set item|{.force ansi|%folder%{.^fn.}.}|comment={.force ansi|{.postvar|text.}.}.} +:}.} +{.pipe|ok.} + +[ajax.changepwd|no log] +{.check session.} +{.break|if={.not|{.can change pwd.}.} |result=forbidden.} +{.if|{.length|{.set account||password={.force ansi|{.postvar|new.}.}.}/length.}|ok|failed.} + +[special:alias] +check session=if|{.{.cookie|HFS_SID_.} != {.postvar|token.}.}|{:{.cookie|HFS_SID_|value=|expires=-1.} {.break|result=bad session.}:} +can mkdir=and|{.get|can upload.}|{.!option.newfolder.} +can comment=and|{.get|can upload.}|{.!option.comment.} +can rename=and|{.get|can delete.}|{.!option.rename.} +can delete=get|can delete +can change pwd=member of|can change password +can move=or|1|1 +escape attr=replace|"|"|$1 +commentNL=if|{.pos||$1.} +add bytes=switch|{.cut|-1||$1.}|,|0,1,2,3,4,5,6,7,8,9|$1 {.!Bytes.}|K,M,G,T|$1B + +[special:import] +{.new account|can change password|enabled=1|is group=1|notes=accounts members of this group will be allowed to change their password.} + +[lib.js|no log|cache] +//