QuIRC - What do you think?

Copyright (C) 1998-2000, Patrick Earl (Advantage Software)

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

Patrick Earl - patearl@pobox.com


TABLE OF CONTENTS
-Notes
-Keys
-Commands
-Popups
-Alias System
-Event System
-Built-In Subroutines
-General Scripting Information
-QuIRC's Start-Up Process
-UI Programming Information
-Issues To Be Aware Of
-Lacking Features And Known Bugs


NOTES

Bug reports (detailed as possible please) and patches for QuIRC are always
welcomed wholeheartedly.  If anyone would like to assist in the development
of QuIRC, let me know and we'll see what we can work out.

Special thanks to Stuart Moore (hero-) for writing the nick complete and
substantial portions of the tcl code, and for being an Alpha tester for QuIRC.

Thanks also to Wilton Wong (Atko) who was a great help in fixing the
multiserver problems as well as a few bugs that caused a seg fault on exit.

Let's have a great big round of applause for D. Richard Hipp without whose
Embedded Tk, QuIRC would not even have happened.  Thanks also for the nice
pure Tcl/Tk tree widget :)

See the INSTALL file for instructions on installing.

See the CHANGELOG file for details on what's new.

See the FAQ for a variety of information not found here.


KEYS

These are the default keys that come in config.tcl:

Control-Enter
	Sends the input without parsing it first, so lines with / can be sent
        and not interpreted as commands.

Alt-Enter
	Acts like Control-Enter only it trims space off the text before
	sending.  Is useful for dealing with data pasted from Netscape.

Shift-Enter
	Inserts a linefeed into the command line so you can run more than one
	command on the same line easily.

Control-Down
	Goes to the next window

Control-Up
	Goes to the previous window

Up
	Recalls the previous command in the history list

Down
	Recalls the next command in the history list

Shift-Prior (PgUp)
	Scrolls the currently showing text window up.

Shift-Next (PgDn)
	Scrolls the currently showing window down.

Prior
	Same as Shift-Prior

Next
	Same as Shift-Next

Control-Prior
	Scrolls the nicklist up.

Control-Next
	Scrolls the nicklist down.

Alt-Prior
	Scrolls the windowlist up.

Alt-Next
	Scrolls the windowlist down.

Control-F4
	Closes the current window.

Alt-F4
	Closes the client.

Control-c
	Inserts the color character (\x03).

Control-l
	Inserts the bold character (\x02).

Control-u
	Inserts the underline character (\x1f).

Control-_
	Inserts the underline character (\x1f).

Alt-n
	Opens the server dialog.


COMMANDS

Commands that begin with / are evaluated as aliases.  Every command not listed
here is an alias:

/lookup - Given a hostname, it will return the numeric IP for it

Commands that begin with // are evaluated as tcl expressions.  For example:

	//say My home dir is $::env(HOME)
	//say 582 divided by 17 is [expr 582/17.0]

Will be evaluated to, for example:

	/say My home dir is /home/patearl
	/say 582 divided by 17 is 34.2352941176

And will send the message "My home dir is /home/patearl" to the current
channel, query, or chat session.  For the calcuation example, you could just
use /calc 582/17.0 to acheive similar results.

Try hitting F1 for commands not listed here.

(Really) Partial list of IRCII commands supported as well as any known
differences from IRCII:
(For more information see http://www.dal.net/services/helpserv/index.html)

/abort - Simply exits.
/admin
/away
/beep
/bye
/cd
/channel


POPUPS

See the popup command below for how to implement popups.  The popups that come
with QuIRC are all in popups.tcl and it is suggested that you place your own
popups in userpopups.tcl which will be loaded by popups.tcl.  That way when you
upgrade QuIRC it won't be a concern to merge the popup changes.


ALIAS SYSTEM

There are two types of aliases, server specific aliases and global aliases.
The server specific aliases run within the namespace of the script that they
are loaded in.  The global aliases run within the global namespace.  The server
specific aliases are run before the global ones.  Any / command entered that
does not have a corresponding alias will be sent to the server as is.  If an
alias returns 1, no other aliases of the same name (in different scripts or in
the global namespace) will be executed.  Do not put more than one alias of
the same name in the same script file.

Example:

proc alias_test { arg } {
    quote "PRIVMSG [mynick] :$arg"
}

OR

alias test {
    quote "PRIVMSG [mynick] :$arg"
}

When run with:

	/test Hello there.

would message you with the message "Hello there."


EVENT SYSTEM

There are two types of events, global events and server specific events.

Global Events

There can only be one global event of any type.  If a script is loaded that has
that particular event in it, any older one will be replaced.

The return values of global events are ignored unless otherwise indicated.

proc event_windowchanged { oldpathname oldname oldserver oldindex pathname name server index } { script }
	This event is called at the start of the totop proc and is passed the
        pathnames, names, server indexes, and windowlist indexes of the old and
        new windows.

proc event_echo { message pathname new } { script }
	This event is called everytime text is to be echoed.  You must return
	the text that you actually want to be echoed.  If you return nothing,
	it will not echo anything.  You can use echotags from within this proc
	for very customized echoing.  The new parameter is used to indicate
	whether or not the window list should be activated when the text is
	printed.

proc event_enter { message pathname } { script }
	Is called (by parseentry) whenever data is entered normally in an entry
	box.  Whatever you return is what is considered to be the actual input.
	This can be used to do replacements on various data in the input or to
	cancel certain input by returning "".

Server Specific Events

The event system is composed of the following:

proc event_raw { prefix command args } { script }
proc event_??? { prefix args } { script }
proc event_unparsednumeric { prefix command args } { script }
proc event_unparsed { prefix command args } { script }

??? is the event (in lowercase) as sent by the server.  For example:
	privmsg or 301
$prefix corresponds to the prefix as found in the IRC RFC (doc/rfc1459.txt).
	It is often the originator of the event.  This is usually either a
	nick!user@host or a server ip.
$command is the actual command produced (exactly as returned by the server).
$args is a TCL list of any arguments following the command part of the IRC
	reply from the server.  The 0th argument often contains the target
	of the event.  See the RFC for details.  The individual arguments of
        $args can be accessed like so: [lindex $args #], where # is any
        integer between 0 and up to but not including [llength $args].

Example:

proc event_376 { prefix args } {
    quote "JOIN #mychannel"
}

The above would send the command to join #mychannel upon reception of the
end of the MOTD from the server.

Order of Event Execution:
	event_raw_unparsed
	event_raw
	Specific Events (i.e. event_privmsg or event_301)
	event_mymode(+/-)?
	event_mode(+/-)?
        Internal Events
	event_unparsednumeric
		If any previous events return 2, this event will not occur.
	event_unparsed
		If any previous events return 2, this event will not occur.

If the message is a server numeric and is not one of the known invalid
responses, mynick is set after event_raw_unparsed.

Return Values of Events:

	1 - Stop the same event (i.e. event_raw or event_privmsg) from occuring
            in any other scripts after this point.  Scripts that are loaded
            later are executed first, so the last script you load can override
            previously loaded scripts.
	2 - Stop output to the text windows from occuring.
	    (event_unparsednumeric and event_unparsed will not be called and
            any output internal to QuIRC will not be produced)
	4 - Special return for event_raw and event_mode; stops the specific
	    events from being checked. (i.e. Events like event_privmsg and
            event_mode+o will not be called.)  This now applies to
	    event_privmsg (event_ctcp, event_text) and event_notice
	    (event_noticetext, event_ctcpreply).

As an example, "return 7" would stop everything past that point.

IRC Message Events:
	proc event_raw_unparsed { data } { script }
	proc event_raw { prefix command args } { script }
	proc event_mode { prefix args } { script }
	proc event_mymode+? { prefix args } { script }
		? is any letter of the alphabet.  Gets executed when a
                non-channel mode event occurs (ie. Personal mode change)
	proc event_mymode-? { prefix args } { script }
		Same as mymode only the removal of the mode instead of
	        the addition.		
	proc event_mode+v { prefix target parameter } { script }
	proc event_mode-v { prefix target parameter } { script }
	proc event_mode+b { prefix target parameter } { script }
	proc event_mode-b { prefix target parameter } { script }
	proc event_mode+l { prefix target parameter } { script }
	proc event_mode+k { prefix target parameter } { script }
	proc event_mode-k { prefix target parameter } { script }
	proc event_mode+o { prefix target parameter } { script }
	proc event_mode-o { prefix target parameter } { script }
	proc event_mode+? { prefix target } { script }
		Channel modes that aren't covered above.
	proc event_mode-? { prefix target } { script }
	proc event_text { prefix target text } { script }
		This event occurs when a privmsg, with some portion of it not
		being CTCP, occurs.  text is the data in the privmsg with the
		CTCP messages removed.
	proc event_ctcp { prefix target ctcps } { script }
		This occurs when a privmsg occurs with CTCP data.  ctcps is a
		list of data pairs.  In each pair, the first item is the ctcp
		name, the second item is the extra data if any.
	proc event_noticetext { prefix target text } { script }
	proc event_ctcpreply { prefix target ctcps } { script }
		These two events are the equivalent of event_text and
		event_ctcp only they are used for the replies instead of the
		queries.

Other Events:
        proc event_unload {} { script }
	proc event_disconnect {} { script }
	proc event_connect () { script }
		-Happens immediately after socket is connected before any data
		 is sent.


BUILT-IN SUBROUTINES

activebutton
alias
bgerror
callproc
channel
closewindow
configtags
connect
currentindex
currentwindow
die
disconnect
domainloop
echo
echotags
escape
exit
fdisplay
flocation
fparse
fset
gettags
hist
histdown
histup
ic
idle
index
ischannel
microtime
n_complete
newserver
nextwindow
parseentry

popup add item <type> <submenu> <title> <command>
	type is one of the following (erroneous types will be ignored):
                maintext
                mainentry
	submenu is the submenu this entry will be placed in.  It should either
		be "" for no submenu, or it should start with a ".", such as
		".mysub" or ".mysub1.mysub2"  Submenus must be children of
		their parent menus.
	title is the name for the menu item
	command is the tcl code to run when the item is picked.  It will be run
                within the global namespace.

popup add submenu <type> <submenu> <title>
	Creates a submenu with paramters the same as popup add

popup clear <type> <submenu>
	Clears the given menu with paramters the same as popup add

previouswindow
	Makes the previous window in the window list active

renamewindow <pathname> <new name>
	Renames the window specified by the pathname to the given new name.  It
	returns the window index of the new window.

say <message> [<target pathname>]
	Sends a normal message to channel/query/dcc is given.  If the target
        is not provided, it will be sent to the current window.

servers
	Returns a list of the server indexes currently open.

selectednicks
	Returns the nicks selected within a channel, otherwise nothing.

serverindex <pathname>
	Returns the server index for the given pathname, or -1 if the pathname
	refers to the Main Status window or doesn't exist.

shutdown
	Performs any needed shutdown functions.  Is called by exit before it
	calls die.

title <pathname> [<text>]
	Sets the title for the given pathname to the given text.  If no text
	is specified, it returns the current title for the given pathname.

totop <windowindex>
	Brings the given window to the top.  The index is the same as the order
	of the window list starting at 0.  This is called when a window is
	clicked on in the window list or when a window is opened or closed.
	After bringing the window to the top, it runs update to make sure all
	the changes it made actually occur.

version
	Returns the current version number

windowindex [<pathname>]
	Returns the window index for the given pathname, or the window index
        for the current window if the pathname is not given.
	
windowname [<pathname>]
	Returns the window name for the given pathname, or the window name
        for the current window if the pathname is not given.

windows
	Returns a Tcl list of the pathnames of all open windows.

windowtype <pathname>
	Returns the window type for a given pathname.  It will be one of either
	main, status, files, channel, query, or chat.


The following server specific commands are also available.  These will only
work if run from within an event or alias, or if the full namespace to
the command is specified.

acceptlist add chat <nick> <psuedo-ip> <port>
	Adds the chat to a list of chats that need accepted.  The parameters
	are the same as the CTCP DCC CHAT arguments.

acceptlist add send <nick> <psuedo-ip> <port> <filename> [<size>]
	Adds the file to the accept list with the same parameters as the CTCP
	DCC CHAT arguments.

acceptlist accept <idtag>
	Accepts the given session.

acceptlist overwrite <idtag>
	Accepts the given session and overwrites the existing file.

acceptlist rename <idtag> <filename>
	Accepts the given session and renames the file.

acceptlist reject <idtag>
	Rejects the given session.

channelmode <mode letter> <channel>
	Returns 0 or 1 whether the given mode is set for the given channel. If
	the mode letter is l, it will either return 0 or the limit for the
	channel. If the mode letter is k, it will either return "" or the key
	for the channel.

channels
	Returns a TCL list of all the channels currently on the server
	(joined or not).

connected
	Returns 1 if connected, 0 if not.

createchannel <channel>
	Creates a new channel window and performs all the neccessary internal
	actions to set that window up.  If the window already exists it does
	nothing.

createquery <nick>
	Creates a new query window and performs all the neccessary internal
	actions to set that window up.  If the window already exists it does
	nothing.

dcc <type> <nick> [filename]
	Initiates a DCC session.  Type can be either chat or send.  If you use
	send you need to specify the filename.  If you need the DCC to send
	a different IP than is automatically detected, then set the global
	tcl variable dcc_localip, for example:
		/evalglobal set dcc_localip 10.0.0.2
        If you send a file with spaces in the name, the spaces will be
	converted to underlines in order to send the CTCP DCC request.

dccquote [=]<nick> <message>
	Sends the given message to the dcc session specified by the given nick.

disconnect
	Disconnects from the IRC server.

fdisplay <type> [<argument> [<argument> ...]]
	Displays the previously fset type, filling in the given arguments.
	Can use global or server specific locations.

fixnicklist <channel>
	On some occaisions due to the limitations of the IRC protocol, the
	nicklist display for voiced people will become incorrect.  This
	proc allows you to retrieve a new corrected nicklist from the NAMES
	response for the given channel.

fparse <type> [<argument> [<argument> ...]]
	Returns the filled in format for the given type and arguments.  See
	fset for more details. 	Can use global or server specific locations.

index
	Returns the server's index.

ison <nick> <channel>
	Returns 1 if nick is on channel, 0 otherwise.  Returns 0 if you are not
        on the given channel.

isop <nick> <channel>
	Returns 1 if nick in channel is oped, 0 otherwise.  Returns 0 if you
	are not on the given channel.

isvoice <nick> <channel>
	Returns 1 if nick in channel is voiced, 0 otherwise.  Returns 0 if you
	are not on the given channel.

modenicks <channel>
	Returns a TCL list of the nicks in the channel with any @ or +
        prefixes.

modes <channel>
	Returns a string showing the modes set for the given channel.  Nothing
	will be returned if no modes are set.

mynick
	Returns the current nick on that server.

nicks <channel>
	Returns a TCL list of nicks in the channel.

onchannel <channel>
	Returns 1 if you are on the channel, 0 otherwise.

pathname <type> [<argument>]
	TYPE		ARGUMENT
	status		None
	files		None
	channel		Channel Name
	query   	Query Nick
	guess		Channel Name, Query Nick, or DCC Nick
        all             None
        <something>     None

	Returns the pathname associated with the given information.  For guess
	if it can't find the given name it will return the status window's
	pathname.  Returns "" if it can't the appropriate information.  The
	pathname for the Main Status window is ".main"  When the type is all,
        it returns all the pathnames under the appropriate server.

	DCC Nick should have the = in front if you want to be sure to get the
        DCC nick instead of a query nick when using guess.  If guess can't
        find a channel, query, or chat session to match, it will return the
        pathname for the status window.

	If something is not one of the other types, it will run guess on it.

	pathname itself is a frame
	pathname.text is the text box in each window
	pathname.entry is the entry box in each window
	pathname.text_vscroll is the scrollbar
	pathname.nicks is a tk listbox for the nicks in channel windows

popup add item <type> <submenu> <title> <command>
	type is one of the following (main* types will be ignored):
		statustext
		statusentry
		channelnicks
		channeltext
		channelentry
		querytext
		queryentry
		chattext
		chatentry
                filetext
                fileentry
	submenu is the submenu this entry will be placed in.  It should either
		be "" for no submenu, or it should start with a ".", such as
		".mysub" or ".mysub1.mysub2"  Submenus must be children of
		their parent menus.
	title is the name for the menu item
	command is the tcl code to run when the item is picked.  It will be run
                within the ::X namespace where X is the index of the server
                that the popup command is run within.

popup add submenu <type> <submenu> <title>
	Creates a submenu with paramters the same as popup add

popup clear <type> <submenu>
	Clears the given menu with paramters the same as popup add

queries
	Returns a TCL list of all the nicks of the query windows open for the
	current server.

quote <message>
	Sends message to the server.

script <script>
	Loads the script into the interpreter.  Watch the Main Status window
	for errors.  It loads by evaluating the script within its namespace
	and then adding the script to the $::<serveridx>::scripts variable.
        Be sure to use relative pathnames (to ~/.quirc/) when specifying the
	script.  Scripts are server specific.  The script name in the client is
        all alpha-numeric characters immediately following the trailing slash.

server [<server>[:[<port>][:<password>]]]
	Reconnects the current server using the given given server, and port
	if specified.  If no port is specified, uses the default_port.  If no
	server is specified, it uses the default_server.

topic <channel>
	Returns the topic set for the given channel, or nothing if there is
	no such topic or channel.

unscript <script>
	Unloads the script from the interpreter by running the event_unload and
        then destroying the namespace the script is contained within.  It will
        also remove the script from the $::<serveridx>::scripts variable.

userhost <nick>
	Returns the last known user@host for the given nick, or "" if the
	userhost info was not encountered for that nick.  The user@host
	will contain the leading ~ if there is any.  The IAL database
        currently never shortens itself and adds data from the prefix of
	any message sent to the client, userhost, who replies and nick
	changes.


GENERAL SCRIPTING INFORMATION

Each script is loaded into its own namespace.  To access script-wide variables
you should use [set ::[index]::scriptname::variablename], otherwise standard
namespace conventions apply.  See the tcl man page for namespace for details.

Each server has its own namespace, given by ::<serveridx>.  Scripts are loaded
under that namespace as ::<serveridx>::<script_name>, where script_name is
the first part of the script file name that contains only alphanumeric
characters.

The way QuIRC determines which server a given command originated from is that
it checks the name of the proc it was called from.  For example:

	proc ::4::some_script::some_procname {
	    /msg [mynick] hi
        }

will run the /msg command as if it was typed in server 4.  As another example:

	proc some_procname {
	    quote "bleh"
        }

will not know which server to use the quote command on because it wasn't run
from a proc within any server's namespace.  In this case, only global commands
or aliases are allowed.

There are various types of commands which can be run:
	Regular Tcl Commands
	Templated Server Tcl Commands
        Global Aliases
        Server Specific Aliases
        Server Commands

Templated Server Tcl Commands are used in the following manner.  First a proc
is created in the ::template namespace as follows:

	proc ::template::procname { serverindex args } {
        }

After that, whenever procname is executed within a server's namespace (as shown
previously), ::template::procname will be invoked and it will be passed the
server's index as well as the arguments that were given.

Global Aliases are aliases that are created in the global namespace and are
run like this:

	/aliasname regular tcl args

Note that unlike aliases typed in at the command line, the arguments given must
be valid TCL.

Server Specific Aliases are like Global Aliases, but run in the namespace of
the server that they were created in.

Server Commands have the following format:

	/command args

Basically anything that isn't handled by an alias will be sent to the server as
"command args".

To run a command on another server, run:

	evalserver <serveridx> <script>
or:

	namespace eval ::<serveridx> <script>


If you need to escape a string to avoid problems with characters like ", {, $,
[, etc, using pure TCL, I suggest the following:

	[string range [list "\x7d$var"] 2 end]

This is the equivalent to QuIRC's:

	[escape $var]


In QuIRC, if a disconnect is detected, it will check if the auto_reconnect
variable is set.  If it is set, it will then check to see if the connect was
on purpose, in which case the ::[index]::intentional_disconnect variable will
be set to 1.  If it was on purpose, no reconnect will occur, otherwise QuIRC
will attempt reconnection with small delays.  ::template::condis is the proc


QuIRC'S START-UP PROCESS

If you would like to see the techical details as to how QuIRC starts, you will
want to examine the bottom of quirc.cc from the source.  It is well commented
and you shouldn't have many problems seeing what happens.


UI PROGRAMMING INFORMATION

A lot of the UI is handled through qwidgets.tcl.  See that file for info.

* QEntryBox

The QEntryBox widget is used to provide a quick dialog box for entering in
information.  Here is an example of it in use in a popup:

popup add item channeltext "" "Set Keyword (+k)" {
    QEntryBox::create "Channel Keyword" "Enter new keyword for channel:" "::template::quote [index] \"MODE \[channel] +k %g\""
}

The syntax is:
    QEntryBox::create <window title> <message> <command>

Any occurence of %g in the command will be replaced with the results of the
message box.  Note also that the command is run in the global namespace, so
if you need it to send data to a server or something you would need to
specify the server like I did in the example.  You could also use some
form of the tcl namespace command to do that.

QEntryBox returns the the name of the toplevel window it created.  You might
use it with tkwait to make the dialog box modal.

* QPasswordBox

Identical to QEntryBox, only it uses *'s in the box to hide what you're typing.

* QColorChooser

To pop up a little color chooser window that lets users pick one of the current
16 colors, run:

	QColorChooser command

The command will run like so:

	command <color number (0-15)>

If the window is just closed, the command will not be run.  If you want to
modify the window after you run the QColorChooser command, the window is called
.colorchooser.  Only one should be run at a time.

An example of use would be:

	QColorChooser {set ::default_foreground}


ISSUES TO BE AWARE OF

The ANSI system does not handle cases where there is = or " in the given code.
This does not affect the operation for normal IRC type ANSI, but could cause
display of parts of the code if used.  If you encounter this, let me know and
I will do something about it, otherwise it will stay this way.

In order to stop the automatic scrolling in a window due to new text being
inserted, simply move the scrollbar up so it is not at the very bottom.


LACKING FEATURES AND KNOWN BUGS

  A number of these features are easy to implement, however there are so many
  easy things that need done it amounts to tons of work for me.  If there is a
  feature here that you feel you could do, please implement it and send me the
  patch.  I will be happy to include it in the distribution.

  If you encounter any of these bugs, information on where and how it occured
  would be of great help.  If the client cores, please do a "bt" on the core
  in gdb.  The more descriptive the bug report, the more likely I'll be able
  to find the bug.  If you can make a patch for it yourself, all the better :)

  The list has moved to http://quirc.org/cgi/bugs.cgi.

Enjoy!  Patrick Earl (Hynato on irc.dal.net, patearl@pobox.com)
