/* Do not remove the headers from this file! see /USAGE for more info. */ #include <mudlib.h> #include <commands.h> inherit SHELL; inherit M_SHELLVARS; inherit M_PROMPT; inherit M_COMPLETE; inherit M_GETOPT; inherit M_REGEX; #define WIZ_CMD_DIRS ({CMD_DIR_NO_RESTRICT "/", CMD_DIR_RESTRICT "/",\ CMD_DIR_CREATE "/", CMD_DIR_PLAYER "/"}) #define ADMIN_CMD_DIRS ({CMD_DIR_NO_RESTRICT "/", CMD_DIR_RESTRICT "/",\ CMD_DIR_CREATE "/", CMD_DIR_PLAYER "/", CMD_DIR_ADMIN "/" }) private nosave string path; int expand_vars; void set_expand_vars(int i) { expand_vars = i; } int is_variable(string name); private mixed check_for_nuggets(string array args); private void cmd_rehash() { CMD_D->cache(map(path,(:evaluate_path:))); write("Okay.\n"); } private mixed evaluate_code(mixed code) { string dir; code = reg_assoc(code,({"\\$[a-zA-Z0-9]+"}),({0}))[0]; code = map(code, (: (strlen($1) > 1 && $1[0] == '$' && is_variable($1[1..])) ? "(get_user_variable(\""+$1[1..]+"\"))" : $1 :)); code = implode(code, ""); // don't chop access if (check_privilege(1)) dir = "/trans/tmp"; else if (file_size(dir = wiz_dir(this_user())) != -2) dir = "/tmp"; if(is_file(wiz_dir(this_user())+"/eval.h")) return exec_code(code, dir, wiz_dir(this_user())+"/eval.h"); else return exec_code(code, dir); } private nomask string * expand_arguments(string* argv) { int i, n; if ( this_user() != query_owner() ) error("get your own shell, asswipe!\n"); n = sizeof(argv); for( i = 0; i < n; i++) { if(strlen(argv[i])>2 && argv[i][0] == '`' && argv[i][<1] == '`') { if(catch(argv[i] = evaluate_code(argv[i][1..<2]))) return 0; } } return argv; } // called when the value of the "path" variable changes private void set_path(string arg) { if (!arrayp(arg)) return; arg = filter(arg, (: stringp :)); path = map(arg, (: evaluate_path :)); } string query_path() { // New shells need to query this to get the saved value if (!path) set_path(get_variable("path")); return path; } private void fix_path() { set_variable("path", WIZ_CMD_DIRS); if(query_owner() && adminp(query_owner())) set_variable("path", ADMIN_CMD_DIRS); printf("Ok, your path is fixed.\n"); } private void show_shell_help() { more_file("/help/wizard/shell"); } private void create() { if ( !clonep() ) return; ::create(); prompt::create(); set_privilege(1); /* set up to save variables through the M_SAVE api */ setup_for_save(); arg_to_words_func = (: argument_explode :); } protected void prepare_shell() { ::prepare_shell(); set_if_undefined("path", WIZ_CMD_DIRS); if(query_owner() && adminp(query_owner())) set_if_undefined("path", ADMIN_CMD_DIRS); set_if_undefined("pwd", "/"); set_if_undefined("cwf", 0); shell_bind_if_undefined("resetpath", (: fix_path :)); shell_bind_if_undefined("?", (: show_shell_help :)); shell_bind_if_undefined("set", (: cmd_set :)); shell_bind_if_undefined("unset", (: cmd_unset :)); shell_bind_if_undefined("rehash", (: cmd_rehash :)); add_variable_hook("path", (: set_path :)); } string query_shellname() { return "wish (Lima wizard shell) v. 0.9"; } varargs protected void execute_command(string original_input) { string * argv = explode(original_input, " "); mixed tmp; string path = query_path(); mixed cmd_info; string channel_name; mixed orig_argv; mixed stdin_info; mixed extra_args; mixed nugget_info; mixed remaining_implode_info; string virgin_input; string array implode_info; /* BEGINNING OF EXPANSION */ tmp = evaluate(arg_to_words_func, implode(argv," ")); argv = tmp[0]; implode_info = tmp[1]; if(sizeof(argv) == 1 && argv[0][0] == '$' && strlen(argv[0]) > 1) { print_variable(argv[0][1..]); return; } if(sizeof(argv) > 1) argv = argv[0..0] + map(argv[1..], (: expand_if_variable($1,1) :)); // In some shells, this is the hook for doing username completion, // globbing, flag pre-parsing, etc... In others, it's used to execute // code encased in ` `'s. argv = expand_arguments( argv - ({ "" }) - ({})); if(!argv) return; if(wizardp(this_user())) argv = map(argv, (: (stringp($1)) ? replace_string($1,"\\`","`") : $1 :)); // check for if this is a variable setting. if(sizeof(argv) > 2 && argv[1] == "=" && strlen(argv[0]) > 1 && argv[0][0] == '$') { if(sizeof(argv) == 3) set_variable(argv[0][1..],expand_if_variable(argv[2])); else set_variable(argv[0][1..], implode_by_arr(map(argv[2..], (: expand_if_variable :)), implode_info[2..])); return; } // Expand variables if(expand_vars) argv = map(argv, (: expand_if_variable :)); // ### wtf is this? // Hmm, I might undo this one... the only reason this is here is to // allow \\$ to work right. \$ can work right in other ways.... argv = map(argv, (: stringp($1) ? replace_string($1, "\\$","$") : $1 :)); // If there is a local shell command that matches our input, try to // execute it. if (!sizeof(argv)) return; evaluate(tmp=dispatch[argv[0]], argv, implode_info); if(tmp) return; /* END OF EXPANSION */ orig_argv = argv; virgin_input = implode_by_arr(map(orig_argv[1..], (:stringp($1)?$1:sprintf("%O",$1):)), implode_info[1..])[1..]; nugget_info = check_for_nuggets(argv); argv = nugget_info[0]; stdin_info = nugget_info[1]; extra_args = nugget_info[2]; remaining_implode_info = implode_info[sizeof(argv)..]; implode_info = implode_info[1..(sizeof(argv)-1)]+({""}); if(sizeof(implode_info) && (implode_info[0][0..0] == " ")) implode_info[0] = implode_info[0][1..]; /* find and execute the given command */ cmd_info = CMD_D->smart_arg_parsing(argv, path, implode_info); if ( !intp(cmd_info) ) { if(strlen(virgin_input) == strlen(original_input)) virgin_input = ""; while(1) { mixed tmp2; cmd_info = cmd_info[0]->call_main(cmd_info[2], cmd_info[1], stdin_info, extra_args, implode_info, remaining_implode_info, virgin_input); if(!cmd_info) return; stdin_info = cmd_info[1]; implode_info = cmd_info[2]; nugget_info = check_for_nuggets(cmd_info[0]); argv = nugget_info[0]; extra_args = nugget_info[2]; tmp2 = argv; if(arrayp(extra_args)) tmp2 += extra_args; if(!sizeof(tmp2)) { write("error: pipe to nothing.\n"); return; } virgin_input = implode_by_arr(tmp2[1..], implode_info[(sizeof(implode_info)-sizeof(tmp2))..]); if(virgin_input[0] == ' ') virgin_input = virgin_input[1..]; remaining_implode_info = implode_info[sizeof(argv)..]; implode_info = implode_info[1..(sizeof(argv)-1)]+({""}); if(sizeof(implode_info) && (implode_info[0][0..0] == " ")) implode_info[0] = implode_info[0][1..]; cmd_info = CMD_D->smart_arg_parsing(argv,path,implode_info); if(intp(cmd_info)) { if (sizeof(argv)) printf("error: pipe to %s failed.\n", argv[0]); else write("error: pipe to nothing.\n"); return; } } } if ( cmd_info > 0 ) { if ( cmd_info != 1 ) printf("Found command is uncallable.\n"); return; } if( cmd_info == -2) { printf("Unable to finish command.\n"); return; } if (!sizeof(argv)) { printf("Nothing before pipe.\n"); return; } if (this_body()) { /* use the parser to try the command */ if ( this_body()->do_game_command(original_input) ) return; /* try a channel */ channel_name = CHANNEL_D->is_valid_channel(orig_argv[0], this_user()->query_channel_list()); if ( channel_name ) { int chan_type = channel_name[0..4] == "imud_"; CHANNEL_D->cmd_channel(channel_name, virgin_input, chan_type); return; } if(is_file(CMD_DIR_VERBS "/" + argv[0] + ".c")) write(this_body()->nonsense()); else printf("I don't know the verb '%s'.\n", argv[0]); } else { if (is_file(CMD_DIR_VERBS "/" + argv[0] + ".c")) write("Can't use verb with no body.\n"); else printf("I don't know the verb '%s'.\n", argv[0]); } } void set_pwd(string fname) { set_variable("lastpwd", get_variable("pwd")); set_variable("pwd", fname); } void swap_pwd() { set_pwd(get_variable("lastpwd")); } void set_cwf(string fname) { set_variable("cwf", fname); } void setup_for_save() { ::setup_for_save(); shellvars::setup_for_save(); } protected mixed what_prompt() { return (: get_prompt :); } protected nomask string query_save_path(string userid) { return WSHELL_PATH(userid); } // Support for IO redirection private mixed check_for_nuggets(string array args) { int i,j; string array stdinstuff = 0; i = member_array("<",args); if(i != -1) { j = i+1; while((j < sizeof(args)) && (args[j] != ">") && (args[j] != ">>") && (args[j] != "|") && (args[j] != "<")) j++; stdinstuff = args[i+1..(j-1)]; args = args[0..(i-1)] + args[j..]; } for(i=0;i<sizeof(args);i++) { if(stringp(args[i])) switch(args[i]) { case "|": case ">": case ">>": return ({args[0..(i-1)], stdinstuff, args[i..]}); default: break; } } return ({args, stdinstuff, 0}); }