tmi2_fluffos_v2/
tmi2_fluffos_v2/bin/
tmi2_fluffos_v2/etc/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/ChangeLog.old/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/Win32/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/compat/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/compat/simuls/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/include/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/clone/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/command/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/data/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/etc/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/include/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/inherit/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/inherit/master/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/log/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/compiler/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/efuns/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/operators/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/u/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/tmp/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/windows/
tmi2_fluffos_v2/lib/
tmi2_fluffos_v2/lib/adm/
tmi2_fluffos_v2/lib/adm/daemons/languages/
tmi2_fluffos_v2/lib/adm/daemons/network/I3/
tmi2_fluffos_v2/lib/adm/daemons/virtual/
tmi2_fluffos_v2/lib/adm/daemons/virtual/template/
tmi2_fluffos_v2/lib/adm/news/
tmi2_fluffos_v2/lib/adm/obj/
tmi2_fluffos_v2/lib/adm/obj/master/
tmi2_fluffos_v2/lib/adm/priv/
tmi2_fluffos_v2/lib/adm/shell/
tmi2_fluffos_v2/lib/adm/tmp/
tmi2_fluffos_v2/lib/cmds/
tmi2_fluffos_v2/lib/d/
tmi2_fluffos_v2/lib/d/Conf/
tmi2_fluffos_v2/lib/d/Conf/adm/
tmi2_fluffos_v2/lib/d/Conf/boards/
tmi2_fluffos_v2/lib/d/Conf/cmds/
tmi2_fluffos_v2/lib/d/Conf/data/
tmi2_fluffos_v2/lib/d/Conf/logs/
tmi2_fluffos_v2/lib/d/Conf/obj/
tmi2_fluffos_v2/lib/d/Conf/text/help/
tmi2_fluffos_v2/lib/d/Fooland/adm/
tmi2_fluffos_v2/lib/d/Fooland/data/
tmi2_fluffos_v2/lib/d/Fooland/data/attic/
tmi2_fluffos_v2/lib/d/Fooland/items/
tmi2_fluffos_v2/lib/d/TMI/
tmi2_fluffos_v2/lib/d/TMI/adm/
tmi2_fluffos_v2/lib/d/TMI/boards/
tmi2_fluffos_v2/lib/d/TMI/data/
tmi2_fluffos_v2/lib/d/TMI/rooms/
tmi2_fluffos_v2/lib/d/grid/
tmi2_fluffos_v2/lib/d/grid/adm/
tmi2_fluffos_v2/lib/d/grid/data/
tmi2_fluffos_v2/lib/d/std/
tmi2_fluffos_v2/lib/d/std/adm/
tmi2_fluffos_v2/lib/data/adm/
tmi2_fluffos_v2/lib/data/adm/daemons/
tmi2_fluffos_v2/lib/data/adm/daemons/doc_d/
tmi2_fluffos_v2/lib/data/adm/daemons/emoted/
tmi2_fluffos_v2/lib/data/adm/daemons/network/http/
tmi2_fluffos_v2/lib/data/adm/daemons/network/services/mail_q/
tmi2_fluffos_v2/lib/data/adm/daemons/network/smtp/
tmi2_fluffos_v2/lib/data/adm/daemons/news/archives/
tmi2_fluffos_v2/lib/data/attic/connection/
tmi2_fluffos_v2/lib/data/attic/user/
tmi2_fluffos_v2/lib/data/std/connection/b/
tmi2_fluffos_v2/lib/data/std/connection/l/
tmi2_fluffos_v2/lib/data/std/user/a/
tmi2_fluffos_v2/lib/data/std/user/b/
tmi2_fluffos_v2/lib/data/std/user/d/
tmi2_fluffos_v2/lib/data/std/user/f/
tmi2_fluffos_v2/lib/data/std/user/l/
tmi2_fluffos_v2/lib/data/std/user/x/
tmi2_fluffos_v2/lib/data/u/d/dm/working/doc_d/
tmi2_fluffos_v2/lib/data/u/l/leto/doc_d/
tmi2_fluffos_v2/lib/data/u/l/leto/smtp/
tmi2_fluffos_v2/lib/doc/
tmi2_fluffos_v2/lib/doc/driverdoc/applies/
tmi2_fluffos_v2/lib/doc/driverdoc/applies/interactive/
tmi2_fluffos_v2/lib/doc/driverdoc/concepts/
tmi2_fluffos_v2/lib/doc/driverdoc/driver/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/arrays/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/buffers/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/compile/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/ed/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/filesystem/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/floats/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/functions/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/general/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/mappings/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/numbers/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/parsing/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/constructs/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/preprocessor/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/types/
tmi2_fluffos_v2/lib/doc/driverdoc/platforms/
tmi2_fluffos_v2/lib/doc/mudlib/
tmi2_fluffos_v2/lib/ftp/
tmi2_fluffos_v2/lib/include/driver/
tmi2_fluffos_v2/lib/log/
tmi2_fluffos_v2/lib/log/driver/
tmi2_fluffos_v2/lib/obj/net/
tmi2_fluffos_v2/lib/obj/shells/
tmi2_fluffos_v2/lib/obj/tools/
tmi2_fluffos_v2/lib/std/adt/
tmi2_fluffos_v2/lib/std/board/
tmi2_fluffos_v2/lib/std/body/
tmi2_fluffos_v2/lib/std/fun/
tmi2_fluffos_v2/lib/std/living/
tmi2_fluffos_v2/lib/std/object/
tmi2_fluffos_v2/lib/std/shop/
tmi2_fluffos_v2/lib/std/socket/
tmi2_fluffos_v2/lib/std/user/
tmi2_fluffos_v2/lib/std/virtual/
tmi2_fluffos_v2/lib/student/
tmi2_fluffos_v2/lib/student/kalypso/
tmi2_fluffos_v2/lib/student/kalypso/armor/
tmi2_fluffos_v2/lib/student/kalypso/rooms/
tmi2_fluffos_v2/lib/student/kalypso/weapons/
tmi2_fluffos_v2/lib/u/l/leto/
tmi2_fluffos_v2/lib/u/l/leto/cmds/
tmi2_fluffos_v2/lib/www/errors/
tmi2_fluffos_v2/lib/www/gateways/
tmi2_fluffos_v2/lib/www/images/
tmi2_fluffos_v2/old/
tmi2_fluffos_v2/win32/
 
/***
 ***	  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; }