RFile

This is a simple file manager written in Run Basic. It is modelled on [|FileDrawers].

How to Install RFile
Copy the source code below and save the project.

Download the RFile icons package:

Unzip the file into the Run Basic Public directory. If you decide to rename the directory, change IMAGEURL$ to point to the correct name.

Customizing RFile
Change PASSWORD$ to whatever password you want. If you don't want to be prompted for a password at all, change following section of code: code ' ' Display the Login screen ' action$ = "login" code to code ' ' Display the Login screen ' action$ = "" code You can customize the date and time formats by changing DATEFORMAT$ and TIMEFORMAT$ respectively.

How To Use RFile
When you run RFile, you will be prompted to enter a passsword (unless disabled - see above), Enter the passsword you put in PASSWORD$ (default is "admin"). You should after a short delay see the contents of the Run Basic directory.

Known Issues

 * You cannot copy a read-only file - his is because Run Basic always opens binary files in read/write mode.
 * On Windows you cannot view the root folder of C:\ due to a bug in Run Basic.
 * You can only download files from the Run Basic public directory.
 * If you upload a file which the same name as a file in the Run Basic directory, the copy in the Run Basic directory will be removed.

RFile Source Code
code format="vb" ' ' RFile - File Manager ' based on FileDrawers (filedrawers.org) '

PROGRAM$ = "RFile" VERSION$ = "0.4 Beta"

PASSWORD$ = "admin" ' Access password - CHANGE TO SOMETHING SECURE!

DATEFORMAT$ = "dd/mm/yyyy" ' Display format for dates TIMEFORMAT$ = "hh:mm" ' Display format for times

global IMAGEURL$ IMAGEURL$ = "/rfile" ' URL to images

dim FAVORITE$(19, 1) FAVORITE$(0,0) = "Home"    : FAVORITE$(0,1) = DefaultDir$ FAVORITE$(1,0) = "Public"  : FAVORITE$(1,1) = ResourcesRoot$ FAVORITE$(2,0) = "Projects" : FAVORITE$(2,1) = ProjectsRoot$

dim ACTION$(10,1) ACTION$(0,0) = "Upload File"            : ACTION$(0,1) = "upload" ACTION$(1,0) = "Cut Selected Item(s)"   : ACTION$(1,1) = "cut" ACTION$(2,0) = "Copy Selected Item(s)"  : ACTION$(2,1) = "copy" ACTION$(3,0) = "Paste to This Folder"   : ACTION$(3,1) = "paste" ACTION$(4,0) = "Delete Selected Item(s)" : ACTION$(4,1) = "delete" ACTION$(5,0) = "Create a New Folder"    : ACTION$(5,1) = "new" ACTION$(6,0) = "Rename Selected Item"   : ACTION$(6,1) = "rename"

currentPath$ = DefaultDir$ ' Current path filenames$ = "" ' Selected file(s)

global pathDelim$ ' Path seperator

if Platform$ = "win32" then pathDelim$ = "\" else pathDelim$ = "/" end if

global IMAGEPATH$ IMAGEPATH$ = ResourcesRoot$ + replaceChar$(IMAGEURL$, "/", pathDelim$)

' ' Load names of all file icons into an array for fast searching ' files #file, IMAGEPATH$ + pathDelim$ + "mime" + pathDelim$ + "*.gif"

global numIcons numIcons = #file rowcount

global ICON$ dim ICON$(numIcons - 1)

for i = 0 to numIcons - 1 #file nextfile$ ICON$(i) = #file name$ next i

' ' Define copy, cut and delete lists ' dim copy$(100) dim cut$(100) dim delete$(100)

global copy$, numCopies, copySize global cut$, numCuts, cutSize global delete$, numDeletes

' ' Define CSS styles ' cssid #heading, "{background: #000066; color: #FFFFFF; font-family: sans-serif; padding: 2px 8px;}" cssid #title, "{font-size: large; font-weight: bold;}" cssid #version, "{float: left;}" cssid #date, "{text-align: right;}" cssid #infobar, "{color: #666; border-bottom: 1px solid #369; font-family: sans-serif; padding: 3px;}" cssid #location, "{}" cssid #infobuttons, "{float: right;}" cssid #content, "{font-family: sans-serif; padding: 8px 4px; white-space: normal;}" cssid #message, "{background: #FFFF99; border: 1px dashed #000000; color: #882222; padding: 10px;}" cssid #propbox, "{float: left; border: 1px solid #369; padding: 0px; width: 190px;}" cssid #propheader, "{background: #369; color: #FFFFFF; padding: 4px; font-weight: bold;}" cssid #propcontent, "{padding: 8px 4px;}" cssid #selectedfolder, "{background: url(";IMAGEURL$;"/folder.gif); background-repeat: no-repeat; font-weight: bold; line-height: 48px; padding-left: 50px;}" cssid #selecteditem, "{background: url(";IMAGEURL$;"/doc_lg.gif); background-repeat: no-repeat; font-weight: bold; line-height: 48px; padding-left: 50px;}" cssid #propsubhead, "{color: #F97909; border-bottom: 1px solid #F97909; font-weight: bold; margin-bottom: 6px;}" cssid #propmenu, "{margin-left: 4px;}" cssid #confirm, "{background: #FFFF99; border: 1px dashed #000000; color: #882222; font-family: sans-serif; padding: 10px; margin-left: 15%; margin-right: 20%; margin-top: 40px;}" cssid #display, "{margin-left: 200px;}" cssid #info, "{background: #FFFF99; border: 1px dashed #000000; color: #000066; font-family: sans-serif; padding: 10px; margin-left: 15%; margin-right: 20%; margin-top: 40px;}" cssid #login, "{background: #F1F1F1; border: 1px solid #69C; color: #000066; font-family: sans-serif; padding: 10px; margin-left: auto; margin-right: auto; margin-top: 40px; text-align: center; width: 400px;}" cssid #errormsg, "{color: red; font-weight: bold; padding: 4px 0px; text-decoration: underline;}" cssclass "table", "{border: 1px solid #69C; border-collapse:collapse; padding: 0px;}" cssclass "th", "{background: #DEDEEE; color: #369; border: 1px solid #69C; padding: 8px 4px}" cssclass "td.left0", "{background: #FFFFFF; border: 1px solid #69C; padding: 4px;}" cssclass "td.left1", "{background: #F1F1F1; border: 1px solid #69C; padding: 4px;}" cssclass "td.right0", "{background: #FFFFFF; border: 1px solid #69C; padding: 4px; text-align: right;}" cssclass "td.right1", "{background: #F1F1F1; border: 1px solid #69C; padding: 4px; text-align: right;}" cssclass "a", "{color: #03C; text-decoration: none;}" cssclass "a:visted", "{color: #03C; text-decoration: none;}" cssclass "a:hover", "{color: #03C; text-decoration: underline;}" cssclass "img", "{border: none;}" cssclass "div.upload", "{background: #FFFF99; border: 1px dashed #000000; color: #000066; font-family: sans-serif; padding: 10px; margin-left: 15%; margin-right: 20%; margin-top: 40px;}"

' ' Display the Login screen ' action$ = "login"

' ' Start of main display loop ' [main] on error goto [unexpectedError]

if action$ = "cut" or action$ = "copy" or action$ = "delete" or action$ = "rename" then selected = 0 rename$ = "" for i = 0 to numFiles - 1 name$ = "check_"; i     if #name$ value then selected = selected + 1 select case action$ case "cut" if type$(i) <> "folder" then call cutItem file$(i), size(i) case "copy" if type$(i) <> "folder" then call copyItem file$(i), size(i) case "delete" delete$(numDeletes) = file$(i) numDeletes = numDeletes + 1 case "rename" rename$ = file$(i) call removeCopy file$(i), size(i) exit for end select end if   next i    if selected = 0 then message$ = "Nothing selected!" action$ = "" end if end if

if action$ = "delete_item" then action$ = "delete"

if action$ = "paste" then if numCopies = 0 and numCuts = 0 then message$ = "Nothing to paste!" else for i = 0 to numCopies - 1 source$ = copy$(i) target$ = currentPath$ + pathDelim$ + lastItem$(source$, pathDelim$) if source$ <> target$ then call copyFile source$, target$ end if     next i      numCopies = 0 copySize = 0

for i = 0 to numCuts - 1 source$ = cut$(i) target$ = currentPath$ + pathDelim$ + lastItem$(source$, pathDelim$) if source$ <> target$ then call moveFile source$, target$ end if     next i    end if  end if

cls div heading div title print PROGRAM$ end div div version print "Version "; VERSION$; end div div date print date$("mmm dd, yyyy"); " "; time$; end div end div

select case action$ case "delete" div confirm html " Comfirm Item Deletion " print print "Are you sure that you want to delete the following "; numDeletes; " items(s)?" print for i = 0 to numDeletes - 1 print delete$(i) next i       print button #delete, "Delete Item(s)", [delete] print " "; button #cancel, "Cancel", [cancel] end div case "login" div login html " ";PROGRAM$;" Login " if message$ <> "" then div errormsg print message$; message$ = "" end div end if       print "Enter password: "; passwordbox #password, "", 20 print " "; button #login, "Login", [login] end div case "new" div info html " Create a New Folder " print "Folder Name: "; textbox #folder, "", 20 #folder setfocus print " "; button #create, "Create Folder", [createFolder] print " "; button #cancel, "Cancel", [cancel] end div case "upload" html " " html " Upload File " print link #cancel, "return to folder", [cancel] print : print upload ""; file$ if currentPath$ <> DefaultDir$ then call moveFile DefaultDir$ + pathDelim$ + file$, currentPath$ + pathDelim$ + file$ end if     action$ = "" goto [main] case else div infobar div infobuttons if action$ = "view" then button #goUp, "Go Up", [cancel] else button #goUp, "Go Up", [goUp] end if         print " "; button #refresh, "Refresh", [main] end div div location print "Location: "; if action$ = "change_directory" then textbox #newPath, currentPath$, 40 #newPath setfocus print " "; button #go, "Go", [changePath] print " "; button #cancel, "Cancel", [cancel] else path$ = "" if currentPath$ = "" then link #link, "/", [setPath] #link setkey("") end if           for i = 1 to countItems(currentPath$, pathDelim$) dir$ = myword$(currentPath$, i, pathDelim$) if i > 1 then path$ = path$ + pathDelim$ path$ = path$ + dir$ if i > 1 then print " > "; if dir$ = "" then dir$ = "/" link #link, dir$, [setPath] #link setkey(path$) next i           if action$ = "view" then print " > "; lastItem$(selectedFile$, pathDelim$); print " "; button #change, "Change", [action] #change setkey("change_directory") end if       end div end div div content div propbox if action$ = "view" then div propheader print "Item Properties"; end div div propcontent div selecteditem print lastItem$(selectedFile$, pathDelim$); end div div propsubhead print "Actions"; end div div propmenu link #link, "Cut This Item", [cutItem] print link #link, "Copy This Item", [copyItem] print link #link, "Delete This Item", [deleteItem] print end div print div propsubhead print "Information"; end div div propmenu files #file, selectedFile$ if #file hasanswer then #file nextfile$ #file dateformat(DATEFORMAT$) #file timeformat(TIMEFORMAT$) selectedFileSize = #file size print "Size: "; size$(selectedFileSize) print "Date Modified: "; #file date$ print "Time Modified: "; #file time$ end if             end div end div else div propheader print "Folder Properties"; end div div propcontent div selectedfolder if currentPath$ = "" then print "/"; ' special case for unix root folder else print lastItem$(currentPath$, pathDelim$); end if             end div div propsubhead print "Actions"; end div div propmenu i = 0 while ACTION$(i,0) <> "" link #link, ACTION$(i,0), [action] #link setkey(ACTION$(i,1)) print i = i + 1 wend end div print div propsubhead print "Favorites"; end div div propmenu i = 0 while FAVORITE$(i,0) <> "" link #link, FAVORITE$(i,0), [setPath] #link setkey(FAVORITE$(i,1)) print i = i + 1 wend end div print div propsubhead print "Information"; end div div propmenu if numCopies <> 0 then html ""; numCopies; " item(s) copied [" link #reset, "reset", [resetCopy] print "]" print size$(copySize) for i = 0 to numCopies - 1 print lastItem$(copy$(i), pathDelim$) next i                 print end if               if numCuts <> 0 then html ""; numCuts; " item(s) cut [" link #reset, "reset", [resetCut] print "]" print size$(cutSize) for i = 0 to numCuts - 1 print lastItem$(cut$(i), pathDelim$) next i                 print end if             end div end div end if       end div

div display if message$ <> "" then div message html message$ end div print message$ = "" end if

if action$ = "view" then type$ = getFileType$(selectedFile$) if type$ = "gif" or type$ = "jpg" or type$ = "jpeg" or type$ = "png" then if isDownloadable(selectedFile$) then html "" else loadgraphic #img, selectedFile$ render #img end if         else if isText(selectedFile$) then html " " open selectedFile$ for input as #in while not(eof(#in)) line input #in, a$               print a$              wend close #in html " " else div message html" Unsupported File Type " print "This file contains binary data and is not viewable in a web browser." print if isDownloadable(selectedFile$) then print "You may "; html "download " print " this file, or "; end if               link #cancel, "return to the parent folder", [cancel] end div end if         end if        else html " " ' action$ = "" end if       end div end div end select wait end

[action] action$ = EventKey$ goto [main]

[baddir] message$ = "The folder '" + newPath$ + "' does not exist!" goto [main]

' ' Generic cancel action - clear the deleted items list and return to the folder display ' [cancel] action$ = "" numDeletes = 0 goto [main]

' ' Change the current folder to the one specified by the user ' [changePath] action$ = "" newPath$ = trim$(#newPath contents$) while right$(newPath$, 1) = pathDelim$ newPath$ = left$(newPath$, len(newPath$) - 1) wend if Platform$ = "win32" and lower$(newPath$) = "c:" then message$ = "Due to a Run Basic bug, it is not possible to view the C:\ folder." else if not(dirExists(newPath$)) then [baddir] currentPath$ = newPath$ end if goto [main]

' ' Add the curent item to the copy items list ' [copyItem] call copyItem selectedFile$, selectedSize goto [main]

' ' Create a new folder ' [createFolder] folder$ = #folder contents$ if folder$ = "" then message$ = "No folder name supplied!" goto [main] end if

if not(validName(folder$)) then message$ = "Folder name contains invalid characters." goto [main] end if

folder$ = currentPath$ + pathDelim$ + folder$ if mkdir(folder$) then action$ = "" else message$ = "Cannot create folder '" + folder$ + "'." end if goto [main]

[cutItem] action$ = "" call cutItem selectedFile$, selectedSize goto [main]

' ' Delete all the items in the delete items list ' [delete] action$ = ""

for i = 0 to numDeletes - 1 path$ = delete$(i) files #file, path$ if #file hasanswer then #file nextfile$ size = #file size if #file isdir then if not(rmdir(path$)) then message$ = message$ + " Failed to delete folder '" + path$ + "'" else on error goto [deleteError] kill path$ call removeCopy path$, size end if   end if  next i  numDeletes = 0 if message$ <> "" then message$ = mid$(message$, 6) ' Skip first goto [main]

[deleteError] message$ = mid$(message$, 6) + " Failed to delete file '" + path$ + "'" goto [main]

' ' Add the current item to the delete list ' [deleteItem] action$ = "delete_item" delete$(0) = selectedFile$ numDeletes = 1 goto [main]

' ' Go to the parent folder ' [goUp] action$ = "" newPath$ = myword$(currentPath$, 1, pathDelim$) for i = 2 to countItems(currentPath$, pathDelim$) - 1 newPath$ = newPath$ + pathDelim$ + myword$(currentPath$, i, pathDelim$) next i if Platform$ = "win32" and lower$(newPath$) = "c:" then message$ = "Due to a Run Basic bug, it is not possible to view the C:\ folder." else currentPath$ = newPath$ end if goto [main]

' ' Check login password ' [login] if #password contents$ = PASSWORD$ then action$ = "" else message$ = "Invalid password." end if goto [main]

' ' Rename an item ' [rename] action$ = "" newname$ = #newname contents$ if newname$ = "" then message$ = "No name supplied!" goto [main] end if

if not(validName(newname$)) then message$ = "Name contains invalid characters." goto [main] end if

if Platform$ = "win32" then message$ = shell$("rename " + escapeWin$(rename$) + " " + escapeWin$(newname$)) else newname$ = currentPath$ + pathDelim$ + newname$ message$ = shell$("mv " + escapeUnix$(rename$) + " " + escapeUnix$(newname$)) end if goto [main]

[resetCopy] numCopies = 0 copySize = 0 goto [main]

[resetCut] numCuts = 0 cutSize = 0 goto [main]

[setPath] action$ = "" if Platform$ = "win32" and lower$(EventKey$) = "c:" then message$ = "Due to a Run Basic bug, it is not possible to view the C:\ folder." else currentPath$ = EventKey$ end if goto [main]

[unexpectedError] if action$ = "view" then message$ = "An unexpected error occurred while trying to view '";selectedFile$;"'." else message$ = "An unexpected error has occurred Error Number: ";err;" Error Message: ";err$ end if action$ = "" goto [main]

[view] action$ = "view" selectedFile$ = EventKey$ goto [main]

' ' Return the last item in the list s$ delimted by d$ ' function lastItem$(s$, d$) for i = len(s$) to 1 step -1 if mid$(s$, i, 1) = d$ then exit for lastItem$ = mid$(s$, i, 1) + lastItem$ next i end function

' ' Return the number if items delimted by d$ in the list s$ ' function countItems(s$, d$) if s$ = "" then countItems = 0 else countItems = 1 for i = 1 to len(s$) if mid$(s$, i, 1) = d$ then countItems = countItems + 1 next i end if end function

' ' Test if the directory exists ' function dirExists(path$) on error goto [baddir] files #file, path$ if #file hasanswer then #file nextfile$ if #file isdir then dirExists = 1 end if end function

' ' Quote string for Windows shell ' function escapeWin$(s$) escapeWin$ = """" + s$ + """" end function

' ' Quote string for Unix Shell ' function escapeUnix$(s$) escapeUnix$ = "'" + replaceChar$(s$, "'", "'""'""'") + "'" end function

' ' Convert the path into a URL ' function downloadURL$(path$) downloadURL$ = mid$(path$, len(ResourcesRoot$) + 1) if pathDelim$ <> "/" then downloadURL$ = replaceChar$(downloadURL$, pathDelim$, "/") end if end function

' ' Get the file type (extension) ' function getFileType$(path$) name$ = lastItem$(path$, pathDelim$) if instr(name$, ".") = 0 then getFileType$ = "" else getFileType$ = lower$(lastItem$(path$, ".")) if len(getFileType$) > 4 then getFileType$ = "" end if end function

' ' Find the icon corresponding to the file type ' function getSmallIcon$(type$) for i = 0 to numIcons - 1 if lower$(type$ + ".gif") = lower$(ICON$(i)) then getSmallIcon$ = IMAGEURL$ + "/mime/" + ICON$(i) exit for end if next i  if getSmallIcon$ = "" then getSmallIcon$ = IMAGEURL$ + "/mime/empty.gif" end if end function

' ' Test if a file is in the public directory ' function isDownloadable(path$) if left$(path$, len(ResourcesRoot$) + 1) = ResourcesRoot$ + pathDelim$ then isDownloadable = 1 end function

' ' Test is a file appears to be text ' function isText(path$) isText = 1 open path$ for input as #in size = min(lof(#in) - 1, 40) a$ = input$(#in, size) for i = 1 to len(a$) c = asc(mid$(a$, i, 1)) select case c     case 9 case 10 case 13 case else if c 126 then isText = 0 exit for end if   end select next i close #in end function

' ' Just like word$ but returns any empty string instead ' of the delimiter if a word is missing ' function myword$(s$, n, d$) myword$ = word$(s$, n, d$) if myword$ = d$ then myword$ = "" end function

' ' Replaces all instances of the character c$ in the string s$ with the string r$ ' function replaceChar$(s$, c$, r$) for i = 1 to len(s$) a$ = mid$(s$, i, 1) if a$ = c$ then a$ = r$   replaceChar$ = replaceChar$ + a$  next i end function

' ' Format the size s (in bytes) as Kb ' function size$(s) kb = int((s / 1024) + 0.5) if kb = 0 then size$ = "< 1 Kb" else size$ = trim$(using("###,###,###,###", kb)) + " Kb" end if end function

' ' Check that name is a valid file/folder name ' function validName(name$) if instr(name$, pathDelim$) = 0 then validName = 1 if Platform$ = "win32" then for i = 1 to len(name$) if instr("<>:""/\|?*", mid$(name$, i, 1)) > 0 then validName = 0 exit for end if     next i      if right$(name$, 1) = "." then validName = 0 end if end if end function

' ' Add a file to the cut list ' sub cutItem name$, size for i = 0 to numCuts - 1 if cut$(i) = name$ then found = 1 exit for end if next i  if not(found) then cut$(numCuts) = name$ numCuts = numCuts + 1 cutSize = cutSize + size call removeCopy name$, size end if end sub

' ' Add a file to the copy list ' sub copyItem name$, size for i = 0 to numCopies - 1 if copy$(i) = name$ then found = 1 exit for end if next i  if not(found) then copy$(numCopies) = name$ numCopies = numCopies + 1 copySize = copySize + size end if end sub

' ' Copy a file from source$ to target$ ' sub copyFile source$, target$ open source$ for binary as #fin open target$ for binary as #fout size = lof(#fin) pos = 0 while pos < size r = min(size - pos, 2048) x$ = input$(#fin, r)   print #fout, x$; pos = pos + r wend close #fin close #fout end sub

' ' Copy a file from source$ to target$, then delete source$ ' sub moveFile source$, target$ call copyFile source$, target$ kill source$ end sub

' ' Remove a file from the copy list ' sub removeCopy name$, size for i = 0 to numCopies - 1 if copy$(i) = name$ then for j = i + 1 to numCopies - 1 copy$(j - 1) = copy$(j) next j     numCopies = numCopies - 1 copySize = copySize - size exit for end if next i end sub code