jab -- CLI-based Jabber client of/by/for Ruby Author: Chip Camden Date: August, 2010 Site: http://chipstips.com/?tag=rbjab Hg: http://bitbucket.org/sterlingcamden/jab GENERAL DESCRIPTION jab provides a minimal, text-only, serial (no cursing) XMPP or IRC client written in Ruby, that uses Ruby as its command language. jab provides methods to handle the common set of chat tasks, but of course you can execute any Ruby code within its read-eval loop. jab binds the execution context of all evaluated commands to a proc inside the Jab class. This means any local variables you define will not conflict with variables in the calling program, and any methods or instance variables you define will be contained within the Jab class. To set up your environment each time you start jab, you can place commands in a file named ~/.jabrc -- if that file exists, it will be executed before jab asks you for input. You can also override the name of this file with the -r command-line option. Typical commands placed in .jabrc include connecting to the server, defining aliases, selecting colors, enabling extensions, and user-specific functions. An example .jabrc file is included with this distribution as dot.jabrc, along with two files that it relies upon: .jab-aliases (dot.jab-aliases) and .jab-colors (dot.jab-colors). A second example can be found in dot.jabrc-irc, which shows how to use jab for IRC. You can use these as patterns for creating your own customized jab session. For the list of common commands, type 'help' at the prompt (:). Help pages its output by piping it to the executable named in the PAGER environment variable, or "less" if PAGER is not set. For full command reference, see the REFERENCE section below. jab supports command history and either vi-style or emacs-style editing, using Readline. Whenever a prompt includes a list of possible responses, command completion is available by pressing Tab. You can suppress the use of Readline by setting @@use_readline to false. jab does not provide conversation logging, but you can easily accomplish that by redirecting output through tee(1). jab does not separate multiple, simultaneous conversations, but it does provide visual cues to tell you not only who said something but to whom your next line of text will go if you don't switch jabs. Because chat operates asynchronously, you will often receive a message or notification while composing a message. If that confuses you to the point of not being able to finish your thought, use Ctrl+U to erase your pending input, press Return to get a fresh prompt, and begin again. An empty line is always ignored when entering commands or messages. If you panic and press Ctrl+C, no worries -- the interrupt will be reported to you, and you'll get another prompt. Alternatively, see the provided extension 'keep-prompt', which scrolls all output above the bottom line and keeps the prompt line intact. When you're all done, you can press EOF (usually Ctrl+D on Unix systems) to exit jab, or use the 'q' or 'exit' commands. INSTALLATION You must first install Ruby and the xmpp4r gem. Place the file jab.rb in a directory that is included in your Ruby load path. To see what directories are included, use the command: ruby -e "puts $:" You can also specify a directory to add to the load path using Ruby's -I switch. Place the file jab in a directory in your PATH, unless you want to always execute it by specifying the full path. Edit default commands into ~/.jabrc, and you're ready to go! jab COMMAND LINE OPTIONS -e, --emacs Use emacs line editing (default is vi) -h, --help Display help and exit -r, --rcfile RCFILE Use a different startup file (can use more than one) -v, --version Display version and exit REFERENCE This section documents all of the methods of the Jab class, which can naturally be used as commands in jab along with other Ruby statements. --- about => nil Prints version, author, and web site information. --- ask(prompt, silent=nil, call=nil) => string or nil Displays prompt to the user (applying any color filters), and returns the user's response. If silent is true and $stdin is a terminal, turns echo off and back on using stty(1). Prompt is prefixed by the name of the caller, in parentheses -- but that can be suppressed by passing call as ''. You can also override the name of the caller by passing call as a string containing the desired caller in `' (back-quote, single-quote). The prompt may be further filtered by providing a proc for the :prompt event. See 'on' and EVENTS. If the user presses the EOF key, ask returns nil -- otherwise, whatever the user entered. However, input may be filtered by assigning a proc to the :input event. See 'on' and EVENTS. When $stdin is a terminal, command line editing and recall are enabled using the Readline module. Editing mode is vi by default, but can be overridden to emacs using the -e command line switch. --- bg(color) => string Synonym for get_color('AB', color). --- signal_event(event, *args) => Object or nil Calls all procs associated with event, in the order they were specified. Returns the result of the last such proc, or nil if no such events are specified. See 'on'. Any arguments passed to signal_event will in turn be passed to each proc. --- color(what, *how) => Array Adds a color filter to all output. The what parameter is required and must be a regular expression (or something that can be converted into a regular expression via Regexp.new) that specifies the portion of the string to which to apply color. Thus, if you want to color the whole string, be sure that your expression includes the beginning and end of the string. The remaining parameters specify colors to apply. They should be terminal-specific strings of escape sequences to apply colors. You can generate these sequences using the 'fg', 'bg', or 'get_color' methods. The sequences will be prefixed, in order, to the matching portion of the string. If one or more sequences are specified, then the matching portion of the string will be followed by the terminal-specific sequence for the "me" termcap capability. Care should be taken when specifying two or more color filters that may apply to the same string. All color filters will be applied in the order specified, but the application of one filter may prevent another one from matching -- because each escape sequence gets inserted into the original string. Some examples of color filters can be found in the file dot.jab-colors. --- connect(user=nil, password=nil) => Boolean Connects to a server. The user argument should be in the form "user@domain/resource" for XMPP (Jabber). When using the 'protocol-irc' extension, it should be in the format "nick@domain". If nil, the user will be asked to enter it. Likewise, if password is not provided, the user will be asked for it, using the silent option on 'ask'. Passing an empty string (or pressing Enter at the prompt) will leave the password unspecified (common for IRC). Returns true if the connection was established. Returns false if the user entered EOF at any prompt. Raises an error if the connection failed. After a connection is successfully established, the :connect event is signaled. --- disconnect => nil Disconnects any current session. In interactive mode, 'interact' will immediately prompt for a new connection. Prior to closing the connection, the :disconnect event is signaled. --- filter_event(event, arg) => Object Applies the procs associated with event as filters to arg. Each proc associated with event (if any) is called in the order specified, passing arg as an argument. Whatever the proc returns becomes the new value of arg. Returns the final value, or the original value if no procs are defined for event. See 'on'. --- fg(color) => string Synonym for get_color('AF', color). --- get_color(cap, color) => string Returns the character sequence for the termcap capability named cap for the current terminal, given the argument color. By default, this uses tput(1), but you can override that by setting @@termcap['AF'] and @@termcap['AB']. While this is used for colors in jab, it could also be used for any termcap capability (by passing any arguments joined by spaces in color). --- getcmd => string or nil Asks the user for input using only a ':' prompt (still applying any color filter). Rescues Interrupt and prints "interrupted" instead of a full exception. Returns the command typed, or '' if interrupted, or nil if the user entered EOF. --- handle_requests => Boolean Asks the user to confirm any pending subscription requests when the subscription handling action is :ask (see 'when_tapped'). This method is called automatically within the 'interact' loop, so you only need to call it if you are using these methods outside of 'interact'. --- help => nil Outputs helpful information by piping it through the utility named in the environment variable PAGER. If PAGER is not set, "less" is used. --- hush(what) => false Synonym for notify(what, false). --- id_verbosity(level) => nil Sets the verbosity level for usernames in messages. The default is 2. For the Jabber protocol, the following levels apply: 0 = Just the username portion 1 = Username@domain otherwise = Username@domain/resource For the IRC protocol, if set to 0, only the username is displayed. Otherwise, the entire user ID is displayed. --- interact => nil A read/eval loop for interactive jabbing. As long as the user does not press EOF or enter some equivalent of 'exit', the loop continues. Each command is evaluated within the sandboxed binding. Any errors are rescued and reported to the user. This method cannot proceed without a connection, so if one is not established it will ask the user for login credentials and attempt to connect. If a connection is not established, this method also returns nil. --- interject(type, sender, message) => nil Provides a layer over 'say' for filtering messages based on notification preferences. The type argument is a symbol for filtering, per the 'notify' method -- typically one of :errors, :info, :status, :jabs, or :always. If the corresponding element of the @notify array is true, the message will be displayed, otherwise suppressed. The sender argument becomes the first element of the message. It may be nil to suppress that portion. The message will be terminated with a newline. --- irc(command) => nil When using IRC, sends command directly to the server. This command has no effect when using XMPP. --- jab(whom=nil, message=nil) => nil Sends a chat message to whom. The whom argument should be in the form 'user@domain' or 'user@domain/resource' for XMPP -- for IRC it can be either a nickname or a channel. The user will be asked for it if nil. If the message argument is nil, jab accepts messages in a loop until EOF. Each prompt includes the destination, so you can easily tell to whom you are chatting. When using IRC, a line of text beginning with '/' will be taken as an IRC command. Message send errors are not synchronous, so this method always returns nil. If an error occurs, it will be displayed to the user via 'interject' with type :errors. --- multiask(choices, default=nil, call=nil) => string or nil Uses ask to retrieve a multiple-choice answer from the user. The choices argument should be an array of strings containing the possible choices, and the prompt will be composed of these, separated by '/'. If default is non-nil, the choice that matches it will be enclosed in  in the prompt, and will be returned if the user enters only Return. Otherwise, the user's input must match one of the choices. Auto-completion is enabled through the Readline module to match one of the choices. The call parameter behaves exactly as for 'ask' -- with the exception that if not passed, it defaults to the caller of multiask. --- on(event, &proc=nil) => Array Adds to and/or returns the list of procs to call on an event. The event parameter is a symbol (or will be converted to a symbol) that is used to identify the event. For the list of events that are used by jab, see EVENTS below. Of course, you may add and signal your own events as well. See 'signal_event' and 'filter_event'. If proc is non-nil, it will be added to the list of procs to call for this event. In any case, this method returns that list. --- notify(what=nil, how) => Boolean Enables or disables a class of notifications. The what argument will typically be one of the following: :all combination of :errors, :info, :jabs, and :status :errors error messages :info informational messages :jabs messages from other users :status status updates from users If what is not passed, the user will be asked for one of the above choices. If how is true, the specified notification(s) will be enabled, otherwise disabled. If you pass what, it can be something other than one of the above, which allows you to create a new class of notifications for you own use. I'd recommend avoiding :always, as that is used internally for notifications that may not be suppressed. Returns how. --- q Synonym for 'exit'. --- say(what) => nil Prints what to $stdout, after applying any color filters. --- settings => nil Prints current settings to $stdout, after applying any color filters. The following settings are reported for XMPP: status :state, 'message' # current availability status hush :type # any suppressed notifications when_tapped :action # how to handle subscription requests The following settings are reported for IRC: domain, port, nickname the result of sending an INFO command to the server --- shove(whom=nil) => nil XMPP: Sends an :unsubscribe request to whom. If whom is nil, the user will be asked for it. While there is a supported mechanism to receive responses to this request, I have yet to see any server provide them. IRC: Sends a PART command for channel specified by whom. --- source(file=nil, ignore_fnf=nil) => Object or nil Processes commands from file. if file is nil, the user will be asked for it. Returns the result of evaluating file -- or nil if an error occurred, the user pressed EOF, or the file does not exist and ignore_fnf is true. The entire file is evaluated in one eval statement, so statements can cross line boundaries (unlike within 'interact'). If an error occurs, it is rescued and reported to the user. As with 'interact', all commands are evaluated within a sandboxed binding. If ignore_fnf is true, then if the file does not exist no error occurs. Otherwise, an Errno:ENOENT error is reported. --- status(state=nil, message=nil) => Jabber::Presence or nil Set the user's current status. State must be one of :available, :away, :chat, :dnd (do not disturb), or :xa (extended away), but may be a string instead of a symbol. If nil, the user will be asked, with the default being :available. The message argument is an optional text description of the status. If nil, the user will be asked. Use an empty string for no message. Returns the new Jabber::Presence resulting from the specified status, or nil if the user pressed EOF at any prompt. This command has no effect when using IRC. Use "irc away [message]" or /away at a jab prompt to set away status. --- tap(whom=nil) => nil XMPP: Sends a :subscribe request to whom. If whom is nil, the user will be asked for it. Most XMPP servers respond to this message with a status update if you have successfully subscribed now or in the past, so you can use this command to check status of an existing friend as well as to subscribe to a new one. IRC: Sends a JOIN command for the channel specified by whom. --- unhush(what) => true Synonym for notify(what, true). --- when_tapped(action) => Symbol or nil Specify how to handle incoming subscription requests. Action may be one of the following, or its string equivalent: :ask Ask the user on the next call to 'handle_requests' :y Always approve :n Always decline If action is nil, the user will be asked for one of the above. If the user presses EOF, returns nil, otherwise the symbol. This command has no effect when using IRC. --- EVENTS You may define and signal any number of events, but the folloiwng list indicates pre-defined events that are signaled by jab. See 'on', 'signal_event', and 'filter_event'. Event When called Arguments Returns ----- ----------- --------- ------- :connect 'connect' after opening none ignored the connection :disconnect 'disconnect' before none ignored closing the connection :identity 'interject' before output user identity filtered identity :input 'ask' after user presses Enter user input filtered input (string or nil) :interject 'interject' before output (string) filtered string :jab before displaying an incoming body of jab filtered body jab (occurs before :interject) (string) :prompt 'ask' before prompting user prompt (string) filtered prompt (and before applying colors) MEMBER VARIABLES Because each command is evaluated within a proc inside the Jab class, you can access instance and class variables of the Jab class. The following variables are provided: @@numcolors Number of colors supported by this terminal. This is only set on the first call to 'get_color'. @@me The terminal-specific sequence for the termcap capability "me". This is only set on the first execution of 'color'. @@termcap Hash of termcap capability and command used to retrieve it. The default is to use tput. @@use_readline Whether to use the Readline module for terminal input. True by default. @accept How to handle subscription requests. One of :ask, :y, or :n. @client Jabber::Client for the connection. @colors Array of color filters. Each element of the Array is an Array of [Regexp, String], where Regexp is the regular expression of the match, and String is what to replace it with (using String#gsub!) @domain When using IRC, the server URL. @events Hash of :event => [proc...], hooks to call on certain events. Set by 'on'. @id_verbosity The verbosity level for user identities. @listener When using IRC, the thread that receives messages from the server. @nick When using IRC, the user's nickname. @notify Hash of notification settings. Each element is Symbol => Boolean, where Symbol is one of the notification type symbols, and Boolean is true if enabled. @pager Pager command to use for 'help'. @port When using IRC, the port number on the host. @presence Jabber::Presence from last status modification for this user. @real_name When using IRC protocol, the user's full name. Must be set prior to connecting to take effect. If not set when connecting, the value of $USER will be used to extract the full name from /etc/passwd. @requests Queue of pending subscription requests. Each element of the Array is a Jabber::Presence from a request. @roster Jabber::Roster::Helper for the connection. @sandbox Binding for command evaluation. @statuses Hash of user => [:status, 'message'] for previously seen status updates. @user Currently connected username. EXTENSIONS The following extensions to jab are provided. See the comments at the top of each file for usage, but in general all you need to do is source these in your .jabrc to obtain their functionality. notify-new Updates a file with the number of unread jabs. keep-prompt Keeps the prompt visible on the last line of the terminal. Relies on specific termcap entries. Also adds the current time to each notification. protocol-irc Substitutes the IRC protocol instead of Jabber. Connects to an IRC server, changes the 'tap' command to joing a channel, and 'jab' to start talking to a channel or user. When in iterative jab mode, a '/me ' at the beginning of a line will send an ACTION message, otherwise a '/' at the beginning of a line indicates an IRC command. The extension also adds an explicit 'irc' command. See the supplied file dot.jabrc-irc for a usage example. Of course you can write your own extensions just as simply as these are implemented. END
stacyw70 began watching sterlingcamden/jab
95c21ae - Update license to OWL 0.9
5f58799 - Added /me to IRC protocol
71225df - Override respond_to? since we're overriding method_missing.
f7e484b - Added id_verbosity and :identity event.
e0b7074 - Forgot to include keep-prompt in the repo.
f394da2 - Update license to OWL 0.8
e2fe71a - Remove accidental change
7ddbdcd - Added logging module