/*** *** Shadow Shell Display System [Version 4.6] *** - Created by Glenn Ferguson ( Watcher@TMI, GateWay ) *** *** Copyright (1993) - All Rights Reserved. *** *** TMI DISTRIBUTION VERSION *** *** You must have an ANSI compatible terminal to use the window *** portions of the shadow shell system. *** *** You are free to use any portion of this file as you wish, but *** please maintain my name in the header. If you have a bug fix or *** a better way of doing part of the shell, please let me know. :) *** *** Refer to the shell man page for detailed information on *** specific shell functions and commands. *** *** Updated: 09/18/1993 by kyosuke@moonstar to fix bug introduced *** when socket_create() efun in 0.9.17.17? driver was fixed. *** *** Updated: 10/08/1993 by Watcher@TMI-2 to allow extra \n option *** toggle for window scrolling. *** ***/ // Leto fixed bug in inheriting ansi.h (thorugh the say simul_efun // by renaming the HOME int to NO_ANSI_HOME jan-3 95 #include <mudlib.h> #include <net/daemons.h> #include <config.h> #include <net/socket.h> inherit OBJECT ; /* Commented out by Leto, it conflicted with inherited say.c which inherited ansi.h #define ESC "" #define CSI ESC + "[" #define BEEP "" */ #include <ansi.h> #define WHOM environment(this_object()) #define NAME capitalize((string)this_player()->query("name")) #define TIME extract(ctime(time() + (time_mod * 60)), 4, 15) #define HISTORY (string *)environment()->query_history() #define NULL ({ }) /** Null empty building array **/ #define SVERSION "4.6" /** Shadow Shell version number **/ #define COMMCHAR "/" /** Precharacter for commands **/ #define RCFILE ".ssrc" /** RC save file name **/ #define RCDEF 0 /** Default toggle of RCFILE save **/ #define MAX_ALARM 5 /** Default maximum allowed alarms **/ #define MAX_BUFFER 100 /** Maximum lines stored in buffer **/ #define MAXSOCKET 2 /** Max number of open connections **/ #define ALLOW 1 /** Insert Shell Security here **/ #define COLOUR ({ ({ "default","red","green","yellow","blue","magenta", \ "cyan","white","light red","light green","light yellow",\ "light blue","light magenta","high white" }), \ ({ "-","31","32","33","34","35","36","37","1;31","1;32",\ "1;33","1;34","1;35","1;36","1;37" }) }) // Function prototypes static string define_user_path(); static string query_socket_error(int err); static int restore_array(string array); static int add_buffer(string mesg); static int display_alarms(); static void init_divider(); static set_main_window(); static int send_mesg(string str, int win); static int file_completion(string str); static new_window_size(string size); static int shell_help(string str); static int setup_screen(); static int stop_shell(); static int mark_text(string str); static int unmark_text(string str); static int display_assign(); static int display_text_list(string str); static int save_rcfile(); static mixed *process_choice(string str); static mixed *process_users(); static string comm_catch(string mess); static int conduct_history(int num); nomask int socket_permission(); string save_array(); string process_dir(string str); static int vis_ck(); static int busy_ck(); // Global shell variables - Saved in RCFILE file mixed *window, *GAG, *HILITE, *ASSIGN, *ALARM, *PAGE; string *cursor, *divider, *hilight, *snoop, *buff; int MAX, time_mod, rcflag, fcflag, crflag; // Static global shell variables - Not retained in save file static object old_room; static mixed *sweep, *socket, *buff_pos; static string prompt, time, dir, *BUFFER, *TMP_BUFFER; static int Status, scheck, vis, busy, NOT_ANSI_HOME, help; create() { set("id", ({"shadow shell", "shell", "shsh"}) ); set("short", "Shadow shell"); set("long", "This is Watcher's Shadow Shell System [Version " + SVERSION + "]\nType \"help shell\" for shell commands.\n"); set("prevent_drop", 1); MAX = 24; /** Default Screen Length **/ NOT_ANSI_HOME = 1; /** Default Home Window **/ GAG = NULL; /** Setup GAG array **/ HILITE = NULL; /** Setup HILITE array **/ PAGE = NULL; /** Setup PAGE array **/ ASSIGN = ({ NULL, NULL }); /** Setup Assignment array **/ ALARM = NULL; /** Setup Alarm array **/ BUFFER = NULL; /** Setup Buffer holding array **/ socket = ({ NULL, NULL, NULL }); /** Setup socket system **/ rcflag = RCDEF; /** Set rcflag as default **/ buff_pos = ({ 0, 0 }); /** Buffer parameter setup **/ window = ({ 0,0,0,0,0,0 }); /** Window array framework **/ seteuid(getuid(this_object())); /** Set object permissions **/ cursor = ({ "default", "-" }); /** Setup default colour **/ divider = ({ "default", "-" }); hilight = ({ "default", "-" }); snoop = ({ "red", "0;31" }); buff = ({ "yellow", "1;33" }); } /** ** Override Simul_efun message rerouting ** - Necessary to maintain shell as previous_object() in ** message rerouting in /std/user.c's receive_message() **/ #include "/adm/simul_efun/write.c" #include "/adm/simul_efun/say.c" #include "/adm/simul_efun/tell_object.c" /** ** Shell's user command function **/ int command_user(string what) { this_player()->force_me(what); return 1; } /** ** Shell autoloading routines **/ string query_auto_load() { string par1; int par2; sscanf(file_name(this_object()),"%s#%d", par1, par2); if(save_rcfile()) return par1 + ":"; return par1 + ":" + NOT_ANSI_HOME + "||" + save_array(); } static int save_rcfile() { string where; if(WHOM && rcflag && (where = define_user_path()) != "") { save_object(where); return 1; } return 0; } init_arg(string arg) { string saved; if(!arg || arg == "") return; sscanf(arg,"%d||%s", NOT_ANSI_HOME, saved); restore_array(saved); MAX = window[ sizeof(window)-1 ]; return; } int clean_up() { return 1; } // Prevent inadvertant clean_up // Locate the user's RCFILE save directory static string get_home_path() { string name; name = (string) WHOM->query("name"); return "/u/" + extract(name,0,0) + "/" + name + "/"; } // Locate path to user's ssrc save file static string define_user_path() { if(file_size(get_home_path()) != -2) { tell_object(WHOM,"\nShsh: Error in locating user home directory.\n "+ "Reverting to autoload save format.\n"); rcflag = 0; return ""; } return get_home_path() + RCFILE; } // Restore saved shell attributes static int restore_attr_file() { string where; where = get_home_path(); if((!rcflag && window[0] != 0) || file_size(where) != -2 || file_size(where + RCFILE + SAVE_EXTENSION) < 0) return 1; restore_object(where + RCFILE); return 1; } string save_array() { /** Converts numeric array to a savable string **/ string array, temp; int loop; for(array="",loop=0; loop<sizeof(window); loop++) array += ( window[loop] + "," ); array += "X"; /** End point mark **/ return array; } /*** Converts loaded strings back into numeric array ***/ static int restore_array(string array) { int number; window = ({ }); while(sscanf(array,"%d,%s",number,array)==2) window += ({ number }); return 1; } void init() { // If the environment isn't a user ... remove the shell. if(environment() && !interactive(environment())) { remove(); return; } // Check user's permissions to use the shell if(!ALLOW || this_player() != environment()) return; // Set the shell's euid to that of the user seteuid(getuid(this_player())); add_action("player_quit", "quit"); add_action("command_catch", "", 1); add_action("system_config", "configure"); add_action("toggle_shell", "shsh"); add_action("clean_screen", "cls"); add_action("shell_help", "help"); add_action("add_window", "add"); add_action("rem_window", "remove"); add_action("refresh_shell", "refresh"); add_action("change_window", "change"); add_action("assign_comm", COMMCHAR + "assign"); add_action("unassign_comm", COMMCHAR + "unassign"); add_action("change_time", COMMCHAR + "time"); add_action("add_alarm", COMMCHAR + "alarm"); add_action("rem_alarm", COMMCHAR + "unalarm"); add_action("switch_window", COMMCHAR + "goto"); add_action("beep_other", COMMCHAR + "beep"); add_action("mark_text", COMMCHAR + "gag"); add_action("unmark_text", COMMCHAR + "ungag"); add_action("mark_text", COMMCHAR + "hilite"); add_action("unmark_text", COMMCHAR + "unhilite"); add_action("cr_toggle", COMMCHAR + "cr"); add_action("mark_text", COMMCHAR + "page"); add_action("unmark_text", COMMCHAR + "unpage"); add_action("shell_status", COMMCHAR + "status"); add_action("display_text_list", COMMCHAR + "history"); add_action("open_buffer", COMMCHAR + "buffer"); add_action("completion_mode", COMMCHAR + "fc"); add_action("conduct_history", COMMCHAR + "do"); if(socket_permission()) { add_action("connect_window", COMMCHAR + "open"); add_action("disconnect_window", COMMCHAR + "close"); } restore_attr_file(); /** Restore saved attributes **/ } // Designation of shadow shell version string query_version() { return SVERSION; } // Indicates shell activity status // - Returns 1 if shell is active, 0 if shell is inactive int query_status() { return Status; } // Function used by status window for maintaining status display static int status_check() { int scheck; if(vis_ck() != vis) { vis = vis_ck(); scheck = 1; } if(busy_ck() != busy) { busy = busy_ck(); scheck = 1; } return scheck; } /** Status Function checks **/ static vis_ck() { return (int)WHOM->query("invisible"); } static busy_ck() { return (int)WHOM->query("busy"); } /** ** ANSI Function/Window Library processing calls **/ static void Talk(string str) { tell_object(WHOM, str); } static void clear_window(int top, int bottom) { Talk(CSI + top + "H" + CSI + (bottom - top) + "M"); } static void win_size(int top, int bottom) { Talk(CSI+top+";"+bottom+"r"); } static void save_position() { Talk(ESC+"7"); } static void restore_position() { Talk(ESC+"8"); } static void new_pos(int pos) { Talk(CSI+pos+"H"); } static string invert(string mess) { if(hilight[1] != "-") // Add colour return (CSI + "7m" + CSI + hilight[1] + "m" + mess + CSI + "0m" + (cursor[1] != "-" ? CSI + cursor[1] + "m" : "")); else return (CSI + "7m" + mess + CSI + "0m" + (cursor[1] != "-" ? CSI + cursor[1] + "m" : "")); } static void erase_line(int pos) { Talk(CSI + pos + "H" + CSI + "2K"); } static void form_line(int pos, int wind) { save_position(); new_pos(pos); if(divider[1] != "-") Talk(CSI + divider[1] + "m"); /* Colour */ if(wind == -1) Talk("==[Communication]==================================================" + "============="); else if(wind) Talk("==[Window " + wind + "]============================================" + "========================"); else Talk("===================================================================" + "============"); if(divider[1] != "-") Talk(CSI + "0m"); /* Turn colour off */ if(cursor[1] != "-") Talk(CSI + cursor[1] + "m"); /* Cursor colour */ restore_position(); } // Place a description label on window separation divider static void label_line(string mesg, int win) { if(!mesg || mesg == "") { form_line(window[(NOT_ANSI_HOME*2)+2]-1, NOT_ANSI_HOME); return; } save_position(); new_pos(window[(win*2)+2]-1); Talk(CSI + "15C" + "[" + mesg + "]"); restore_position(); } /*** *** Return to main NOT_ANSI_HOME window *** - The main window can be changed by changing the NOT_ANSI_HOME *** variable to the new window number ***/ static int main_screen() { string tmp; int position; position = (NOT_ANSI_HOME + 1) * 2; if(position > sizeof(window)-1) { write("Error: Set home window is out of array bounds.\n"); return 0; } win_size(window[position],window[position+1]); if(member_array(query_verb(), ({ "shsh", "refresh" })) == -1) new_pos(window[position + 1]); else new_pos(window[position]); tmp = "" + (window[position + 1] - window[position]) + ""; environment()->setenv("LINES", tmp); /* Adjust pager to window size */ environment()->do_new(); return 1; } /** Write a message to a specific shell window ** ** - Window 0 is to the Communication window ** - Window 1 is to the main interactive window ** - Window X is to the Xth open window (Window 0 if X is nonexistent) ** ** Ex: write_window(0,"Watcher begins to glow.", "tell_object"); ** will write that message to the communication window. **/ void write_window(int num, string mess, string type) { string *tmp; int position, where; mess = comm_catch(mess); // Adjustment to message via gag/hilite/etc if(!mess || mess == "") return; if(previous_object() != this_object()) // Store message to buffer add_buffer(mess); // Label incoming snoop communication with optional colour if (type == "snoop") { if (snoop[0] != "default") mess = CSI + snoop[1] + "m" + mess + CSI + "0m"; else mess = mess[0..<2]; } // If the user is in a socket window, block any prompts from host mud if(mess == prompt && member_array(NOT_ANSI_HOME, socket[1]) != -1) return; // If message is a standard write message, dump straight to screen if(type == "write") { Talk( mess ); return; } tmp = explode(mess, "\n"); mess = implode(tmp, "\n"); if(!Status) mess += "\n"; // Reroute to window 1 if comm isn't present and // active window is 2 or greater. if(!num && !window[2] && NOT_ANSI_HOME > 1) num = 1; if((!num && !window[2]) || !Status) { Talk( mess ); // Relay incoming message if(mess == prompt) Talk("\n"); return; } where = member_array(type, ASSIGN[0]); /* Check for reassignment */ if(where != -1) num = ASSIGN[1][where]; if(num == -1) return 0; /* Communication redirected to nul */ // Located requested window access point position = (num + 1) * 2; if(position > sizeof(window)-1 || position < 2) position = 2; // Write incoming message to specified window save_position(); win_size(window[position], window[position+1]); new_pos(window[position+1]); mess = "\n" + mess; /** Scroll window up **/ Talk( mess + (crflag ? "\n" : "") ); main_screen(); restore_position(); return; } /** ** Mudlib Message communication relay ** - Called from receive_message() in user object **/ receive_message(string Class, string msg) { return write_window(0, msg, Class); } // Cycling refresh system for updating status window refresh_status() { int size; remove_call_out("refresh_status"); call_out("refresh_status",0); // Updated records of present user prompt prompt = (string)environment()->write_prompt(1); if(status_check()) { save_position(); new_pos(window[0] + 1); Talk("Status: "); if(vis_ck()) Talk("You are invisible "); else Talk("You are visible "); Talk("Busy flag: "); if(busy) Talk("Active "); else Talk("Inactive "); Talk("Time: " + TIME ); time = TIME; restore_position(); } if(time != TIME) { save_position(); Talk(CSI + "2;53HTime: " + TIME ); time = TIME; restore_position(); } if(environment(WHOM) == old_room && (string)environment()->query("cwd") == dir) return; old_room = environment(WHOM); dir = (string)environment()->query("cwd"); save_position(); new_pos(window[0]); erase_line(window[0]); Talk("["+file_name(environment(WHOM))+"] "); Talk(invert((string)environment(WHOM)->query("short"))); size = strlen(" [Cwd: " + process_dir(dir) + "] "); Talk(CSI + "0;" + (81-size) + "H [Cwd: " + process_dir(dir) + "] "); restore_position(); } // Setup outline and preliminary status of status window static create_status() { old_room = 0; vis = -1; if(window[1] == MAX) form_line(MAX - 3, 1); else if(window[2]) form_line(window[1], -1); else form_line(window[1], 1); refresh_status(); return 1; } // Command function for activating/deactivating shell system int toggle_shell(string str) { if(Status) notify_fail("Your Shadow shell is presently active.\n" + "Usage: shsh [on/off]\n"); else notify_fail("Your Shadow shell is presently inactive.\n" + "Usage: shsh [on/off]\n"); if(str == "on") return setup_screen(); else if(str == "off") return stop_shell(); return 0; } // Draw window divisions and setup initial shell systems static setup_screen() { if(!window[0] && !window[2] && !window[4]) { write("Your shell system has not been configured.\n"); return 1; } if(Status) { write("Your shell system is already active.\n"); return 1; } Talk(CSI + "2J"); // Clears user string Talk(CSI + "0m"); // Reset Screen colours if(cursor[1] != "-") Talk(CSI + cursor[1] + "m"); // Cursor colour if(window[0]) create_status(); init_divider(); main_screen(); Status = 1; if(query_verb() == "shsh") Talk("Shadow Shell enabled.\n"); return 1; } // Creates divider lines for each created window static void init_divider() { int loop, pos; if(!window[2]) pos = 6; else pos = 4; for(loop=pos; loop<sizeof(window); loop += 2) form_line(window[loop - 1]+1, loop/2-1); } /** ** Shell System User configuration **/ static system_config(string str) { notify_fail("Usage: configure shell\n"); if(!id(str)) return 0; // Clear previous window setup designations NOT_ANSI_HOME = 1; window = ({ 0,0,0,0,0,0 }); remove_call_out("refresh_status"); write("Shadow Shell Configuration\n\n"); write(" Input your screen length [Default 24] : "); input_to("screen_length"); return 1; } static screen_length(string length) { int temp; if(!length || length == "") { write(" Default screen length maintained.\n"); MAX = 24; } else { temp = atoi(length); if(!intp(temp) || temp < 1) { write("\n Invalid shell screen length.\n"); write(" Input your screen length [Default 24] : "); input_to("screen_length"); return 1; } MAX = temp; } write("\n Change default screen colours [yes/no] : "); input_to("change_colour"); return 1; } static change_colour(string str) { string hold; int loop; if(!str || member_array(lower_case(str),({"yes","y","no","n"})) == -1) { write(" Change default screen colours [yes/no] : "); input_to("change_colour"); return 1; } if(member_array(lower_case(str), ({ "no", "n" })) != -1) { write("\n Initiate status window [yes/no] : "); input_to("status_set"); return 1; } hold = "\nAvailable colours: "; for(loop=0; loop<sizeof(COLOUR[0]); loop++) { hold += COLOUR[0][loop]; if(loop < sizeof(COLOUR[0])-1) hold += ", "; if(loop == sizeof(COLOUR[0])-2) hold += "and "; } write(wrap(hold + ".") + "\n"); write(" [Please Note: Not all terminals support all above colours]\n\n"); write(" Cursor [" + cursor[0] + "] : "); input_to("cursor_colour"); return 1; } static cursor_colour(string str) { int pos; if(!str || str == "") { write(" Colour unchanged.\n\n Dividers [" + divider[0] + "] : "); input_to("divider_colour"); return 1; } pos = member_array(lower_case(str), COLOUR[0]); if(pos == -1) { write(" Cursor [" + cursor[0] + "] : "); input_to("cursor_colour"); return 1; } write(" Colour changed.\n"); cursor[0] = COLOUR[0][pos]; cursor[1] = COLOUR[1][pos]; write("\n Dividers [" + divider[0] + "] : "); input_to("divider_colour"); return 1; } static divider_colour(string str) { int pos; if(!str || str == "") { write(" Colour unchanged.\n\n Snooping [" + snoop[0] + "] : "); input_to("snoop_colour"); return 1; } pos = member_array(lower_case(str), COLOUR[0]); if(pos == -1) { write(" Dividers [" + divider[0] + "] : "); input_to("divider_colour"); return 1; } write(" Colour changed.\n"); divider[0] = COLOUR[0][pos]; divider[1] = COLOUR[1][pos]; write("\n Snooping [" + snoop[0] + "] : "); input_to("snoop_colour"); return 1; } static snoop_colour(string str) { int pos; if(!str || str == "") { write(" Colour unchanged.\n\n Buffer [" + buff[0] + "] : "); input_to("buffer_colour"); return 1; } pos = member_array(lower_case(str), COLOUR[0]); if(pos == -1) { write(" Snooping [" + snoop[0] + "] : "); input_to("snoop_colour"); return 1; } write(" Colour changed.\n"); snoop[0] = COLOUR[0][pos]; snoop[1] = COLOUR[1][pos]; write("\n Hilights [" + hilight[0] + "] : "); input_to("hilight_colour"); return 1; } static buffer_colour(string str) { int pos; if(!str || str == "") { write(" Colour unchanged.\n\n Hilights [" + hilight[0] + "] : "); input_to("hilight_colour"); return 1; } pos = member_array(lower_case(str), COLOUR[0]); if(pos == -1) { write(" Buffer [ " + buff[0] + "] : "); input_to("buffer_colour"); return 1; } write(" Colour changed.\n"); buff[0] = COLOUR[0][pos]; buff[1] = COLOUR[1][pos]; write("\n Hilights [" + hilight[0] + "] : "); input_to("hilight_colour"); return 1; } static hilight_colour(string str) { int pos; if(!str || str == "") { write(" Colour unchanged.\n\n Initiate status window [yes/no] : "); input_to("status_set"); return 1; } pos = member_array(lower_case(str), COLOUR[0]); if(pos == -1) { write(" Hilights [" + hilight[0] + "] : "); input_to("hilight_colour"); return 1; } write(" Colour changed.\n"); hilight[0] = COLOUR[0][pos]; hilight[1] = COLOUR[1][pos]; write("\n Initiate status window [yes/no] : "); input_to("status_set"); return 1; } static status_set(string str) { if(str == "yes" || str == "y") { window[0] = 1; window[1] = 3; } else if(str == "no" || str == "n") { window[0] = 0; window[1] = 0; } else { write(" Initiate status window [yes/no] : "); input_to("status_set"); return 1; } write("\n Initiate communication window [yes/no] : "); input_to("comm_set"); return 1; } static comm_set(string str) { if(str == "yes" || str == "y") { write("\n Communication window size [Default 5] : "); input_to("set_comm_size"); return 1; } else if(str == "no" || str == "n") { window[2] = 0; window[3] = 0; } else { write(" Initiate communication window [yes/no] : "); input_to("comm_set"); return 1; } set_main_window(); write("\n Save attributes in a record file? [Default: "); if(rcflag) write("yes] "); else write("no] "); input_to("rcfile_choice"); return 1; } static set_comm_size(string size) { int temp; if(!size || size == "") { write(" Default communication window size maintained.\n"); temp = 5; } else { temp = atoi(size); if(!intp(temp) || temp < 1) { write("\n Invalid communication window size.\n"); write(" Communication window size [Default 5] : "); input_to("set_comm_size"); return 1; } } if(!window[0]) window[2] = 1; else window[2] = 4; window[3] = window[2] + temp; set_main_window(); write("\n Save attributes in a record file? [Default: "); if(rcflag) write("yes] "); else write("no] "); input_to("rcfile_choice"); return 1; } static rcfile_choice(string str) { string where; if(str!="" && !(member_array(lower_case(str),({"yes","y","no","n"}))+1)) { write("\n Invalid choice responce (yes/no)\n Save attributes in a " + "record file? [Default: "); if(rcflag) write("yes] "); else write("no] "); input_to("rcfile_choice"); return 1; } if(str == "yes" || str == "y" || str == "Y") rcflag = 1; else if(str == "no" || str == "n" || str == "N") rcflag = 0; if(rcflag && (where = define_user_path()) != "") { if(file_size(where + SAVE_EXTENSION) > -1) write(" Updating shell \"" + RCFILE + "\" file.\n"); else write(" Creating shell \"" + RCFILE + "\" file.\n"); save_rcfile(); } write("\nShell configuration complete.\n"); if(Status) write("Type \"refresh shell\" to update screen setup.\n"); return 1; } static set_main_window() { if(!window[0] && !window[2]) { window[4] = 1; window[5] = MAX; return 1; } if(window[2]) { window[4] = window[3] + 2; window[5] = MAX; return 1; } window[4] = window[1] + 1; window[5] = MAX; return 1; } // Modify time display according to user's timezone position static int change_time() { write("Present Mud time\t: " + extract(ctime(time()), 4, 15) + "\n" + "Present Shell time\t: " + TIME + "\n\n" + "Shell time zone modification [" + time_mod + " minutes] : "); input_to("modify_time"); return 1; } static int modify_time(string str) { int num; if(!str || str == "") { write("Time zone modification unchanged.\n"); return 1; } if(str == "none") str = "0"; if(sscanf(str, "%d", num) != 1) { write("Illegal modification. Value unchanged.\n"); return 1; } write("Time modification changed.\n"); time_mod = num; save_rcfile(); return 1; } // Terminate and clear shell screen system static stop_shell() { int loop; remove_call_out("refresh_status"); // Remove shell LINES designation size and replace any // previous line environmental setup. this_player()->remove_env("LINES"); this_player()->do_new(); if(!Status) { write("Your shell system is not active.\n"); return 1; } // Close and clear any open shell terminal sockets for(loop=0; loop<sizeof(socket[0]); loop++) socket_close(socket[0][loop]); socket = ({ NULL, NULL, NULL }); // Clear and reset screen and cursor write(CSI + "0r"); write(CSI + "H" + CSI + "J"); write(CSI + "0m"); /** Reset cursor colour **/ // Save present shell designations before terminating activity if(rcflag) save_rcfile(); Status = 0; write("Shadow Shell disabled.\n"); return 1; } // Command used to clear screen or specified windows int clean_screen(string str) { int temp; notify_fail("Usage: cls || cls comm || cls [window]\n"); // If shell isn't active, clear entire screen if(!Status) { write(CSI + "0r"); write(CSI + "H" + CSI + "J"); write("Screen cleared.\n"); return 1; } // If no window is specified, clear active window if(!str || str == "") { clear_window(window[(NOT_ANSI_HOME*2)+2], window[(NOT_ANSI_HOME*2)+3]); new_pos(window[(NOT_ANSI_HOME*2)+2]); return 1; } if(str == "comm" || str == "communication") { save_position(); win_size(window[2], window[3]); clear_window(window[2], window[3]+1); win_size(window[4], window[5]); restore_position(); return 1; } if(sscanf(str,"%d",temp)!=1 || temp < 0) return 0; if(!temp) return clean_screen("comm"); if(temp == 1) return clean_screen(""); if((temp*2)+3 > sizeof(window)) { write("There is no such window open.\n"); return 1; } save_position(); win_size(window[(temp*2)+2], window[(temp*2)+3] + 1); clear_window(window[(temp*2)+2], window[(temp*2)+3] + 2); win_size(window[(NOT_ANSI_HOME*2)+2], window[(NOT_ANSI_HOME*2)+3]); restore_position(); return 1; } // Command used to add an additional window to active set static add_window(string str) { int num; notify_fail("Usage: add window\n"); if(str != "window" && sscanf(str,"window %d", num) != 1) return 0; if(!Status) { write("You must be in shell mode to add a new window.\n"); return 1; } if(num) return new_window_size("" + num + ""); write("Input size of new window : "); input_to("new_window_size"); return 1; } static new_window_size(string size) { int temp, last; if(!size || size == "") { write("New window initiation aborted.\n"); return 1; } if(sscanf(size,"%d",temp)!=1 || temp < 1) { write("Illegal new window size. Initiation aborted.\n"); return 1; } // Check to see if new window size is possible last = sizeof(window) - 2; if(temp >= (window[last+1] - window[last])) { write("New window length is too large for present configuration.\n"); return 1; } // Clear lowest window, and add new window at requested size clear_window(window[last], MAX - 1); window[last + 1] -= (temp + 2); window += ({ (window[last + 1] +2) }); window += ({ MAX }); form_line(window[last + 1]+1, sizeof(window)/2-2); main_screen(); return 1; } static refresh_shell(string str) { notify_fail("Usage: refresh shell\n"); if(!id(str)) return 0; if(!Status) { write("Your shell system is not active.\n"); return 1; } Status = 0; time = 0; /* force status screen rewrite */ return setup_screen(); } static rem_window(string str) { int last, pos; notify_fail("Usage: remove window\n"); if(str != "window") return 0; if(!Status) { write("Your shell system is not active.\n"); return 1; } last = sizeof(window) - 1; if(last == 5) { write("You do not have any extra windows open.\n"); return 1; } pos = member_array((last/2 - 1), socket[1]); if(pos != -1) { /* Close socket if one is present */ socket[0] = exclude_array(socket[0], pos); socket[1] = exclude_array(socket[1], pos); } if(NOT_ANSI_HOME == (last/2 -1)) NOT_ANSI_HOME--; last = last -2; window[last] = MAX; /** Wipe contents of the old window **/ save_position(); win_size(window[last - 1], window[last]); clean_screen("" + (last/2-1)); restore_position(); main_screen(); window = window[0..last]; return 1; } /** ** Send a beep signal to another player **/ static beep_other(string str) { object target; notify_fail("Usage: " + query_verb() + " [player]\n"); if(!str || str == "") return 0; target = find_player(str); if(!target) { write("No such player is active.\n"); return 1; } tell_object(target, BEEP + NAME + " signals you.\n"); write("You signal " + capitalize(str) + ".\n"); return 1; } int shell_help(string str) { if(str == "window" || str == "windows") { write("\nWindow Message-Output Information\n" + "---------------------------------\n\n" + "If you wish a certain output to be placed into a particular window\n"+ "of the active shadow shell, simply use the following patch to the shell\n"+ "in the target's inventory:\n\n"+ " present(\"shell\",target)->write_window(window #, message, " + "Class);\n\n" + "If you want a message patched to the communication window, then the\n" + "window number is 0, with windows increasing in number from there. If\n" + "the window doesn't exist, the shell will relay to the communication\n" + "window. Adding a Class designation is optional, and allows the shell\n" + "to further adjust the input according to preset window assignments.\n\n"); return 1; } if(str == "shsh long" || str == "shell long") { help = 1; write("\n"); command_user("help shsh"); help = 0; return 1; } if(!id(str) || help) return 0; write("\nWatcher's Shadow Shell [Version " + SVERSION + "]\n" + "----------------------\n\n"); write(" Window Commands:\n"); write(" - shsh [on/off], configure shell, refresh shell\n"); write(" - add window, remove window, change window, " + COMMCHAR + "goto [num], cls [comm/window]\n\n"); write(" Message Manipulation Commands:\n"); write(" - " + COMMCHAR + "gag [string], " + COMMCHAR + "ungag [string/#]" + ", " + COMMCHAR + "hilite [string], " + COMMCHAR + "unhilite [string/#]\n"); write(" - " + COMMCHAR + "page [string], " + COMMCHAR + "unpage [string/#]\n"); write(" - " + COMMCHAR + "assign [Class] to [window], " + COMMCHAR + "unassign [Class]\n\n"); if(socket_permission()) { write(" Socket Control Commands:\n"); write(" - " + COMMCHAR + "open [ip number], " + COMMCHAR + "close\n\n"); } write(" Miscellaneous Shell Commands:\n"); write(" - " + COMMCHAR + "time, " + COMMCHAR + "beep [player], " + COMMCHAR + "fc, " + COMMCHAR + "status, " + COMMCHAR + "history, " + COMMCHAR + "do, " + COMMCHAR + "buffer, " + COMMCHAR + "cr\n"); write(" - " + COMMCHAR + "alarm [time in minutes] [optional message], " + COMMCHAR + "unalarm [alarm number]\n"); write("\nType \"help shsh long\" for the shadow shell's man page.\n" + "You must have an ANSI terminal to use the shell window " + "functions.\n\n"); return 1; } // If the user quits the mud...deactivate shell, then complete quit int player_quit() { if(Status) stop_shell(); return 0; } static change_window(string str) { notify_fail("Usage: change window\n"); if(str != "window") return 0; write("Input new home window : "); input_to("switch_window"); return 1; } switch_window(string str) { int num; if(!str || sscanf(str,"%d",num)!=1 || !intp(num) || num < 0) { notify_fail("Invalid new window selection.\n"); return 0; } if(!num) { notify_fail("You cannot select the communication window as your NOT_ANSI_HOME" + " window.\n"); return 0; } if(num == NOT_ANSI_HOME) { notify_fail("You are already active in that window.\n"); return 0; } if( (num*2 + 2) > sizeof(window)-1) { notify_fail("There is no such window presently open.\n"); return 0; } NOT_ANSI_HOME = num; main_screen(); if(member_array(NOT_ANSI_HOME, socket[1]) != -1) input_to("socket_catch", 0); return 1; } // Check incoming communication for gag/hilite/etc content // and manipulate as required static string comm_catch(string mess) { string tmp1, tmp2; int loop; for(loop=0; loop<sizeof(GAG); loop++) if(sscanf(" " + mess + " ", "%s" + GAG[loop] + "%s",tmp1,tmp2) == 2) return 0; for(loop=0; loop<sizeof(HILITE); loop++) if(sscanf(" " + mess + " ", "%s" + HILITE[loop] + "%s",tmp1,tmp2) == 2) mess = invert(mess); for(loop=0; loop<sizeof(PAGE); loop++) if(sscanf(" " + mess + " ", "%s" + PAGE[loop] + "%s",tmp1,tmp2) == 2) Talk(BEEP); return mess; } static int mark_text(string str) { mixed *tmp; string verb; int loop; sscanf(query_verb(), COMMCHAR + "%s", verb); notify_fail("Usage: " + query_verb() + " [string]\n"); if(verb == "gag") tmp = GAG; else if(verb == "hilite") tmp = HILITE; else if(verb == "page") tmp = PAGE; if(!str || str == "") { if(tmp == NULL) { write("You have no " + verb + " strings stored.\n"); return 0; } display_text_list(verb); return 0; } if(member_array(str, tmp) > -1) { write("You have already placed a " + verb + " on that string.\n"); return 1; } if(verb == "gag") GAG += ({ str }); else if(verb == "hilite") HILITE += ({ str }); else PAGE += ({ str }); write("You place a " + verb + " on the string : \"" + str + "\".\n"); save_rcfile(); return 1; } static int unmark_text(string str) { mixed *fill; string verb; int tmp; sscanf(query_verb(), COMMCHAR + "%s", verb); notify_fail("There is no such " + verb + " string entry.\n"); if(verb == "ungag") fill = GAG; else if(verb == "unhilite") fill = HILITE; else fill = PAGE; if(!str || str == "") { display_text_list(verb); write("\nUsage: " + query_verb() + " [string / #]\n"); return 1; } if(member_array(str, fill) > -1) { if(verb == "ungag") GAG -= ({ str }); else if(verb == "unhilite") HILITE -= ({ str }); else PAGE -= ({ str }); write("You remove the " + verb + " on the string : \"" + str + "\".\n"); save_rcfile(); return 1; } if(sscanf(str, "%d", tmp) == 1) { if(tmp > sizeof(fill)) return 0; write("You remove the " + verb + " on the string : \"" + fill[tmp - 1] + "\".\n"); if(verb == "ungag") GAG -= ({ GAG[tmp - 1] }); else if(verb == "unhilite") HILITE -= ({ HILITE[tmp - 1] }); else PAGE -= ({ PAGE[tmp - 1] }); save_rcfile(); return 1; } return 0; } static int display_text_list(string str) { mixed *tmp; int loop; if(query_verb() == COMMCHAR + "history") { str = "history"; tmp = HISTORY; } else if(str == "gag") tmp = GAG; else if(str == "hilite") tmp = HILITE; else tmp = PAGE; if(str == "history") { write("Present Stored History list:\n"); for(loop=sizeof(tmp)-1; loop>-1; loop--) write(" " + (loop + 1) + "] " + tmp[loop] + "\n"); write("\n"); return 1; } if((str == "ungag" && GAG == NULL) || (str == "unhilite" && HILITE == NULL) || (str == "unpage" && PAGE == NULL)) { write("There are presently no stored " + capitalize(str) + " strings."); return 0; } write("Present Stored " + capitalize(str) + " Strings:\n"); for(loop=0; loop<sizeof(tmp); loop++) write(" " + (loop + 1) + "] " + tmp[loop] + "\n"); write("\n"); return 1; } // Assign rerouting message functions static int display_assign() { int loop; if(!ASSIGN[0] || ASSIGN[0] ==({ })) { write("You have no assigned communication classes.\n"); return 1; } write("\nPresently reassigned communication classes:\n"); for(loop=0; loop<sizeof(ASSIGN[0]); loop++) if(ASSIGN[1][loop] == -1) write(" " + (loop + 1) + "] " + ASSIGN[0][loop] + " to nul\n"); else if(!ASSIGN[1][loop]) write(" " + (loop + 1) + "] " + ASSIGN[0][loop] + " to " + "communication window.\n"); else write(" " + (loop + 1) + "] " + ASSIGN[0][loop] + " to window " + ASSIGN[1][loop] + "\n"); write("\n"); return 1; } static int assign_comm(string str) { string Class; int where, num; notify_fail("Usage: " + query_verb() + " [Class] to [window]\n"); if(!str || str == "") { display_assign(); return 0; } if(sscanf(str,"%s to nul", Class) == 1) where = -1; else if(sscanf(str,"%s to comm", Class) == 1) where = 0; else if(sscanf(str,"%s to %d", Class, where) != 2) return 0; if(where > sizeof(window)/2-2 || where < -1) { write("Illegal window assignment. Must be an open window.\n"); return 1; } num = member_array(Class, ASSIGN[0]); if(num == -1) { if(where > 0) write("Class " + Class + " communication assigned to window " + where + ".\n"); else if(!where) write("Class " + Class + " communication assigned to " + "communication window.\n"); else write("Class " + Class + " communication ignored.\n"); ASSIGN[0] += ({ Class }); ASSIGN[1] += ({ where }); save_rcfile(); return 1; } if(where == -1) write("Class " + Class + " communication ignored.\n"); else if(!where) write("Class " + Class + " communication reassigned to " + "communication window.\n"); else write("Class " + Class + " communication reassigned to window " + where + ".\n"); ASSIGN[1][num] = where; save_rcfile(); return 1; } static int unassign_comm(string str) { int num; notify_fail("Usage: " + query_verb() + " [communication Class]\n"); if(!str || str == "") return 0; num = member_array(str, ASSIGN[0]); if(num == -1) { write("You have not assigned " + str + " Class to a particular window.\n"); return 1; } ASSIGN[0] = exclude_array(ASSIGN[0], num); ASSIGN[1] = exclude_array(ASSIGN[1], num); write("You remove the " + str + " Class window assignment.\n"); save_rcfile(); return 1; } // Shell status output display static int shell_status() { write("\nShadow Shell Status\n===================\n"); write("\n File Completion : "); if(fcflag) write("[active]\n"); else write("[inactive]\n"); write("\n Save Method : "); if(rcflag) write(define_user_path() + ".o file recall\n"); else write("Autoload recall\n"); write("\n"); display_alarms(); if(GAG != NULL) display_text_list("gag"); else write("You have no active gag strings.\n"); if(HILITE != NULL) display_text_list("hilite"); else write("You have no active hilite strings.\n"); if(PAGE != NULL) display_text_list("page"); else write("You have no active page strings.\n"); display_assign(); write("\n"); return 1; } command_catch(string str) { mixed *tmp; string action, what; int num, pos; // Complete full verb with action if(!str) action = query_verb(); else action = query_verb() + " " + str; // Parse for window redirecting of action if(sscanf(action,"/%d %s", num, what) == 2) return send_mesg(what, num); // Check for file completion request in action if(file_completion(action)) return 1; // Check for history request via keyboard arrow keys // This option will not work if mudlib has ANSI set define off if(member_array(query_verb(),({ CSI+"A", CSI+"B", CSI+"C", CSI+"D" })) != -1) return conduct_history(1); tmp = explode(query_verb(), CSI); if(sizeof(tmp) > 1) return conduct_history(sizeof(tmp)); return 0; } // Conduct action history request... // The shell accesses the player's history list via tsh static int conduct_history(int num) { string *tmp, what; if(num && stringp(num)) sscanf(num, "%d", num); if(!num || num < 1 || num > sizeof(HISTORY)) { write("Shsh: History request outside of set bounds.\n"); return 1; } if(query_verb() != COMMCHAR + "do") num--; tmp = HISTORY; what = tmp[num]; write("Doing: " + what + "\n"); command_user(what); return 1; } // This function allows file path completion of sorts. // If the last character in the file path is a *, then the // shell will try to complete the path as best it can. static int file_completion(string str) { mixed *tmp, *result; string command; // If file completion is off or last char isn't a *, then ignore if(!fcflag || str[strlen(str)-1] != '*') return 0; // Break command into its word subsets and process last word tmp = explode(str, " "); result = process_choice(tmp[sizeof(tmp)-1]); // Indicate shell's ability to complete the file path if(!result || !sizeof(result)) write("Shsh: Unable to complete designated filename [" + tmp[sizeof(tmp)-1] + "]\n"); else if(sizeof(result) > 1) write("Shsh: Multiple possible filename completions [" + tmp[sizeof(tmp)-1] + "]\n"); // Otherwise complete and initiate the command else { tmp[sizeof(tmp)-1] = result[0]; command = implode(tmp, " "); command_user(command); } return 1; } // The function does the directory searches in an attempt // to complete the requested command's file path. static mixed *process_choice(string str) { mixed *dir, *tmp, *hold; string file, where, patt, dump; int loop; // Obtain user's present active directory file = resolv_path("cwd", str); // Obtain the requested file's root path tmp = explode(file, "/"); where = "/" + implode(tmp[0..(sizeof(tmp)-2)], "/") + "/"; // Form file search pattern if(sscanf(tmp[sizeof(tmp)-1],"%s\*",patt) == 1) patt += "%s"; // Get requested directory contents dir = get_dir(where); // Get all possible filenames that would match requested pattern for(hold = ({}),loop=0; loop<sizeof(dir); loop++) if(sscanf(dir[loop], patt, dump) == 1) hold += ({ (where + dir[loop]) }); return hold; } static int completion_mode(string str) { if(fcflag) notify_fail("Shell file completion is presently active.\n" + "Usage: " + query_verb() + " [on/off]\n"); else notify_fail("Shell file completion is presently inactive.\n" + "Usage: " + query_verb() + " [on/off]\n"); if(str != "on" && str != "off") return 0; if(str == "on") { if(fcflag) write("Shell file completion is already active.\n"); else { write("Shell file completion is now active.\n"); fcflag = 1; } return 1; } if(!fcflag) write("Shell file completion is already inactive.\n"); else { write("Shell file completion is now inactive.\n"); fcflag = 0; } return 1; } /*** *** Alarm processing subroutines ***/ static mixed *process_alarm_calls() { mixed *calls; int loop; // Get list of active alarms in the queue calls = call_out_info(); for(loop=sizeof(calls)-1; loop>-1; loop--) if(calls[loop][1] != "initiate_alarm") calls = exclude_array(calls, loop); return calls; } static int display_alarms() { mixed *calls; int loop, remainder; calls = process_alarm_calls(); if(sizeof(calls) < 1) return 1; // No alarm calls in queue write("Alarm calls presently in the queue:\n"); for(loop=0; loop<sizeof(calls); loop++) { remainder = (calls[loop][2]%60); write((loop + 1) + "] " + ALARM[loop] + "\n Time remaining: " + (calls[loop][2]/60) + " minutes, " + remainder + " seconds.\n"); } write("\n"); return 1; } static int add_alarm(string str) { string mesg; int num; notify_fail("Usage: " + query_verb() + " [time in minutes] " + "[optional description]\n"); if(!str || str == "") { display_alarms(); return 0; } if(sizeof(ALARM) > MAX_ALARM-1) { write("You can only have a maximum of " + MAX_ALARM + " alarms.\n"); return 1; } if(sscanf(str, "%d %s", num, mesg) != 2 && sscanf(str, "%d", num) != 1) return 0; if(num < 1) return 0; else num = num * 60; // Convert to minute format if(!mesg || mesg == "") mesg = "none"; // Set no mesg string ALARM += ({ mesg }); call_out("initiate_alarm", num); write("You set the \"" + mesg + "\" alarm to sound in " + (num/60) + " minutes.\n"); return 1; } static int rem_alarm(string str) { mixed *calls; int num, loop; notify_fail("Usage: " + query_verb() + " [alarm number]\n"); if(!str || str == "" || sscanf(str, "%d", num) != 1) return 0; calls = process_alarm_calls(); if(num < 1 || num > sizeof(calls)) { notify_fail("There is no such alarm sequence set.\n"); return 0; } while(find_call_out("initiate_alarm") != -1) remove_call_out("initiate_alarm"); // Clear the queue for(loop=0; loop<sizeof(calls); loop++) { // Replace the queue if(loop == num-1) continue; // minus removed alarm call_out("initiate_alarm", calls[loop][2]); } write("You remove \"" + ALARM[num-1] + "\" from alarm queue.\n"); ALARM = exclude_array(ALARM, num-1); return 1; } // Give the beep on the alarm call static int call_alarm() { int loop; for(loop=0; loop<40; loop++) tell_object(WHOM, BEEP); return 1; } static void initiate_alarm() { tell_object(WHOM,"Alarm: " + ALARM[0] + "\n"); call_alarm(); ALARM = exclude_array(ALARM, 0); // Remove message from stack return; } // Shadow Shell Window socket systems // // This shell has an imbedded window-socket system which allows // a user to open a window to another mud. While this is a very // useful shell ability, an admin should be careful as to how open // they leave the permissions to this system. Such window socket // telneting basically leaves the user anonymous to the remote // sites (ie: they will have your host system's ip number). Various // schemes are being worked on to allow passing of the user's ip // address to the remote system, but at this release time, no // such system is available. // // It should be noted that much of the shell's socket system was // based upon the excellent work of Jacques@TMI (Dwayne Fontenot). // Without his socket system within the driver and related mudlib // support, many of our excellent intermud systems would not exist. // Many thanks Jacques!! // Insert shell socket use permissions here // - Returns 1 to allow, returns 0 to disallow nomask int socket_permission() { // Place your socket restrictions here...if you wish to restrict it. :) return 1; } /*** *** Window socket handling routines ***/ int connect_window(string str) { mapping mudlist; string mudname; int ret, pos; notify_fail("What numeric address do you wish to connect to?\n" + "Usage: " + query_verb() + " [numeric address] [port]\n"); if(!Status) { notify_fail("You cannot open a connection without an active window.\n"); return 0; } if(!str || str == "") return 0; if(sizeof(socket[0]) == MAXSOCKET) { write("This shell can only accept " + MAXSOCKET + " linked windows.\n"); return 1; } if(member_array(NOT_ANSI_HOME, socket[1]) != -1) { write("This window already has an open connection.\n"); return 1; } // Open socket and link it to present window socket[0] += ({ socket_create(STREAM,"receive_data","socket_shutdown") }); socket[1] += ({ NOT_ANSI_HOME }); pos = sizeof(socket[0]) - 1; // Check for mud name match in host name server mudlist = DNS_MASTER->query_mud_info(str); if(mudlist && mudlist["HOST"] && mudlist["PORT"]) { mudname = capitalize(str); str = mudlist["HOST"] + " " + mudlist["PORT"]; } write("Trying : " + str + "\n"); // Try to connect window to requested ip address ret = socket_connect(socket[0][pos], str, "receive_data", "write_data"); // If unable to open connection, remove link from window if(ret != EESUCCESS) { printf("Unable to connect: %s.\n", query_socket_error(ret)); socket[0] = exclude_array(socket[0], sizeof(socket[0])-1); socket[1] = exclude_array(socket[1], sizeof(socket[1])-1); return 1; } label_line("Open : " + (mudname ? mudname + " - " : "") + str, NOT_ANSI_HOME); write("[Connection is now open]\n"); socket[2] += ({ str }); input_to("socket_catch", 0); return 1; } int disconnect_window(string str) { int ret, pos, num; if(!Status) { notify_fail("You do not have a connected window open.\n"); return 0; } // Locate requested window for socket closure if(!str || str == "") num = NOT_ANSI_HOME; else if(sscanf(str, "window %d", num) != 1) sscanf(str,"%d", num); pos = member_array(num, socket[1]); if(pos == -1) { write("This window does not have an open connection.\n"); return 1; } // Attempt to close open socket ret = socket_close(socket[0][pos]); if(ret != EESUCCESS) { printf("Unable to disconnect: %s.\n", query_socket_error(ret)); return 1; } // Remove socket designation from window system socket[0] = exclude_array(socket[0], pos, pos); socket[1] = exclude_array(socket[1], pos, pos); socket[2] = exclude_array(socket[2], pos, pos); label_line(0, num); write_window(num,"[Connection is now closed]\n\n", "telnet"); return 1; } // Catch all outgoing commands in socket window static int socket_catch(string str) { string tmp; int num; if(member_array(NOT_ANSI_HOME, socket[1]) == -1) return command_user(str); if(str == "cls" || sscanf(str, "cls %s", tmp) == 1 || sscanf(str, COMMCHAR + "%d %s", tmp, num) == 2) { command_user(str); input_to("socket_catch", 0); return 1; } if(str == COMMCHAR + "close" || sscanf(str, COMMCHAR + "close %s", tmp) == 1) return disconnect_window(tmp); if(sscanf(str, COMMCHAR + "goto %s", tmp) == 1) { if(!switch_window(tmp)) { input_to("socket_catch", 0); return 0; } return 1; } send_mesg(str, 0); input_to("socket_catch", 0); return 1; } // Send a specific action to a specified window static int send_mesg(string str, int win) { int ret, pos; if(win) pos = member_array(win, socket[1]); else pos = member_array(NOT_ANSI_HOME, socket[1]); if(pos == -1) { command_user(str); return 1; } ret = socket_write(socket[0][pos], str + "\n"); if(ret != EESUCCESS) printf("Unable to send command: %s.\n", query_socket_error(ret)); return 1; } void receive_data(int where, string mess) { int pos; pos = member_array(where, socket[0]); if(pos == -1) { write("Error: Incoming message could not be routed to a window.\n"); return; } if(socket[1][pos] == NOT_ANSI_HOME) Talk( mess ); else write_window(socket[1][pos], mess, "telnet"); return; } void socket_shutdown(int where) { int ret, pos; pos = member_array(where, socket[0]); if(pos == -1) return; ret = socket_close(socket[0][pos]); if(ret != EESUCCESS) printf("Unable to close socket: %s.\n", query_socket_error(ret)); label_line(0, socket[1][pos]); write_window(socket[1][pos], "[Connection is now closed]\n\n", "telnet"); socket[0] = exclude_array(socket[0], pos, pos); socket[1] = exclude_array(socket[1], pos, pos); socket[2] = exclude_array(socket[2], pos, pos); return; } mixed *query_socket() { return socket; } // This function returns a string description of // socket error returned by the driver static string query_socket_error(int err) { // These errors are designated in /include/socket_errors.h switch(err) { case EESOCKET : case EESETSOCKOPT : return "Could not create socket link"; case EENONBLOCK : return "Could not set non-blocking mode"; case EENOSOCKS : return "No more available socket links"; case EEFDRANGE : return "Descriptor out of range"; case EEBADF : return "Descriptor is invalid"; case EESECURITY : return "Security violation attempt"; case EEISBOUND : return "Accessed socket is already bound"; case EEADDRINUSE : return "Requested address already in use"; case EEBIND : return "Problem with socket binding"; case EEGETSOCKNAME : return "Problem locating requested address"; case EEMODENOTSUPP : return "Socket mode is not supported"; case EENOADDR : return "Socket not bound to an address"; case EEISCONN : return "Set socket is already connected"; case EELISTEN : return "Problem with socket listen"; case EENOTLISTN : return "Set socket is not listening"; case EEWOULDBLOCK : return "Requested operation would block"; case EEINTR : return "Interrupted system call"; case EEACCEPT : return "Problem with socket accept"; case EEISLISTEN : return "Socket is already listening"; case EEBADADDR : return "Invalid internet address format"; case EEALREADY : return "Operation is already in progress"; case EECONNREFUSED : return "Connection refused"; case EECONNECT : return "Problem with socket connection"; case EENOTCONN : return "Socket is not connected"; case EETYPENOTSUPP : return "Object type not supported"; case EESENDTO : return "Problem with sendto functions"; case EESEND : return "Problem with send functions"; case EECALLBACK : return "Wait for socket callback"; case EESOCKRLSD : return "Socket link is already released"; case EESOCKNOTRLSD : return "Socket link not released"; } return ("Socket error #" + err); } // Shell's message storage buffer system functions static int add_buffer(string mesg) { string *tmp; int loop; // Do not save prompt outputs in buffer if(mesg == prompt) return 1; // Divide incoming message into individual lines tmp = explode(mesg, "\n"); // Add individual lines to buffer for(loop=0; loop<sizeof(tmp); loop++) { if(sizeof(BUFFER) > MAX_BUFFER) BUFFER = BUFFER[1..MAX_BUFFER]; BUFFER += ({ tmp[loop] + "\n" }); } return 1; } // Outputs buffer to screen in colour or non-colour // depending on user's setting. static int print_buffer(string str) { if(buff[0] == "default") write(str + CSI + "10Z"); else write(CSI + buff[1] + "m" + str + CSI + "0m" + CSI + "10Z"); return 1; } static int open_buffer() { int loop, win_size, base; if(!Status) { write("The buffer recall can only be used when the shell is active.\n"); return 1; } // Clean present screen and setup buffer output clean_screen(""); win_size = window[(NOT_ANSI_HOME*2)+3] - window[(NOT_ANSI_HOME*2)+2]; label_line("Buffer view open -- Up : \"u\" Down : \"d\" Quit : " + "\"q\"", NOT_ANSI_HOME); // Load present buffer into a temporary buffer. This is necessary // so the main buffer can continue to be added to while the user is // viewing the old buffer contents. TMP_BUFFER = BUFFER; TMP_BUFFER = ({ "[Top of Buffer]\n" }) + TMP_BUFFER + ({ "[End of Buffer]" }); // Determine output buffer contents and window size base = sizeof(TMP_BUFFER) - win_size - 2; if(base < 0) { buff_pos[1] = window[(NOT_ANSI_HOME*2)+3] + base; base = 0; } else buff_pos[1] = window[(NOT_ANSI_HOME*2)+3]; for(loop=base; loop<sizeof(TMP_BUFFER); loop++) print_buffer(TMP_BUFFER[loop]); // Save present buffer line position buff_pos[0] = sizeof(TMP_BUFFER) - 1; get_char("process_buffer", 1); return 1; } static int process_buffer(string str) { if(str == "q" || str == "Q" || str == ESC) { label_line(0, NOT_ANSI_HOME); new_pos(window[(NOT_ANSI_HOME*2)+3]); write("\n[Buffer view closed]\n"); return 1; } if(str == "d") { // If buffer request is beyond the end...ignore and beep if(buff_pos[0] > sizeof(TMP_BUFFER)-2) write(BEEP); // Otherwise move cursor down...if at bottom of the window, // scroll screen down and display next buffer line. else { buff_pos[0]++; if(buff_pos[1] != window[(NOT_ANSI_HOME*2)+3]) { buff_pos[1]++; write(CSI + "B"); } else print_buffer(TMP_BUFFER[buff_pos[0]]); } } if(str == "u") { // If request is above the top of the buffer, ignore and beep if(buff_pos[0] == 0) write(BEEP); // Otherwise move cursor up...If at the top of the window, // scroll window down and output above buffer line. else { buff_pos[0]--; if(buff_pos[1] != window[(NOT_ANSI_HOME*2)+2]-1) { write(CSI + "A"); buff_pos[1]--; } else { write(ESC + "M"); print_buffer(TMP_BUFFER[buff_pos[0]]); write(CSI + "A"); } } } get_char("process_buffer", 1); return 1; } // This function is used to strip user dir pre-name // and substitute a ~ in the displayed path. string process_dir(string str) { string tmp1, tmp2; if(sscanf(str, HOME_DIRS + "%s/%s", tmp1, tmp2) == 2) return "~" + tmp2 + "/"; return str + "/"; } // This function allows the user to toggle an extra carriage // return on or off depending on their terminal needs. int cr_toggle() { write("You toggle the carriage return " + (crflag ? "off" : "on") + ".\n"); crflag = !crflag; save_rcfile(); return 1; }