diff --git a/exec/default.js b/exec/default.js new file mode 100755 index 0000000000000000000000000000000000000000..1d95e8b60a8d518ec5019280292edee906cd62ef --- /dev/null +++ b/exec/default.js @@ -0,0 +1,255 @@ +// Default/Classic Synchronet Command Shell +// replaces default.src/bin + +// @format.tab-size 4 + +"use strict"; + +require("sbbsdefs.js", "K_UPPER"); +require("userdefs.js", "UFLAG_T"); +require("nodedefs.js", "NODE_MAIN"); +require("key_defs.js", "KEY_UP"); +require("text.js", "Pause"); +bbs.revert_text(Pause); +load("termsetup.js"); +var shell = load({}, "shell_lib.js"); + +const help_key = '?'; +// If user has unlimited time, display time-used rather than time-remaining +const time_code = user.security.exemptions & UFLAG_T ? "@TUSED@" : "@TLEFT@"; + +const main_menu = { + file: "main", + eval: 'bbs.main_cmds++', + node_action: NODE_MAIN, + prompt: "\x01-\x01c\xfe \x01b\x01hMain \x01n\x01c\xfe \x01h" + time_code + + " \x01n\x01c[\x01h@GN@\x01n\x01c] @GRP@\x01\\ [\x01h@SN@\x01n\x01c] @SUB@: \x01n", + num_input: shell.get_sub_num, + slash_num_input: shell.get_grp_num, + command: { + 'A': { eval: 'bbs.auto_msg()' }, + '/A': { exec: 'avatar_chooser.js' + ,ars: 'ANSI and not GUEST' + ,err: '\r\nSorry, only regular users with ANSI terminals can do that.\r\n' }, + 'B': { eval: 'bbs.scan_subs(SCAN_BACK)' + ,msg: '\r\n\x01c\x01hBrowse/New Message Scan\r\n' }, + 'C': { eval: 'bbs.chat_sec()' }, + 'D': { eval: 'bbs.user_config(); exit()' }, + 'E': { exec: 'email_sec.js' }, + 'F': { eval: 'bbs.scan_subs(SCAN_FIND)' + ,msg: '\r\n\x01c\x01hFind Text in Messages\r\n' }, + '/F': { eval: 'bbs.scan_subs(SCAN_FIND, /* all */true)' }, + 'G': { eval: 'bbs.text_sec()' }, + 'I': { eval: 'shell.main_info()' }, + 'J': { eval: 'shell.select_msg_area()' }, + 'L': { eval: 'bbs.list_msgs()' }, + '/L': { eval: 'bbs.list_nodes()' }, + 'M': { eval: 'bbs.time_bank()' }, + 'N': { eval: 'bbs.scan_subs(SCAN_NEW)' + ,msg: '\r\n\x01c\x01hNew Message Scan\r\n' }, + '/N': { eval: 'bbs.scan_subs(SCAN_NEW, /* all */true)' }, + 'O': { eval: 'shell.logoff(/* fast: */false)' }, + '/O': { eval: 'shell.logoff(/* fast: */true)' }, + 'P': { eval: 'bbs.post_msg()' }, + '/P': { exec: 'postpoll.js' }, + 'Q': { eval: 'bbs.qwk_sec()' }, + 'R': { eval: 'bbs.scan_msgs()' }, + 'S': { eval: 'bbs.scan_subs(SCAN_TOYOU)' + ,msg: '\r\n\x01c\x01hScan for Messages Posted to You\r\n' }, + '/S': { eval: 'bbs.scan_subs(SCAN_TOYOU, /* all */true)' }, + 'U': { eval: 'shell.list_users()' }, + '/U': { eval: 'bbs.list_users(UL_ALL)' }, + 'V': { exec: 'scanpolls.js' }, + '/V': { exec: 'scanpolls.js', args: ['all'] }, + 'W': { eval: 'bbs.whos_online()' }, + 'X': { eval: 'bbs.xtrn_sec()' }, + '/X': { eval: 'exit(0)' }, + 'Z': { eval: 'bbs.scan_subs(SCAN_NEW | SCAN_CONT)' + ,msg: '\r\n\x01c\x01hContinuous New Message Scan\r\n' }, + '/Z': { eval: 'bbs.scan_subs(SCAN_NEW | SCAN_CONT, /* all */true)' }, + '*': { eval: 'shell.show_subs(bbs.curgrp)' }, + '/*': { eval: 'shell.show_grps()' }, + '&': { exec: 'msgscancfg.js' }, + '!': { eval: 'bbs.menu("sysmain")' + ,ars: 'SYSOP or EXEMPT Q or I or N' }, + '#': { msg: '\r\n\x01c\x01hType the actual number, not the symbol.\r\n' }, + '/#': { msg: '\r\n\x01c\x01hType the actual number, not the symbol.\r\n' }, + }, + nav: { + '\r': { }, + 'T': { eval: 'shell.enter_file_section(); menu = file_menu' }, + '>': { eval: 'shell.sub_up()' }, + '}': { eval: 'shell.sub_up()' }, + ')': { eval: 'shell.sub_up()' }, + '+': { eval: 'shell.sub_up()' }, + '=': { eval: 'shell.sub_up()' }, + '<': { eval: 'shell.sub_down()' }, + '{': { eval: 'shell.sub_down()' }, + '(': { eval: 'shell.sub_down()' }, + '-': { eval: 'shell.sub_down()' }, + ']': { eval: 'shell.grp_up()' }, + '[': { eval: 'shell.grp_down()' }, + }, +}; + +// Can't do these statically through initialization: +main_menu.nav[KEY_UP] = { eval: 'shell.sub_up()' }; +main_menu.nav[KEY_DOWN] = { eval: 'shell.sub_down()' }; +main_menu.nav[KEY_RIGHT] = { eval: 'shell.grp_up()' }; +main_menu.nav[KEY_LEFT] = { eval: 'shell.grp_down()' }; + +const file_menu = { + file: "transfer", + eval: 'bbs.file_cmds++', + node_action: NODE_XFER, + prompt: "\x01-\x01c\xfe \x01b\x01hFile \x01n\x01c\xfe \x01h" + time_code + + " \x01n\x01c(\x01h@LN@\x01n\x01c) @LIB@\x01\\ (\x01h@DN@\x01n\x01c) @DIR@: \x01n", + num_input: shell.get_dir_num, + slash_num_input: shell.get_lib_num, + command: { + 'B': { eval: 'bbs.batch_menu()' }, + 'C': { eval: 'bbs.chat_sec()' }, + 'D': { eval: 'shell.download_files()' + ,msg: '\r\n\x01c\x01hDownload File(s)\r\n' + ,ars: 'REST NOT D' }, + '/D': { eval: 'shell.download_user_files()' + ,msg: '\r\n\x01c\x01hDownload File(s) from User(s)\r\n' + ,ars: 'REST NOT D' }, + 'E': { eval: 'shell.view_file_info(FI_INFO)' + ,msg: '\r\n\x01c\x01hList Extended File Information\r\n' }, + 'F': { eval: 'bbs.scan_dirs(FL_FINDDESC);' + ,msg: '\r\n\x01c\x01hFind Text in File Descriptions (no wildcards)\r\n' }, + '/F': { eval: 'bbs.scan_dirs(FL_FINDDESC, /* all: */true);' }, + 'I': { eval: 'shell.file_info()' }, + 'J': { eval: 'shell.select_file_area()' }, + 'L': { eval: 'shell.list_files()' }, + '/L': { eval: 'bbs.list_nodes()' }, + 'N': { eval: 'bbs.scan_dirs(FL_ULTIME)' + ,msg: '\r\n\x01c\x01hNew File Scan\r\n' }, + '/N': { eval: 'bbs.scan_dirs(FL_ULTIME, /* all */true)' }, + 'O': { eval: 'shell.logoff(/* fast: */false)' }, + '/O': { eval: 'shell.logoff(/* fast: */true)' }, + 'R': { eval: 'shell.view_file_info(FI_REMOVE)' + ,msg: '\r\n\x01c\x01hRemove/Edit File(s)\r\n' }, + 'S': { eval: 'bbs.scan_dirs(FL_NO_HDR)' + ,msg: '\r\n\x01c\x01hSearch for Filename(s)\r\n' }, + '/S': { eval: 'bbs.scan_dirs(FL_NO_HDR, /* all */true) ' }, + 'T': { eval: 'bbs.temp_xfer()' }, + 'U': { eval: 'shell.upload_file()' + ,msg: '\r\n\x01c\x01hUpload File\r\n' }, + '/U': { eval: 'shell.upload_user_file()' + ,msg: '\r\n\x01c\x01hUpload File to User\r\n' }, + 'V': { eval: 'shell.view_files()' + ,msg: '\r\n\x01c\x01hView File(s)\r\n' }, + 'W': { eval: 'bbs.whos_online()' }, + 'Z': { eval: 'shell.upload_sysop_file()' + ,msg: '\r\n\x01c\x01hUpload File to Sysop\r\n' }, + '*': { eval: 'shell.show_dirs(bbs.curlib)' }, + '/*': { eval: 'shell.show_libs()' }, + '&': { exec: 'filescancfg.js' }, + '!': { eval: 'bbs.menu("sysxfer")' }, + '#': { msg: '\r\n\x01c\x01hType the actual number, not the symbol.\r\n' }, + '/#': { msg: '\r\n\x01c\x01hType the actual number, not the symbol.\r\n' }, + }, + nav: { + '\r': { }, + 'Q': { eval: 'menu = main_menu' }, + '>': { eval: 'shell.dir_up()' }, + '}': { eval: 'shell.dir_up()' }, + ')': { eval: 'shell.dir_up()' }, + '+': { eval: 'shell.dir_up()' }, + '=': { eval: 'shell.dir_up()' }, + '<': { eval: 'shell.dir_down()' }, + '{': { eval: 'shell.dir_down()' }, + '(': { eval: 'shell.dir_down()' }, + '-': { eval: 'shell.dir_down()' }, + ']': { eval: 'shell.lib_up()' }, + '[': { eval: 'shell.lib_down()' }, + }, +}; + +// Can't do these statically through initialization: +file_menu.nav[KEY_UP] = { eval: 'shell.dir_up()' }; +file_menu.nav[KEY_DOWN] = { eval: 'shell.dir_down()' }; +file_menu.nav[KEY_RIGHT] = { eval: 'shell.lib_up()' }; +file_menu.nav[KEY_LEFT] = { eval: 'shell.lib_down()' }; + +var menu = main_menu; +var last_str_cmd = ""; + +// The menu-display/command-prompt loop +while(bbs.online && !js.terminated) { + if(!(user.settings & USER_EXPERT)) { + console.clear(); + bbs.menu(menu.file); + } + bbs.node_action = menu.node_action; + bbs.nodesync(); + eval(menu.eval); + console.crlf(); + console.aborted = false; + console.putmsg(menu.prompt, P_SAVEATR); + var cmd = console.getkey(K_UPPER); + log("cmd = " + ascii(cmd)); + if(cmd > ' ') + console.print(cmd); + if(cmd == ';') { + cmd = console.getstr(); + if(cmd == '!') + cmd = last_str_cmd; + js.exec("str_cmds.js", {}, cmd); + last_str_cmd = cmd; + console.line_counter = 0; + continue; + } + if(cmd == '/') { + cmd = console.getkey(K_UPPER); + console.print(cmd); + if(cmd >= '1' && cmd <= '9') { + menu.slash_num_input(cmd); + continue; + } + cmd = '/' + cmd; + } + if(cmd >= '1' && cmd <= '9') { + menu.num_input(cmd); + continue; + } + if(cmd > ' ') { + bbs.log_key(cmd, /* comma: */true); + } + if(menu.nav[cmd]) { + if(menu.nav[cmd].eval) + eval(menu.nav[cmd].eval); + continue; + } + console.crlf(); + console.line_counter = 0; + if(cmd == help_key) { + if(user.settings & USER_EXPERT) + bbs.menu(menu.file); + continue; + } + var menu_cmd = menu.command[cmd]; + if(!menu_cmd) { + console.print("\r\n\x01c\x01hUnrecognized command."); + if(user.settings & USER_EXPERT) + console.print(" Hit '\x01i" + help_key + "\x01n\x01c\x01h' for a menu."); + console.crlf(); + continue; + } + if(!bbs.compare_ars(menu_cmd.ars)) + console.print(menu_cmd.err); + else { + if(menu_cmd.msg) + console.print(menu_cmd.msg); + if(menu_cmd.eval) + eval(menu_cmd.eval); + if(menu_cmd.exec) { + if(menu_cmd.args) + js.exec.apply(null, [menu_cmd.exec, {}].concat(menu_cmd.args)); + else + js.exec(menu_cmd.exec, {}); + } + } +} diff --git a/exec/load/shell_lib.js b/exec/load/shell_lib.js new file mode 100755 index 0000000000000000000000000000000000000000..00bdc15356ed403ff09baf75205e3d4b90e24b76 --- /dev/null +++ b/exec/load/shell_lib.js @@ -0,0 +1,549 @@ +// Library for writing command shells +// portions derived from classic_shell.js, default.src, and exec*.cpp + +// @format.tab-size 4 + +"use strict"; + +require("text.js", "DownloadBatchQ"); +require("sbbsdefs.js", "USER_EXPERT"); + +// Build list of current subs/dirs in each group/library +// This hack is required because the 'bbs' object doesn't expose the current +// sub/dir for any group/library except the current +var curgrp = bbs.curgrp; +var curlib = bbs.curlib; +var cursub = []; +var curdir = []; +var usrsubs = []; +var usrdirs = []; +var usrgrps = msg_area.grp_list.length; +var usrlibs = file_area.lib_list.length; +for(var i = 0; i < usrgrps; ++i) { + bbs.curgrp = i; + cursub[i] = bbs.cursub; + usrsubs[i] = msg_area.grp_list[i].sub_list.length; +} +for(var i = 0; i < usrlibs; ++i) { + bbs.curlib = i; + curdir[i] = bbs.curdir; + usrdirs[i] = file_area.lib_list[i].dir_list.length; +} +bbs.curgrp = curgrp; +bbs.curlib = curlib; + +function get_num(str, max) +{ + var num = Number(str); + while(bbs.online && !js.terminated) { + if(num * 10 > max) + break; + var ch = console.getkey(K_UPPER); + if(ch < '0' || ch > '9') { + if(ch > ' ') + console.ungetstr(ch); + break; + } + console.print(ch); + num *= 10; + num += Number(ch); + if(num > max) + return 0; + } + return num; +} + +function get_grp_num(str) +{ + var num = get_num(str, usrgrps); + if(num > 0) + bbs.curgrp = num -1; +} + +function get_sub_num(str) +{ + var num = get_num(str, usrsubs[bbs.curgrp]); + if(num > 0) + bbs.cursub = num - 1; +} + +function get_lib_num(str) +{ + var num = get_num(str, usrlibs); + if(num > 0) + bbs.curlib = num -1; +} + +function get_dir_num(str) +{ + var num = get_num(str, usrdirs[bbs.curlib]); + if(num > 0) + bbs.curdir = num - 1; +} + +// List Message Groups +function show_grps() +{ + if(msg_area.grp_list.length < 1) + return; + if(bbs.menu("grps", P_NOERROR)) + return; + console.print(bbs.text(GrpLstHdr)); + for(var i=0; i < msg_area.grp_list.length && !console.aborted; i++) { + if(i == bbs.curgrp) + console.print('*'); + else console.print(' '); + if(i<9) console.print(' '); + console.add_hotspot(i+1); + console.print(format(bbs.text(GrpLstFmt), i+1 + ,msg_area.grp_list[i].description, "", msg_area.grp_list[i].sub_list.length)); + } +} + +function show_subs(grp) +{ + if(msg_area.grp_list.length < 1) + return; + if(bbs.menu("subs" + msg_area.grp_list[grp].number, P_NOERROR)) + return; + console.crlf(); + console.print(format(bbs.text(SubLstHdr), msg_area.grp_list[grp].description)); + for(var i=0; i < usrsubs[grp] && !console.aborted; ++i) { + if(i==cursub[grp]) console.print('*'); + else console.print(' '); + var str = format(bbs.text(SubLstFmt),i+1 + ,msg_area.grp_list[grp].sub_list[i].description, "" + ,msg_area.grp_list[grp].sub_list[i].posts); + if(i<9) console.print(' '); + if(i<99) console.print(' '); + console.add_hotspot(i+1); + console.print(str); + } +} + +function select_msg_area() +{ + if(usrgrps < 1) + return; + while(bbs.online) { + var j=0; + if(usrgrps > 1) { + show_grps(); + console.mnemonics(format(bbs.text(JoinWhichGrp), bbs.curgrp + 1)); + j=console.getnum(usrgrps); + console.clear_hotspots(); + if(j==-1) + return; + if(!j) + j=bbs.curgrp; + else + j--; + } + show_subs(j); + console.mnemonics(format(bbs.text(JoinWhichSub), cursub[j]+1)); + i=console.getnum(usrsubs[j]); + console.clear_hotspots(); + if(i==-1) { + if(usrgrps==1) + return; + continue; + } + if(!i) + i=cursub[j]; + else + i--; + bbs.curgrp=j; + bbs.cursub=i; + return; + } + return; +} + +// List File Libraries +function show_libs() +{ + if(file_area.lib_list.length < 1) + return; + if(bbs.menu("libs", P_NOERROR)) + return; + console.print(bbs.text(LibLstHdr)); + for(var i=0; i < file_area.lib_list.length && !console.aborted; i++) { + if(i == bbs.curlib) + console.print('*'); + else console.print(' '); + if(i<9) console.print(' '); + console.add_hotspot(i+1); + console.print(format(bbs.text(LibLstFmt), i+1 + ,file_area.lib_list[i].description, "", file_area.lib_list[i].dir_list.length)); + } +} + +function show_dirs(lib) +{ + if(file_area.lib_list.length < 1) + return; + if(bbs.menu("dirs" + file_area.lib_list[lib].number, P_NOERROR)) + return; + console.crlf(); + console.print(format(bbs.text(DirLstHdr), file_area.lib_list[lib].description)); + for(var i=0; i < usrdirs[lib] && !console.aborted; ++i) { + if(i==curdir[lib]) console.print('*'); + else console.print(' '); + var str = format(bbs.text(DirLstFmt),i+1 + ,file_area.lib_list[lib].dir_list[i].description, "" + ,file_area.lib_list[lib].dir_list[i].files); + if(i<9) console.print(' '); + if(i<99) console.print(' '); + console.add_hotspot(i+1); + console.print(str); + } +} + +function select_file_area() +{ + var usrlibs = file_area.lib_list.length; + if(usrlibs < 1) + return; + while(bbs.online) { + var j=0; + if(usrlibs > 1) { + show_libs(); + console.mnemonics(format(bbs.text(JoinWhichGrp), bbs.curlib + 1)); + j=console.getnum(usrlibs); + console.clear_hotspots(); + if(j==-1) + return; + if(!j) + j=bbs.curlib; + else + j--; + } + show_dirs(j); + console.mnemonics(format(bbs.text(JoinWhichDir), curdir[j]+1)); + i=console.getnum(usrdirs[j]); + console.clear_hotspots(); + if(i==-1) { + if(usrlibs==1) + return; + continue; + } + if(!i) + i=curdir[j]; + else + i--; + bbs.curlib=j; + bbs.curdir=i; + return; + } + return; +} + +function main_info() +{ + while(bbs.online && !js.terminate) { + if(!(user.settings & USER_EXPERT)) + bbs.menu("maininfo"); + bbs.nodesync(); + console.print("\r\n\x01y\x01hInfo: \x01n"); + var key = console.getkeys("?QISVY\r"); + bbs.log_key(key); + switch(key) { + case '?': + if(user.settings & USER_EXPERT) + bbs.menu("maininfo"); + break; + case 'I': + bbs.sys_info(); + break; + case 'S': + bbs.sub_info(); + break; + case 'Y': + bbs.user_info(); + break; + case 'V': + bbs.ver(); + break; + default: + return; + } + } +} + +// Prompts for new-file-scan the first time the user enters the file section +function enter_file_section() +{ + if(bbs.file_cmds > 0) + return; + if(!(user.settings & USER_ASK_NSCAN)) + return; + console.crlf(2); + if(console.yesno("Search all libraries for new files")) + bbs.scan_dirs(FL_ULTIME, /* all */true); +} + +function file_info() +{ + var key; + + while(1) { + if(!(user.settings & USER_EXPERT)) + bbs.menu("xferinfo"); + + // async + console.print("\r\n\x01y\x01hInfo: \x01n"); + key=console.getkeys("?TYDUQ\r"); + bbs.log_key(key); + + switch(key) { + case '?': + if(user.settings & USER_EXPERT) + bbs.menu("xferinfo"); + break; + + case 'T': + bbs.xfer_policy(); + break; + + case 'Y': + bbs.user_info(); + break; + + case 'D': + bbs.dir_info(); + break; + + case 'U': + bbs.list_users(UL_DIR); + break; + + case 'Q': + default: + return; + } + } +} + +function list_users() +{ + console.print("\r\n\x01c\x01hList Users\r\n"); + console.mnemonics("\r\n~Logons Today, ~Yesterday, ~Sub-board, or ~All: "); + switch(console.getkeys("LSAY\r")) { + case 'L': + bbs.list_logons(); + break; + case 'Y': + bbs.exec("?logonlist -y"); + break; + case 'S': + bbs.list_users(UL_SUB); + break; + case 'A': + bbs.list_users(UL_ALL); + break; + } +} + +function list_files() +{ + var result = bbs.list_files(); + if(result < 0) + return; + if(result == 0) + console.print(bbs.text(EmptyDir)); + else + console.print(format(bbs.text(NFilesListed), result)); +} + +function view_file_info(mode) +{ + var str=bbs.get_filespec(); + if(!str) + return; + if(!bbs.list_file_info(file_area.lib_list[bbs.curlib].dir_list[bbs.curdir].number, str, mode)) { + var s=0; + console.print(bbs.text(SearchingAllDirs)); + for(var i=0; i<file_area.lib_list[bbs.curlib].dir_list.length; i++) { + if(i!=bbs.curdir && + (s=bbs.list_file_info(file_area.lib_list[bbs.curlib].dir_list[i].number, str, mode))!=0) { + if(s==-1 || str.indexOf('?')!=-1 || str.indexOf('*')!=-1) { + return; + } + } + } + console.print(bbs.text(SearchingAllLibs)); + for(var i=0; i<file_area.lib_list.length; i++) { + if(i==bbs.curlib) + continue; + for(j=0; j<file_area.lib_list[i].dir_list.length; j++) { + if((s=bbs.list_file_info(file_area.lib_list[i].dir_list[j].number, str, mode))!=0) { + if(s==-1 || str.indexOf('?')!=-1 || str.indexOf('*')!=-1) { + return; + } + } + } + } + } +} + +function view_files() +{ + var str=bbs.get_filespec(); + if(!str) + return; + if(!bbs.list_files(file_area.lib_list[bbs.curlib].dir_list[bbs.curdir].number, str, FL_VIEW)) { + console.print(bbs.text(SearchingAllDirs)); + for(var i=0; i<file_area.lib_list[bbs.curlib].dir_list.length; i++) { + if(i==bbs.curdir) + continue; + if(bbs.list_files(file_area.lib_list[bbs.curlib].dir_list[i].number, str, FL_VIEW)) + break; + } + if(i<file_area.lib_list[bbs.curlib].dir_list.length) + return; + console.print(bbs.text(SearchingAllLibs)); + for(var i=0; i<file_area.lib_list.length; i++) { + if(i==bbs.curlib) + continue; + for(j=0; j<file_area.lib_list[i].dir_list.length; j++) { + if(bbs.list_files(file_area.lib_list[i].dir_list[j].number, str, FL_VIEW)) + return; + } + } + } +} + +function sub_up() +{ + if(bbs.cursub == msg_area.grp_list[bbs.curgrp].sub_list.length - 1) + bbs.cursub = 0; + else + bbs.cursub++; + cursub[bbs.curgrp] = bbs.cursub; +} + +function sub_down() +{ + if(bbs.cursub == 0) + bbs.cursub = msg_area.grp_list[bbs.curgrp].sub_list.length - 1; + else + bbs.cursub--; + cursub[bbs.curgrp] = bbs.cursub; +} + +function grp_up() +{ + if(bbs.curgrp == msg_area.grp_list.length - 1) + bbs.curgrp = 0; + else + bbs.curgrp++; +} + +function grp_down() +{ + if(bbs.curgrp == 0) + bbs.curgrp = msg_area.grp_list.length - 1; + else + bbs.curgrp--; +} + +function dir_up() +{ + if(bbs.curdir == file_area.lib_list[bbs.curlib].dir_list.length - 1) + bbs.curdir = 0; + else + bbs.curdir++; + curdir[bbs.curdir] = bbs.curdir; +} + +function dir_down() +{ + if(bbs.curdir == 0) + bbs.curdir = file_area.lib_list[bbs.curlib].dir_list.length - 1; + else + bbs.curdir--; + curdir[bbs.curdir] = bbs.curdir; +} + +function lib_up() +{ + if(bbs.curlib == file_area.lib_list.length - 1) + bbs.curlib = 0; + else + bbs.curlib++; +} + +function lib_down() +{ + if(bbs.curlib == 0) + bbs.curlib = file_area.lib_list.length - 1; + else + bbs.curlib--; +} + +function logoff(fast) +{ + if(bbs.batch_dnload_total && console.yesno(bbs.text(DownloadBatchQ))) + bbs.batch_download(); + else { + if(fast) + bbs.hangup(); + else + bbs.logoff(/* prompt: */true); + } +} + +function upload_file() +{ + bbs.menu("upload"); + var i=0xffff; /* INVALID_DIR */ + if(usrlibs) { + i = file_area.lib_list[bbs.curlib].dir_list[bbs.curdir].number; + if(file_area.upload_dir != undefined + && !file_area.lib_list[bbs.curlib].dir_list[bbs.curdir].can_upload) + i = file_area.upload_dir.number; + } + else { + if(file_area.upload_dir != undefined) + i = file_area.upload_dir.number; + } + bbs.upload_file(i); +} + +function upload_user_file() +{ + if(file_area.user_dir == undefined) + console.print(bbs.text(NoUserDir)); + else + bbs.upload_file(file_area.user_dir.number); +} + +function upload_sysop_file() +{ + if(file_area.sysop_dir == undefined) + console.print(bbs.text(NoSysopDir)); + else + bbs.upload_file(file_area.sysop_dir.number); +} + +function download_files() +{ + if(bbs.batch_dnload_total && console.yesno(bbs.text(DownloadBatchQ))) { + bbs.batch_download(); + return; + } + + view_file_info(FI_DOWNLOAD); +} + +function download_user_files() +{ + if(file_area.user_dir == undefined) + console.print(bbs.text(NoUserDir)); + else { + if(!bbs.list_file_info(file_area.user_dir, FI_USERXFER)) + console.print(bbs.text(NoFilesForYou)); + } +} + +this;