EPIC5-2.2

*** News 10/06/2021 -- EPIC5-2.1.6 (1981 - Impignorate) released Here

*** News 09/21/2021 -- Another round of clang static analysis
	Somewhere around here we did another round of static analysis
	with clang's analyzer, and fixed whatever it recommended.

*** News 09/19/2021 -- "reconnect" script has been reimplemented
	The reconnect script has been renamed to "reconnect.orig".
	If you want the original behavior, just /load reconnect.orig
	The new script is based on improvements we've made in epic5
	to make reconnection logic more reliable and dependable.

*** News 09/11/2021 -- New option,  $serverctl(GET x PADDR)
	The $serverctl(GET x PADDR) returns the server's presentation
	address.  This is "1.2.3.4" for ipv4, or "2600::1" for ipv6.
	This represents the IP address we're connected to.

*** News 09/11/2021 -- New /window operation, /WINDOW CLEARREGEX <regex>
	This was requested by Zlonix.

	The /WINDOW CLEARREGEX <regex> operation removes all items from
	the window's lastlog whose text (what you see on the screen) 
	matches the <regex>.  Removing them from the lastlog removes
	them from the scrollback and your screen as well.  This is useful
	for making conversations with annoying bots go away retroactively.
	Example:	/window clearregex annoybot

*** News 09/11/2021 -- New /ON, /ON RECONNECT_REQUIRED 
	The /ON RECONNECT_REQUIRED hook is thrown by the client when it
	feels that a reconnection intervention is appropriate.  
	We are going to start this small, and build in more use cases
	as we go forward.

	  1. When server is in ACTIVE state and the socket dies
	  2. When a write to the server fails

	In these situations, your script should take whatever measures
	are necessary to save the state of windows, channels, etc,
	in preparation for the upcoming disconnection.

	This /ON is thrown while the server is in a state of chaos.
	The internal state of the system is wrong, and you must assume
	that the connection to the server has already been lost.  

	YOU MUST _*_*_NOT_*_*_ try to do anything clever in this /on.
	If you have this idea of moving windows or servers or channels,
	please don't!  I recommend setting up /timer's and /defer's so
	you can do those sorts of changes away from the blast radius.

	YOU MUST _*_*_NEVER_*_*_ attempt to do any direct intervention
	in this /on -- instead, you should save information and create 
	a timer to deal with the problem later.  YOU HAVE BEEN WARNED.

	/ON RECONNECT_REQUIRED currently provides this information
		$0 	The server that unexpected failed on us.
			Reconnection will be required.  Remember,
			you cannot do reconnection in the /on, you
			have to schedule it to happen "later"

*** News 09/08/2021 -- New /window operation, /WINDOW CLEARLEVEL [levels]
	This was requested by Zlonix.

	The /WINDOW CLEARLEVEL [levels] operation removes all items from
	the window's lastlog of the levels you specify.  Removing them
	from your lastlog removes them from your screen as well.  This is
	useful for making noise go away retroactively
	Example:	/window clearlevel joins,parts,quits,kicks

*** News 09/08/2021 -- New statement type: block-with-arglist
	The ircII syntax now supports a new statement type, which I'm 
	calling a "block with arglist"

		(arglist) {block}

	You could also think of this as an "inline anonymous function".
	For the purposes of the statement, $* is modified by (arglist)
	and then {block} is run.

	Please note there are several caveats to this:
	  1. Arglist is not magic, it is syntactic sugar.  So it creates real 
	     local variables, and those local variables have their ordinary 
	     scope.  So they will persist after the end of the statement.
	  2. The statement only modifies $* during the statement itself.
	     So after {block} is run, $* goes back to what it was originally.
	  3. Note that this is a *statement* and not a *block* so if you are
	     working with something that expects a block, wrap it in {}s to
	     create a block.
		if (# == 3) {(arg0, arg1, arg2) {... code ...}}
	  4. Arglist processing isn't "free" so doing it in a tight loop will
	     be slower than doing it outside of the loop

*** News 09/07/2021 -- Pass window refnum in /ON CHANNEL_LOST
	The /ON CHANNEL_LOST hook now provides the window that a channel
	was in as $2
		$0 - The server refnum of a channel
		$1 - The name of a channel
		$2 - The window refnum of a channel

*** News 09/06/2021 -- Functions for JSON document handling
	Some time ago some new functions appeared for handling
	JSON documents, but they were not documented.  So now
	I am going to document them!

	CONVERTING JSON DOCS TO /ASSIGNS
	--------------------------------
	Syntax:    $json_explode(varbase json-document)

	An example is worth a thousand words:

	    $json_explode(e {"one": 1, "two": { "sub1", "hi", "sub2", "bye" })
	will result in three new assigns
		$e[one]		-> 1
		$e[two][sub1]	-> hi
		$e[two][sub2]	-> bye

	CONVERTING ASSIGNS TO JSON DOCS
	-------------------------------
	Syntax:	   $json_implode(varbase)

	This converts everything under $varbase[*] into a JSON doc.

	HANDLING ERRORS
	--------------
	If there is an error, $json_error() will tell you about it.

*** News 09/06/2021 -- SSL handling improvements (take 2)
	The other day I posted some info on how the SSL handling has been 
	improved.  But then things got revamped again, so I delete the old 
	info and am replacing it with this info.

	1) Step one - You connect to an SSL server
	 You connect to an irc server doing something like
		/SERVER irc.example.com:6697:type=irc-ssl
	 This goes through connect()ing to the server, and then doing an 
	 SSL_connect() to set up the certificate exchange and TLS negotiation.

	2) Step two - The SSL handshake is completed
	 After the SSL_connect() step has completed, we now have a fully 
	 functioning TLS socket with an SSL certificate.  Before we use the 
	 TLS socket, we're supposed to verify we trust the SSL certificate, 
	 to ensure we're talking to who we think we are.

	3) Step three - The client watches the certificate verification
	 OpenSSL "verifies" the certificate and the client provides
	 a C function to tag along for the ride.  The callback function
	 is called every time:
	   (1) An error is discovered, or
	   (2) There are no (further) errors in a certificate.
	 Thus, if a certificate is trusted, it will only report 
	 "no problems" for each link in the chain.

	 This permits the client to trap and categorize every error that
	 happens - some certificates have multiple problems!  There are
	 three buckets the client uses:
		(1) Self-signed certificates
		(2) Incorrect-hostname certificates
		(3) Any other (serious) error
	 The client tracks the "most serious error" (if there is one),
	 using the above priorities.

	4) Step four - The cliet offers you /ON SSL_SERVER_CERT
	  The client sets $serverctl(SET <refnum> SSL_ACCEPT_CERT -1)
	  and then throws /ON SSL_SERVER_CERT.   The use of -1 is on
	  purpose so the client can determine whether your /ON handler
	  sets it to 0 or 1.  

	  If your handler does a $serverctl(SET <retval> SSL_ACCEPT_CERT 0|1)
	  then that is taken as the final disposition of the handling, and 
	  nothing further occurs. (ie, it skips the rest of the steps)

	  Parameters of /ON SSL_SERVER_CERT
		$0  The fd of the socket
		    (Use $serverctl(FROM_SERVER) to get the server refnum)
		$1  Certificate Subject, url-encoded
		$2  Certificate Issuer, url-encoded
		$3  Bits used in the public key 
		$4  OpenSSL error code of the "most serious error"
			(18 is "Self-signed certificate",
			 62 is "Hostname mismatch",
			 everything else is irregular/bad)
		$5  The SSL regime being used (ie, TLSv1.2)
		$6  The Certificate Hash
		$7  Was there a hostname mismatch?  0 = no error, 1 = error
		$8  Was there a self-signed error?  0 = no error, 1 = error
		$9  Was there another (serious) error?  
			0 = no other error 1 = other error
		$10 Was there any error of any kind?  
			0 = no errors of any kind, 1 = some kind of error

	5) Step five - The client makes a provisional decision
	  Next, the client looks at the errors and decides whether
	  it thinks the cert is ok.  
	    * Cert has no errors 		   -> ACCEPT
	    * Cert has "self signed" or "wrong hostname" error
	      and /SET ACCEPT_INVALID_SSL_CERT ON  -> ACCEPT
	    * Cert has "self signed" or "wrong hostname" error
	      and /SET ACCEPT_INVALID_SSL_CERT OFF -> REJECT
	    * Cert has any serious error	   -> REJECT
	  The client sets this provisional value with 
		$serverctl(SET <refnum> SSL_ACCEPT_CERT 0|1)

	6) Step six - The client offers you /ON SERVER_SSL_EVAL
	  Then, the client hooks /ON SERVER_SSL_EVAL.  At this point,
	  all of the information your script needs to make a fully 
	  informed decision to accept or overrule the client's choice
	  is available.  Your handler is not obligated to make any
	  change, but it certainly can if it wants to 

	  Parameters of /ON SERVER_SSL_EVAL
		$0  The server refnum
		$1  The "ourname" of the server (what you /server'd to)
		$2  Was there any error at all? 
			0 = no errors of any kind   1 = some kind of error
		$3  Was there a hostname mismatch?  0 = no error, 1 = error
		$4  Was there a self-signed error?  0 = no error, 1 = error
		$5  Was there another (serious) error?
			0 = no other error, 1 = other error
		$6  What does the client suggest?
			0 = reject certificate, 1 = accept certificate

	  Using $serverctl() to get info about the certificate
	  Use $serverctl(GET <refnum> <item>) where <item> is:
		SSL_CIPHER		The encryption cipher being used
		SSL_PEM			The certificate (in PEM format)
		SSL_CERT_HASH		The certificate's hash
		SSL_PKEY_BITS		The bits in the public key
		SSL_SUBJECT		Who the cert was issued to
		SSL_SUBJECT_URL		Who the cert was issued to (url-encoded)
		SSL_ISSUER		Who issued the cert
		SSL_ISSUER_URL		Who issued the cert (url-encoded)
		SSL_VERSION		What version of SSL being used (ie, TLSv1.2)
		SSL_SANS		Subject Alternate Names in the cert
		SSL_CHECKHOST_ERROR	Hostname Mismatch error - 0 (no) 1 (yes)
		SSL_SELF_SIGNED_ERROR	Self-signed error - 0 (no) 1 (yes)
		SSL_OTHER_ERROR	        Any other (serious) error - 0 (no) 1 (yes)
		SSL_MOST_SERIOUS_ERROR	The OpenSSL error code of the most serious error
					18 (self-signed) and 62 (hostname mismatch)
					are considered non-serious (routine) errors
		SSL_VERIFY_ERROR	Any error at all - 0 (no) 1 (yes)
		SSL_ACCEPT_CERT		Is this cert headed for acceptance?  0 (no) 1 (yes)

	   Use $serverctl(SET <refnum> SSL_ACCEPT_CERT 0) to reject the cert
	   Use $serverctl(SET <refnum> SSL_ACCEPT_CERT 1) to accept the cert
	   If you don't do anything, the client will do the most reasonable thing

	7) Step seven - The client moves forward
	  Finally, everyone has had a chance to weigh in.  
	  Whatever the value of $serverctl(GET <refnum> SSL_ACCEPT_CERT) 
	  is after all this, is used to accept or reject the SSL connection.

*** News 09/02/2021 -- Configuring SSL Ciphers
	Now, if you know what you are doing, you can set
	the SSL Ciphersuites that the client will use for
	SSL connections, via
		/SET SSL_CIPHERS <stuff>
	If you don't know what you're doing, don't touch.
	The default value is "unset", which means we let
	openssl choose the ciphers for us.

*** News 09/02/2021 -- SSL Handling improvements
	[replaced -- see above]

*** News 08/30/2021 -- New server description field "ssl-strict"
	[this feature was removed]

*** News 05/29/2021 -- EPIC5-2.1.5 released here (Fecund) (Commit id: 1945)

*** News 05/25/2021 -- Updated configure to autoconf-2.69
	We upgraded configure from autoconf-2.13 to 2.69 here.
	Along the way, we fixed the support for python3.8+

*** News 05/20/2021 -- Windows have UUIDs ($windowctl(GET x UUID))
	Every window now receives an immutable UUID when it is 
	created.  This UUID is globally unique and cannot be changed.

	Although the UUID is not user-facing (as in /window list),
	you can get it with $windowctl(GET refnum UUID).

	The UUID is an lval (that is, it does not contain hyphens),
	so you can use it as part of a variable name if you wish.

*** News 05/20/2021 -- New concept, "claiming channels"
	When EPIC receives a protocol JOIN message for a channel, 
	it has to decide what window to put the channel in.  
	A common request has been the opportunity to let scripts 
	decide where new channels should go, rather than it being 
	hardcoded.

	So now when a JOIN is received, an /ON will be thrown 
	(see below) which is an invitiation for your script to do
	whatever preparatory work for the channel you see fit.

	One thing in particular is /WINDOW CLAIM (see below), which
	tells EPIC which window the channel should be put into.
	As part of this process, EPIC will suggest a window the 
	channel should go into, unless you choose to overrule that.

	*** NONE OF THIS APPLIES TO /JOIN or /WINDOW CHANNEL
	    when the user is deliberately moving a channel they are
	    already on between windows.  You can't stop that.

*** News 05/20/2021 -- New /ON, /ON CHANNEL_CLAIM 
	The /ON CHANNEL_CLAIM is thrown when a JOIN is received,
	but before the client has assigned the channel to a window.
		$0 - The server refnum 
		$1 - The channel being joined
		$2 - The window refnum epic proposes to put the
		     window into.

	If your handler does /WINDOW CLAIM in any particular window,
	then the channel will go to that window that you specify.

	At this time, you can only do /WINDOW CLAIM in a window that
	is connected to the server in $0. In the future, this will
	probably change.  But for now, a /WINDOW BIND in a "window
	connected to the wrong server" is treated as invalid.

	If you do not do a valid /WINDOW CLAIM, then the channel will
	go into the window proposed by EPIC.

*** News 05/20/2021 -- New /WINDOW operation. /WINDOW CLAIM #channel
	During the handling of an /ON CHANNEL_CLAIM, you may perform
	the /WINDOW CLAIM operation to direct EPIC to put the new
	channel into a particular window.

	You must pass the name of the channel as a paraemter.
	It is available as $1 in the /on.

	You may only claim the channel in a window that is connected
	to the correct server (from $0).  Attempting to claim a 
	channel in a window connected to the wrong server is invalid
	and has no effect.   This will change in the future.

*** News 05/20/2021 -- $uuid4() can now return lvals (NODASHES)
	You can now get a uuid4 that is valid as an lval if you
	supply NODASHES as the only argument
		@ a.$uuid4(NODASHES) = [whatever]

	ALL ARGUMENTS TO THIS FUNCTION ARE RESERVED FOR FUTURE EXPANSION.
	There are now two defined behaviors:
		$uuid4()	 - UUID4 with dashes
		$uuid4(NODASHES) - UUID4 without dashes
	EVERYTHING ELSE IS UNDEFINED BEHAVIOR (ie, other arguments may 
	do something today, but forwards compatability is not guaranteed)

*** News 03/26/2021 -- EPIC5-2.1.4 released here (Redound) (Commit id: 1927)

*** News 02/13/2021 -- /UNLOAD now supports /TIMERs
	If you create a /TIMER in a script you /LOAD with /PACKAGE
	the timer will be tagged just like any aliases or assigns
	or ons or whatever.

	Note that /TIMERs are _not_ tagged if they are created 
	after /load time.  This includes but is not limited to 
	timers created by aliases that are tagged; as well as
	timers that create new versions of themselves (but it 
	will catch timers that run forever)

*** News 02/10/2021 -- New /WINDOW operation, /WINDOW UNCLEAR
	There was already an /UNCLEAR command, and a /CLEAR and
	/WINDOW CLEAR command, but there was no /WINDOW UNCLEAR.
	WHy not? Anyways...

*** News 02/07/2021 -- Low level operations on cutbuffer - $inputctl()
	Harzilein asked if there was a way to manipulate the cutbuffer
	without having to put something in the input line.  As it happens,
	that has never been requested before.  So here we go!

	$inputctl(GET cutbuffer)
		This returns the cut buffer.  This is the same as $U

	$inputctl(SET cutbuffer ... new value ...)
		This sets the cut buffer.  This would be effectively
		the same as:
		 * Saving the input line (with $L)
		 * Erasing the input line (parsekey ERASE_LINE)
		 * /TYPEing what you want into the cut buffer
		 * Erasing the input line (to put it into the cut buffer)
		 * /TYPEing the origial input line
		But this doesn't require you to disrupt the input line.

		Please remember that there is only one cut buffer,
		and a large number of operations replace it -- so 
		whatever you put in the cut buffer, use it quickly,
		or the user might clobber it.

*** News 02/05/2021 -- /ON SERVER_STATUS changed to /ON SERVER_STATE
	Some expressed some confusion about whather "SERVER STATUS"
	and "SERVER STATE" were the same thing, and what the states
	were and what they meant.  To reduce this confusion, there
	will be only one term, "SERVER STATE". However, much code
	already uses "SERVER STATUS".  So we have to support both.

	For now, /ON SERVER_STATUS and /ON SERVER_STATE will both 
	exist side by side.   However, I recommend you use 
	/ON SERVER_STATE for new code, and think about migrating
	your old code.   There will come a day when /ON SERVER_STATUS
	will beoome an alias for /ON SERVER_STATE.

	To be unambiguous, using /ON SERVER_STATUS will never break.
	But you should know the official name is going to be 
	SERVER_STATE.

	The stock scripts have been updated.  You can get the changes
	by making sure to do a 'make install'

*** News 02/05/2021 -- $serverctl(GET x STATUS) changed to STATE
	As per the above, both $serverctl(GET x STATUS) and 
	$serverctl(GET x STATE) will return the server's state.
	However, you are encouraged to start using "STATE", since
	that is now the official term for it.

	The stock scripts have been updated.  You can get the changes
	by making sure to do a 'make install'

*** News 07/03/2020 -- New /WINDOW operation, /WINDOW DELETE_KILL
	Harzilein pointed out:
	  1) You cannot delete the last window on a screen
	  2) Deleting a screen does not kill a window
	  3) Therefore, deleting a screen necessarily orphans a window
	But what if you don't want to orphan a window when you kill a
	screeN?  

	The /WINDOW DELETE_KILL operation does a /WINDOW DELETE and
	then does a /WINDOW KILL on the window that was the current
	window.  There are several caveats to this *which i reserve
	the right to change in the future*
	
	Caveat 1) Only the "current window" gets killed.  So if you 
	    DELETE_KILL a screen with multiple windows, other windows
	    will be orphaned in the ordinary way.  I reserve the right
 	    to change this behavior (it will be documented)
	Caveat 2) If you cannot kill the window for other reasons, 
	    such as /window killable off, then the attempt to kill the
	    window will fail, and it will be orphaned.

*** News 05/11/2020 -- EPIC5-2.1.2 released here (Lugubrious) (Commit id: 1908)

*** News 05/09/2020 -- New built in function $execctl()
	You can now program the /EXEC command with this low level function

	--- warning ---
	Many of the things you can set here are not sanity checked.
	If you feed it garbage in, you will get garbage out.
	If you need safety rails, use the /EXEC command.
	--- warning ---

	Usage:
	------
	$execctl(REFNUMS)
		Get all refnums in the entire system (as integers)
	$execctl(REFNUM <description>)
		Convert a description (like %3 or %myproc) into a refnum integer

	$execctl(NEW <commands>)
		Create a new /exec process (does not run it!)
	$execctl(LAUNCH <refnum>)
		Run an /exec process that hasn't been started yet
	$execctl(CLOSEIN <refnum>)
		Close the STDIN to the process (this means you can't send any
		more data to the program.  This is useful for programs
		that wait until they've got an EOF from stdin to do their 
		thing)
	$execctl(CLOSEOUT <refnum>)
		Close the STDOUT and STDERR from the process (this means 
		we won't receive any more output from the program.  This is
		useful if we don't want any more output from the program.
		Many programs will die from SIGPIPE if stdout is closed)
	$execctl(SIGNAL <signal> <refnum>)
		KILL (send a signal) to a process.  The <signal> may either
		be an integer (like $execctl(SIGNAL 9 3) or it may
		be a short name (like $execctlSIGNAL HUP 3) to kill 
		process 3.

	$execctl(GET <refnum> [FIELD])
	$execctl(SET <refnum> [FIELD] [VALUE])
		You can GET all the fields of the object, and SET some of them.
		Some fields cannot be changed after the process is launched.

	Field		Set?	Notes
	-------------	------	-----------------------------------
	REFNUM		No	The integer refnum - never repeated.
	REFNUM_DESC	No	The "target" version (ie, %3)
	LOGICAL		Yes	The user-supplied name - must be unique
	LOGICAL_DESC	No	The "target" version (ie, %myproc)
				-- This will change if you SET LOGICAL
	COMMANDS	Yes	The commands to run (**)
	DIRECT		Yes	Whether to use a shell (**)
	REDIRECT	Yes	Either PRIVMSG or NOTICE
	WHO		Yes	The target to send output to
				-- Output from the process is redirected verbatim
	WINDOW_REFNUM	Yes	The window this exec runs in context of
				-- Undefined behavior if window does not exist
	SERVER_REFNUM	Yes	The server this exec runs in context of
				-- This is for redirects and code callbacks
	LINES_LIMIT	Yes	How many lines to receive before CLOSEOUT
				-- 0 means "no limit"
	STDOUTC		Yes	ircII code for every complete line of stdout
	STDOUTPC	Yes	ircII code for every partial line of stdout
	STDERRC		Yes	ircII code for every complete line of stderr
	STDERRPC	Yes	ircII code for every partial line of stderr

	PID		No	The process id of the process (after launch)
				-- This is -1 before launch
	STARTED_AT	No	When the process was created or launched
				-- It is first set when creation happens
				-- It is last set when launched
	P_STDIN		No	File descriptor to talk to process's STDIN
	P_STDOUT	No	File descriptor to read from process's STDOUT
	P_STDERR	No	File descriptor to read form process's STDERR
				-- There is nothing you can do with these.
				-- Don't try.
	LINES_RECVD	No	How many lines of output the process has sent
	LINES_SENT	No	How many lines we sent to the process
	EXITED		No	0 if process has exited yet -- 1 if it has
	TERMSIG		No	The signal that killed the process
				-- It is -1 if the process has not died
				-- It is -1 if the process exited normally
	RETCODE		No	The exit code of the process
				-- It is -1 if the process has not died
				-- It is -1 if the process was killed
	DUMB		No	Reserved for future/internal use
	DISOWNED	No	Reserved for future/internal use
	(Note: ** - Cannot be SET after launch)

*** News 05/08/2020 -- New flag to /EXEC, /EXEC -NOLAUNCH
	The /EXEC -NOLAUNCH flag directs the /EXEC command not to launch 
	a process that has not already launched.  You can launch it later 
	merely by referencing it with its name or refnum.

		/EXEC -nolaunch -name myproc ls -l
		/EXEC -nolaunch -limit 5 %myproc
		/EXEC %myproc

	Many /EXEC operations do not work on an unlaunched process.

*** News 05/07/2020 -- New function, $uuid4()
	This function returns a random UUID4 string.  If you know what that is,
	you might know why it's handy to be able to have one.

	ALL ARGUMENTS TO THIS FUNCTION ARE RESERVED FOR FUTURE EXPANSION.
	To get the default behavior, pass no arguments to this function.
	Forwards compatability is not guaranteed if you pass undefined args

*** News 05/07/2020 -- New /ON, /ON SEND_EXEC
	Whenever text is being sent to an /EXEC process, either through /EXEC -IN
	or /MSG %proc or a /QUERY or whatever, it is displayed to your screen.
	The /ON SEND_EXEC process will let you adorn how this text is displayed,
	instead of it just being displayed blankly as it has always done.

*** News 05/07/2020 -- The /EXEC command
	The /EXEC command has always been part of ircII, but it hasn't
	changed much during EPIC's lifetime.  There were some rough edges
	related to querying exec'd processes, things not always going
	to the windows people expected, some flags not being able to be
	used with other flags, etc.

	So the /EXEC command has been substantially revamped, with an intention
	of everything being "do what i expect".  If you find things that are 
	weirdly behaving, please let me know!

	Instead of describing the changes, let's just level-set the behavior:

	Every /EXEC command can create or modify one process

	[The most general explanation of the syntax]
	Modify an existing running exec:
		/EXEC [options] %refnum [extra arguments]
		/EXEC [options] %logical-name [extra arguments]

	Create a new exec:
		/EXEC [options] commands to run
		/EXEC [options] (commands to run) [extra-arguments]

	OPTIONS to /EXEC

	   [ Options related to sending data to/from the process ]
		-CLOSE
			Close the process's STDIN, STDOUT, and STDERR
		-CLOSEIN
			Close the process's STDIN
		-CLOSEOUT
			Close the process's STDOUT and STDERR
		-IN [extra arguments]
			Send data to a process

	   [ Options related to how the process integrates with ircII ]
		-NAME
			Change the logical name of a process
		-OUT
			Send all output from the process to the now-current 
			channel in the now-current window.
		-WINDOW
			Display all output from or related to the process to the 
			now-current window.
		-WINTARGET <windesc>
			Display all output from or related to the process to the 
			specified window
		-MSG [target]
			Send all output from the process to the target.
			The target can be an irc, dcc chat, or other exec,
			or anything you can send a message to.
			Messages sent over IRC are sent as PRIVMSGs
		-NOTICE
			Send all output from the process to the target.
			Messages sent over IRC are sent as NOTICEs.

	    [ Options related to scripting with processes ]
		-LINE {code}
			Run {code} for each full line of output from stdout of the process.
			$* will be the line of output
		-LINEPART {code}
			Run {code} for each incomplete line of output from stdout of the process.
			$* will be the incomplete line of output
		-ERROR {code}
			Run {code} for each full line of output from stderr of the process.
			$* will be the incomplete line of output
		-ERRORPART {code}
			Run {code} for each incomplete line of output from stderr of the process.
			$* will be the incomplete line of output
		-END {code}
			Run {code} when the process has completed.  This means when the process
			has exited and all of its output has been processed.  (Sometimes this 
			lags the actual exit)
				$0 is the logical process name or its refnum
				$1 is the signal that killed it (if it was killed)
				$2 is the exit code (if it exited)

	    [ Options that don't fit in the other categories ]
		-DIRECT
			Run the program directly -- do not use a shell.  
			Advantages:  The command you give is literally executed
			Disadvantages: If you depend on filename globbing or aliases, well, tough
		-LIMIT <number>
			Read <number> lines from the process and then -CLOSE it.

	    [ Options related to sending a signal to the process ]
		-<signal_number>
			Send the signal to the process, similar to kill -<signal_number> <pid>
		-<signal_name>
			Send the signal to the process, similar to kill -<signal_name> <pid>

	Additionally, %<procref> or %<procname> are full blown message targets that you can 
	/msg or /query or whatever you want, just like all other targets.

	[Examples of how this works]


*** News 04/26/2020 -- New python script, 'shortener'
	You can load this script with
		pyload shortener
	This script provides an in-client URL shortening service.
	Whenever someone provides a URL in a message, the service
	will create a short URL that will be served by an http
	redirection server that runs in client

	Example:
	--------
	<nick> hey, please visit www.frobnitz.com/really-long-and-wraps
        +onto-the-next-line-so-you-can-tpaste-it
	*** http://127.0.0.1:8080/1

	Then you can visit http://127.0.0.1:8080/1 and it will
	redirect you to the original url.

*** News 02/24/2019 -- EPIC5-2.1.1 (Abulia) was released here
	Even though not everything is done, I think I've probably
	dragged my feet long enough

*** News 11/28/2018 -- /EXEC -WINTARGET outsputs to a window by name (caf)
	The normal behavior of /EXEC is to send the output of a command
	to the current window (or is it the OTHER window?  I forget)
	Before this, you couldn't ordinarily send it to just any old
	random window you wanted.  

	You can use /EXEC -WINTARGET to send it to any window you want:
	Example:
		/exec -wintarget msgwin ls

*** News 02/24/2019 -- EPIC5-2.1.1 released here (Abulia) (Commit id: 1899)

*** News 02/05/2018 -- CTCP UTC now implemented as script
	Given the below feature, CTCP PING support has been 
	rewritten, and CTCP UTC is now scripted.

*** News 02/13/2018 -- New flag for $ctcpctl(), "REPLACE_ARGS"
	There are actually two kinds of CTCPs that replace things

	* CTCP PING replaces its argument(s), but is otherwise
	  handled "normally"
		NOTICE nick :\001PING <sec> <usec>\001
	  becomes
		NOTICE nick :\001PING <sec> seconds\001

	* CTCP UTC replaces itself entirely:
		PRIVMSG nick :\001UTC 1518582810\001
	  becomes
		PRIVMSG nick :Tue Feb 13 22:33:30 2018

	So it's not enough to say that "a CTCP handler can replace 
	itself by returning a string", you need to be able to say
	whether this CTCP replaces its arguments only, or whether
	it replaces itself entirely.

	  * $ctcpctl(SET <ctcp-name> REPLACE_ARGS 1)
	  * $ctcpctl(SET <ctcp-name> REPLACE_ARGS 0)
		Select whether or not a CTCP handler that returns a 
		string replaces its arguments (like CTCP PING) or 
		replaces itself entirely (like CTCP UTC).  
		The default is 0 (replace entirely)

*** News 02/05/2018 -- Some CTCPs are now implemented as scripts
	YOU NEED TO START DOING /LOAD ctcp  IN YOUR STARTUP SCRIPTS.

	One of the larger projects in EPIC5 was to move as many
	hard coded things into scripts as was feasible, so you,
	the user (or the script you're using) can have as complete
	control over them.  We've moved a lot of functionality out
	into scripts.

	Traditionally those users who don't have startup scripts 
	(~/.epicrc or ~/.ircrc) get /load global as their startup
	script.  One of the things /load global does is /load builtins
	which brings in the scripted features.  

	Now /load builtins will /load ctcp, which implements these 
	core CTCP functions entirely in ircII, so you are welcome 
	to modify or remove them, as _you_ choose.

		VERSION		PING		ECHO
		CLIENTINFO	USERINFO	ERRMSG
		FINGER		TIME

	Maybe more will be migrated in the future.  But this is a good
	start for now.  This is also a great example of how to 
	build your own first-class ctcp handlers!

*** News 02/04/2018 -- User-defined CTCP handlers with $ctcpctl()
	You can now create your own first-class user-defined CTCP handlers.

	A CTCP handler is a block of code that takes four arguments:
	  $0  - The person making the request
	  $1  - The target of the request (you, or a channel you're on)
	  $2  - The CTCP that was sent 
	  $3- - Arguments (if any) to the CTCP

	A CTCP request handler is a CTCP handler that handles incoming 	
	requests (over PRIVMSG).  A CTCP request handler can either 
	   (1) generate a response or 
	   (2) substitute something.  
	A response can be generated with:
	      /CTCP $0 $2 Your Response Here
	A substitute string is /return'ed by your handler, and replaces
	the CTCP in the original message.

	A CTCP response handler is a CTCP handler that handles incoming 
	responses (over NOTICE).  A CTCP request handler can either
	   (1) Output the response in a special way or
	   (2) substitute something
	CTCP response handlers are unusual, because the ordinary handling
	of CTCP responses is the expected behavior.

	Syntax:
	  * $ctcpctl(SET <ctcp-name> REQUEST {<code>})
		Register <code> as a CTCP handler for <ctcp-name> requests.

	  * $ctcpctl(SET <ctcp-name> RESPONSE {<code>})
		Register <code> as a CTCP handler for <ctcp-name> responses.
		(Note -- handling responses is unusual.  Normally you just
		 let the client output responses in the ordinary way)

	  * $ctcpctl(SET <ctcp-name> DESCRIPTION <string>)
		SET <string> as the CLIENTINFO for <ctcp-name>.  That is,
		when someone does /CTCP CLIENTINFO <ctcp-name>, <string> 
		will be returned as the description for this CTCP.

	  * $ctcpctl(SET <ctcp-name> SPECIAL 1)
	  * $ctcpctl(SET <ctcp-name> SPECIAL 0)
		Enable/Disable a CTCP as being "Special".  A "Special" CTCP
		is a remote function call, and handles everything itself.
		There are only two "special" CTCPs -- ACTION (/me) and DCC.
		I'm not sure if anyone will create a "special" user-defined CTCP

	   * $ctcpctl(SET <ctcp-name> RAW 1)
	   * $ctcpctl(SET <ctcp-name> RAW 0)
		Enable/Disable a CTCP has requiring the "raw data".
		Ordinary CTCPs transport strings, and they have to be recoded
		according to /encode-ing rules.  But some CTCPs transport 
		binary data, and so the handler needs access to the raw binary
		data.  Ordinarily, the raw/binary data is CTCP encoded, which
		mens you can pass it to $xform("-CTCP") to recover the raw
		bytes (although it might not be a C string, so you can't 
		assign it to a variable.)

	   There are corresponding GET operations for the above

	You can get all the registered CTCPs with
	   * $ctcpctl(ALL)

	Very soon, quite a few CTCP types will be migrated out to a script that
	will be /load'ed from /load global, and you may have to add it to your
	own start scripts if you do not /load global.

	I need to write much better examples for all this.  To look at this you'd
	scratch your head and wonder why you care.  But being able to add new 
	CTCPs instead of requiring them to be written in C in a new version of
	epic is expected to help a lot of people.


*** News 01/16/2018 -- New status expando %{1}P ("status prefix") and variables
	The %{1}P value will expand to a "when window current" or "when window
	not current" value.  The idea is to put this at the start of your 
	/set status_format or /window status_format type variables.

	When a window is current, %{1}P will expand to either
		/window status_prefix_when_current
	or
		/set status_prefix_when_current

	When a window is not current, %{1}P will expand to either
		/window status_prefix_when_not_current
	or
		/set status_prefix_when_not_current

	You can use this all in your ~/.epicrc, like so:
		set status_format %{1}P%T [%R] %*%=%@%N%#%S%{1}H%H%B%Q%A%C%+%I%O%M%F%L %D %U %W
		set status_prefix_when_current ^C37,40
		set status_prefix_when_not_current ^C37,44
	which will make your status bar white-on-black when current,
	and white-on-blue when not current.


EPIC5-2.0
EPIC5-1.8

*** News 08/05/2016 -- EPIC5-2.0.1 released here (Commit id: 1869)

*** News 01/30/2016 -- EPIC5-2.0 released here (Commit id: 1864)

*** News 01/30/2016 -- EPIC5-1.8 released here (Commit id: 1862)

*** News 01/30/2016 -- /WINDOW LOGFILE and /SET LOGFILE more like /LOG FILNAME
	Historically, changing a logfile name (with /WINDOW LOGFILE and
	/SET LOGFILE) does not affect the log status.  This leads to 
	unexpected behavior if you do /WINDOW LOG ON LOGFILE foo.txt
	because /WINDOW LOGFILE only changes the filename the *next* time
	you open the log, not affecting the currently open log.

	The behavior of /LOG FILENAME is more in line with what people 
	said they expected.  If you change /LOG FILENAME while the 
	log is ON, then it will 1) close the existing log, 2) change
	the filename, and 3) re-open the log under the new name.

	The behavior of /WINDOW LOGFILE and /SET LOGFILE have been changed
	to match the behavior of /LOG FILENAME -- changing the logfile name
	while it is open will close the existing log and open a new one.

EPIC5-1.6

*** News 01/30/2016 -- EPIC5-1.6 released here (Commit id: 1854)

*** News 01/08/2016 -- Per-server vhosts now restrict protocol (ipv4/ipv6)
	Historically, the client tries to connect to the server using the
	addresses as they are returned in order.  (This is a great thing 
	for round-robin or geographic-aware dns resolvers.)

	However, if you have a per-server vhost, you probably intend that
	epic use that vhost to connect to the server.  But what happens if
	your vhost is ipv4 only or ipv6 only, and the first address to the
	server is to the other protocol?  Historically, epic will just go 
	ahead and connect without your vhost.

	You've been able to correct this behavior by specifying explicitly
	the protocol family:
		/server irc.foo.com:proto=v6:vhost=irc.leet6.com
	Some folks said it violated POLA, so here's a new rule:

	"If you set a per-server vhost, then that server can only be 
	 connected to if the vhost can be used.  If ths means that no
	 addresses can be used, then you will not be able to connect 
	 to the server until you clear the vhost."

	This rule does not apply to you if you're using /HOSTNAME but
	only if you are doing something like 
		/server irc.foo.com:vhost=irc.leet6.com

*** News 01/01/2016 -- Can now /query an exec process that doesn't exist
	Previously, you were forbidden from setting up a /query to an 
	/EXEC process that didn't exist.  That set up a race condition
	between running an /EXEC process and being able to corral its 
	output into a window via the query.  

	So now you can /query an exec process before you start it.  

	If you try to send a message to it before you do fire it up, 
	the user will see a diagnostic telling them that the message 
	could not be sent to a non-existing exec process.

*** News 01/01/2016 -- New /window operation, /window log_mangle
	This allows you to overrule /SET MANGLE_LOGFILES for logs that
	you create with /WINDOW LOG ON (only!)
	Example:
		window logfile "my.windowlog" mangle NORMALIZE,COLOR log on

*** News 01/01/2016 -- New /window operation, /window log_rewrite
	This allows you to overrule /SET LOG_REWRITE for logs that
	you create with /WINDOW LOG ON (only!)
	Example:
		window logfile "my.windowlog" rewrite "HOOBOO $1-" log on

*** News 01/01/2016 -- Refinement to $pad(), $[len]var, and $leftpc()
	These functions do not behave graciously since our conversion
	to UTF-8, since they count code points rather than columns.
	It just seems sensible to redefine the behavior of these 
	functions based on columns, which is what everybody probably
	expects them to do.

	Function: $pad(len char string)
	Summary: Extend, but do not truncate, do not justify 'string'
	Definition: 
		Return 'string' so that it takes up at least 'len' columns.
		If it is too short, it will be padded with 'char's until
			it is 'len' columns wide.
		If it is too long, it is NOT truncated.

	Function: $leftpc(len string)
	Summary: Truncate, but do not extend, do not justify 'string'
	Definition:
		Return the first 'len' columns of 'string'.  
		If it is too short, it will NOT be padded.
		If it is too long, it will be truncated on the right end.

	Function: $[len]var
	Summary: Extend, truncate, and justify $var
	Definition:
		Return $var so that it takes up EXACTLY 'len' columns.
		If it is too short, it will be padded with /set pad_char
			until it is 'len' columns wide.
		If it is too long, it is truncated.
		If 'len' is > 0, then the string is left justified, and
			padding (or truncation) happens on the right end.
		If 'len' is < 0, then the string is right justified, and
			padding (or truncation) happens on the left end.

	Function: $fix_width(len justify pad string)
	Summary: Extend, truncate, and justify 'string'
	Definition:
		Return 'string' so it takes up EXACTLY 'len' columns.
		If it is too short, it will be padded with 'pad'
			until it is 'len' columns wide.
		If it is too long, it is truncated.
		If 'justify' is "l" then the string is left justified,
			and padding (or truncation) happens at the right
		If 'justify' is "c" then the string is centered, and 
			padding (or truncation) happens equally at both
			ends.
		If 'justify' is "r" then the string is right justified,
			and padding (or truncation) happens at the left.

*** News 09/15/2015 -- New /ON, /ON RAW_IRC_BYTES
	This new /ON, /ON RAW_IRC_BYTES is the same as /ON RAW_IRC, 
	except $* is the _raw unmodified bytes_ received from IRC.
	Specifically, $* is not guaranteed to be a UTF-8 string, so 
	functions that expect a UTF-8 string won't work.  You should
	not try to /ECHO the $* from this /ON.

	Just like /on raw_irc, if you catch this hook, you will 
	suppress normal handling of the event:
		/on ^raw_irc_bytes * {echo nothing further happens}

EPIC5-1.4

*** News 08/29/2015 -- EPIC5-1.4 released here (Commit id: 1833)

*** News 08/25/2015 -- Improved automargin support 
	You can now use automargins to get better wrapping of long urls.

	1. Use a terminal emulator that supports automargins
	   (they pretty much all do)
	2. Set your TERM env variable to something that supports automargins
		export TERM=vt102am        
	   should do the job
	3. Restart EPIC after you've updated the TERM.  It's not enough 
	   to just change the TERM and re-attach screen.  It's a good 
	   idea to check this when you're upgrading.
	4. /SET -CONTINUED_LINE	
		to get rid of the + thingee
	5. /SET FIRST_LINE >   
		or something if you don't use /set output_rewrite 
		to prefix every line
	6. /SET WORD_BREAK<space><space><enter>
		URLs contain commas and dots and semicolons, and you 
		don't want epic to word break on anything other than 
		a space.

	That should do it!  Your display will now use the final column
	on the display, and urls should be unmangled when you copy them

