ZIRC - The 100% Zsh IRC client :)

X-seq: zsh-users 10388

From: Andrew Ruder <andy@xxxxxxxxxxx>

To: zsh-users@xxxxxxxxxx

Subject: ZIRC - The 100% Zsh IRC client :)

Date: Sun, 18 Jun 2006 15:48:43 -0500

Mailing-list: contact zsh-users-help@xxxxxxxxxx; run by ezmlm

As you can probably tell by the topic, I had some free time this weekend and have created quite possibly the *stupidest* ZSH program ever. ZIRC is an IRC client. It hooks into ZLE's asynchronous select() support and ZSH's builtin TCP support to do everything. Not a *single* external, non-zsh command was used in this program. If you're typing something at the prompt and someone messages you, it'll simply interrupt your current prompt, print out the message and let you continue with your typing. How to use (additional docs at the top of the script): *) Source the file (. ./zirc) *) (Optional) Run zsh_aliases, this sets up some aliases to make it a bit more comfortable to use. me => zirc_action msg => zirc_msg last => zirc_last connect => zirc_connect etc... *) Important commands: command(alias) zirc_switch(sw): change channel focus zirc_last(last): change channel focus to last place with a message zirc_query(query): change focus to username zirc_msg(msg): message to focused user/channel zirc_pmsg(pmsg): message to any user/channel zirc_quit(quit): quit with optional quit message zirc_nick(nick): change nickname zirc_connect(connect): connect to IRC server zirc_part(part): Leave channel zirc_help(help): List zirc commands zirc_action(me): Perform action in focused channel/user *) Screenshot: (I have my prompt setup to incorporate $ZIRC_CURRENT to show current focus) http://dump.aeruder.net/zirc.png I suppose if you were in some not too busy channels, this thing could be pretty useful, but really, its mostly designed to just be a joke so you can tell your friends: "Yea, well, my shell has an IRC client" Have fun, Andrew Ruder P.S. I'm sure there are still some bugs, but I've just got some other things I should probably be doing this weekend, 0.2 for bug fixes :) -- Andrew Ruder <andy@xxxxxxxxxxx> http://www.aeruder.net

#!/bin/zsh # vim:noet fdm=marker sw=4 ts=4 ZIRC_VERSION="0.1" # ZIRC - A 100% ZSH IRC client # # Copyright (C) 2006 by Andrew Ruder <andy@xxxxxxxxxxx> # # This IRC client is pretty ridiculous, I made it entirely as a joke, but it # actually works fairly decently for as little work has been put into it. # And of course, afaik, there are *no* external commands used in the making # of this program. No grep, no sed, nothing... pretty cool :) # # Guide to using it: # Step 1) Source this file. # . ./zirc or whatever # You can even put this into your .zshrc, it won't hurt anything # besides the creation of several _zirc_*/zirc_* functions. # Step 2) (Optional) Run zsh_aliases # This sets up several aliases to make it easier to use. Basically # it strips the zirc_ front end off of everything. If you want to # see the alias list, type echo $functions[zsh_aliases] # Step 3) Run zirc_connect # It'll explain the syntax and the fairly standardized environment # variables controlling its behavior. # Step 4) Use zirc_msg to message, zirc_pmsg to private message. # zirc_switch can change to another channel. (zirc_switch somechan) # or # zirc_query can change to anything # Step 5) zirc_last is very handy as it switches to the channel/user that # last said something to you. # # Prompt integration: a few environment variables can help you on your way. # $ZIRC_CURRENT = current focus # $ZIRC_NICK = current nickname # $ZIRC_SERVER = connected server # # 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. [[ -z "$modules[zsh/net/tcp]" ]] && zmodload zsh/net/tcp [[ -z "$modules[zsh/zselect]" ]] && zmodload zsh/zselect ZIRC_PARAMS=( ZIRC_NICK ZIRC_USER ZIRC_NAME ZIRC_PORT ZIRC_HOST ) if ! [[ -z "$ZIRC_FD" ]] && ! [[ -z "$functions[zirc_disconnect]" ]] ; then zirc_disconnect fi ZIRC_VARS=( ZIRC_LAST ZIRC_CHANNELS ZIRC_CURRENT ZIRC_LOWERCASER ZIRC_FD ZIRC_SERVER "${ZIRC_PARAMS[@]}" ) ZIRC_UNSETSTRING="unset ${ZIRC_VARS[*]}" eval "$ZIRC_UNSETSTRING" typeset -g "$ZIRC_VARS[@]" typeset -A ZIRC_PARAM_DEFS ZIRC_PARAM_DEFS[ZIRC_NICK]="Nickname:\$IRCNICK:$USERNAME" ZIRC_PARAM_DEFS[ZIRC_USER]="Username:\$IRCUSER:$USERNAME" ZIRC_PARAM_DEFS[ZIRC_PORT]="Port:\$IRCPORT:6667" ZIRC_PARAM_DEFS[ZIRC_NAME]="Real name:\$IRCNAME:John Doe" ZIRC_PARAM_DEFS[ZIRC_HOST]="Host name:\$IRCHOST:localhost" # zirc_connect parameter handling {{{ # Print out help for the environment variables using the # ZIRC_PARAM_DEFS and ZIRC_PARAMS variables as a reference function _zirc_param_help { local a b echo -e "Environment variables:" for a in "${ZIRC_PARAMS[@]}"; do b=( ${(s/:/)${ZIRC_PARAM_DEFS[$a]}} ) echo -e "\t${b[2]} - ${b[1]} (default ${b[3]})" done } # Fills in the variables in ZIRC_PARAMS using the correct # fallback values specified in ZIRC_PARAM_DEFS function _zirc_param_populate { local a b for a in "$ZIRC_PARAMS[@]"; do b=( ${(s/:/)${ZIRC_PARAM_DEFS[$a]}} ) if [ -z "${(e)b[2]}" ]; then eval "${a}=\"\${b[3]}\"" else eval "${a}=\"\${(e)b[2]}\"" fi done } # }}} # Lowercasing/string comparison code {{{ # Lowercasing according to rfc1459 strictly function _zirc_lowercase_strict_rfc1459 { local msg="${(L)1}" msg=${msg//\[/\{} msg=${msg//]/\}} msg=${msg//\\/\|} echo "${msg}" } # Lowercasing according to rfc1459 function _zirc_lowercase_rfc1459 { local msg="$(_zirc_lowercase_strict_rfc1459 "$1")" msg=${msg//\~/^} echo "${msg}" } # Lowercasing using standard ascii rules function _zirc_lowercase_ascii { echo "${(L)1}" } # Lowercasing according to the current server's specs function _zirc_lowercase { "$ZIRC_LOWERCASER" "$1" } # Case-insensitive compare according to the case-mapping= spec for the server function _zirc_compare { [[ "$("$ZIRC_LOWERCASER" "$1")" == "$("$ZIRC_LOWERCASER" "$2")" ]] } # Determine if a prefix/word is referring to you function _zirc_isme { _zirc_compare "$ZIRC_NICK" "$(_zirc_prefix_nick "$1")" } # }}} # data from server parsing {{{ # Parse a line like # :blah!host blah3 blah4 :Message with lots of words # and output # blah!host # blah3 # blah4 # Message with lots of words function _zirc_parse_server_line { local readval args args=() readval=( "${(f)$(_zirc_parse_server_prefix "$1")}" ) args+=( "${readval[1]}" ) while ! [[ -z "${readval[2]}" ]] ; do readval=( "${(f)$(_zirc_parse_server_word "${readval[2]}")}" ) #" Bug in vim highlighting if ! [[ -z "${readval[1]}" ]]; then args+=( "${readval[1]}" ) fi done echo "${(F)args}" } # Parse a line like # :blah!host blah3 blah4 # and print out # blah!host # blah3 blah4 function _zirc_parse_server_prefix { local line prefix local EXTENDED_GLOB ; EXTENDED_GLOB=1 line="${1## #}" if [[ "${line[1]}" != ":" ]]; then prefix="" else prefix="${line%% *}" if [[ "$prefix" == "$line" ]]; then line="" else line="${line#* }" fi fi echo "${prefix#:}" echo "$line" } # Parse out a single word from a line, so # blah3 blah4 :Message # prints out: # blah3 # blah4 :Message # again: # blah4 # :Message # again # Message # <empty line> function _zirc_parse_server_word { local line word local EXTENDED_GLOB ; EXTENDED_GLOB=1 line="${1## #}" if [[ "${line[1]}" != ":" ]]; then word="${line%% *}" if [[ "$word" == "$line" ]]; then line="" else line="${line#* }" fi else word="${line#:}" line="" fi echo "$word" echo "$line" } # Split a prefix and get nick (nick!host) # Input: nick!host or nick # Output: # <empty-line> function _zirc_prefix_nick { local a a=( "${(f)$(_zirc_split_prefix "$1")}" ) echo "${a[1]}" } # Split a prefix and get host (nick!host) # Input: nick!host # Output: # host # Input: nick # Output: # <empty-line> function _zirc_prefix_host { local a a=( "${(f)$(_zirc_split_prefix "$1")}" ) echo "${a[2]}" } # Split a prefix # Input: nick!host # Output: # nick # host # Input: nick # Output: # nick # <empty-line> function _zirc_split_prefix { local a a=( ${(s:!:)1} ) [[ ${#a} == "1" ]] && a+=( '' ) echo "${(F)a}" } # }}} # CTCP handling {{{ # Print out the generic ctcp message # Args: prefix command where ctcp msg function _zirc_generic_ctcp { local pref="$1" comm="$2" local where="$3" ctcp="$4" local msg="$5" local who="$(_zirc_prefix_nick "$pref")" _zirc_echo -n "<CTCP> <$who" _zirc_isme "$where" || _zirc_echo -n ":$where" _zirc_echo "> $ctcp $msg" } # Write out a CTCP request # Args: prefix command where ctcp msg function _zirc_ctcp_request_write { local msg if ! [[ -z "$2" ]] && ! [[ -z "$3" ]]; then msg="$2 $3" else msg="$2" fi _zirc_write "`printf "PRIVMSG %s :\001%s\001" "$1" "$msg"`" } # Write out a CTCP reply # Args: where ctcp message function _zirc_ctcp_reply_write { local msg if ! [[ -z "$2" ]] && ! [[ -z "$3" ]]; then msg="$2 $3" else msg="$2" fi _zirc_write "`printf "NOTICE %s :\001%s\001" "$1" "$msg"`" } # Handle a VERSION request function _zirc_ctcp_request_VERSION { _zirc_generic_ctcp "$@" local pref="$1" local who="$(_zirc_prefix_nick "$pref")" _zirc_ctcp_reply_write "$who" "VERSION" "ZIRC $ZIRC_VERSION - 100% zsh!!" } # Handle a PING request function _zirc_ctcp_request_PING { local pref="$1" msg="$5" local who="$(_zirc_prefix_nick "$pref")" _zirc_echo "Received a CTCP PING from $who" _zirc_ctcp_reply_write "$who" "PING" "$5" } # Handle an ACTION function _zirc_ctcp_reply_ACTION { local pref="$1" where="$3" msg="$5" local who="$(_zirc_prefix_nick "$pref")" if ( _zirc_isme "$where" ); then _zirc_compare "$ZIRC_CURRENT" "$who" || ZIRC_LAST="$who" _zirc_echo "*** * $who $msg" else _zirc_echo -n "* $who" _zirc_compare "$ZIRC_CURRENT" "$where" || { ZIRC_LAST="$where" _zirc_echo -n ":$where" } _zirc_echo " $msg" fi } # Handle ACTION requests just like replies function _zirc_ctcp_request_ACTION { _zirc_ctcp_reply_ACTION "$@" } # Handle all other CTCP requests function _zirc_ctcp_request_other { _zirc_generic_ctcp "$@" } # Handle all other CTCP replies function _zirc_ctcp_reply_other { _zirc_generic_ctcp "$@" } # Parse the CTCP stuff and call the appropriate CTCP function above # args: pref command where ctcp+message function _zirc_command_CTCP { local pref="$1" comm="$2" local who="$(_zirc_prefix_nick "$pref")" shift 2 local where="$1" msg="$2" local ctcp func args ctype if [[ "$((#msg))" == "1" ]]; then msg="${msg#?}" fi if [[ "$((##${msg[-1]}))" == "1" ]]; then msg="${msg%?}" fi ctcp="${(U)msg%% *}" msg="${msg#* }" if [[ "$msg" == "$ctcp" ]]; then msg="" fi ctype="request" [[ "$comm" == "NOTICE" ]] && ctype="reply" func="_zirc_ctcp_${ctype}_${ctcp}" if [[ -z "${functions[${func}]}" ]]; then func="_zirc_ctcp_${ctype}_other" fi args=( "$pref" "$comm" "$where" "$ctcp" "$msg" ) "${func}" "$args[@]" } # }}} # Server command handling {{{ # An echo that should be used by anything automatically # called (commands). It invalidates the current prompt line first. function _zirc_echo { zle -I echo "$@" } # Handle private messages function _zirc_command_PRIVMSG { local pref="$1" comm="$2" shift 2 local who="$(_zirc_prefix_nick "$pref")" local where="$1" msg="$2" if [[ "$((#msg))" == "1" ]]; then _zirc_command_CTCP "$pref" "$comm" "$where" "$msg" return 0 fi if ( _zirc_isme "$where" ); then _zirc_compare "$ZIRC_CURRENT" "$who" || ZIRC_LAST="$who" _zirc_echo "*** <$who> $msg" else _zirc_echo -n "<$who" _zirc_compare "$where" "$ZIRC_CURRENT" || { _zirc_echo -n ":$where" ZIRC_LAST="$where" } _zirc_echo "> $msg" fi } # Handle nickname changes function _zirc_command_NICK { local pref="$1" newnick="$3" local who="$(_zirc_prefix_nick "$pref")" if [[ "$who" == "$ZIRC_CURRENT" ]]; then ZIRC_CURRENT="${newnick}" fi _zirc_isme "$pref" && ZIRC_NICK="$newnick" _zirc_echo "$who is now known as $newnick" } # Handle channel joins function _zirc_command_JOIN { local pref="$1" comm="$2" shift 2 local who="$(_zirc_prefix_nick "$pref")" local at="$(_zirc_prefix_host "$pref")" local where="$1" _zirc_echo "$who ($at) has joined $where" _zirc_isme "$pref" && { ZIRC_LAST="$ZIRC_CURRENT" ZIRC_CURRENT="$where" ZIRC_CHANNELS+=("$where") } } # Handle channel parts function _zirc_command_PART { local pref="$1" comm="$2" where="$3" msg="$4" local who="$(_zirc_prefix_nick "$pref")" _zirc_echo "$who has left $where ($msg)" _zirc_isme "$pref" && { [[ ZIRC_CURRENT == "$where" ]] && ZIRC_CURRENT="$ZIRC_LAST" ZIRC_CHANNELS[(r)$where]=() } } # Handle people quitting function _zirc_command_QUIT { local pref="$1" comm="$2" msg="$3" local who="$(_zirc_prefix_nick "$pref")" _zirc_echo "$who has quit IRC ($msg)" } # Handle topic changes function _zirc_command_TOPIC { local pref="$1" comm="$2" where="$3" msg="$4" local who="$(_zirc_prefix_nick "$pref")" _zirc_echo "$who has changed the topic in $where to '$msg'" } # Handle mode changes function _zirc_command_MODE { local pref="$1" comm="$2" object="$3" mode="$4" local who="$(_zirc_prefix_nick "$pref")" local rest rest=( "${@[4,-1]}" ) rest=( " "${^rest} ) rest=${(j::)rest} _zirc_echo "$who sets mode $mode ${object}${rest}" } # Handle invites function _zirc_command_INVITE { local pref="$1" comm="$2" where="$4" local who="$(_zirc_prefix_nick "$pref")" _zirc_echo "$who has invited you to $where" } # Handle kicks function _zirc_command_KICK { local pref="$1" comm="$2" where="$3" user="$4" msg="$5" local who="$(_zirc_prefix_nick "$pref")" _zirc_echo "$user was kicked from $where by $who ($msg)" } # Handle pong messages (shouldn't get these generally, but just in case) function _zirc_command_PONG { } # Handle notices, although we just forward this onto the privmsg code function _zirc_command_NOTICE { _zirc_command_PRIVMSG "$@" return } # Handle wallops function _zirc_command_WALLOPS { local pref="$1" comm="$2" msg="$3" local who="$(_zirc_prefix_nick "$pref")" _zirc_echo "Wallops from $who: $msg" } # Handle IRC Errors function _zirc_command_ERROR { local pref="$1" comm="$2" shift 2 _zirc_echo "ERROR: ${(j: :)@}" } # Handle server pings function _zirc_command_PING { local pref="$1" comm="$2" shift 2 _zirc_write "PONG :$1" } # RPL_WELCOME handler... this will (among other things) # inform us of our true nickname function _zirc_command_numeric_001 { ZIRC_NICK="$3" } # RPL_ISUPPORT this tells us how to handle casemapping function _zirc_command_numeric_005 { case "$4" in *casemapping=rfc1459*) ZIRC_LOWERCASER="_zirc_lowercase_rfc1459" ;; *casemapping=strict-rfc1459*) ZIRC_LOWERCASER="_zirc_lowercase_strict_rfc1459" ;; *casemapping=ascii*) ZIRC_LOWERCASER="_zirc_lowercase_ascii" ;; esac } # Handle numeric commands function _zirc_command_numeric { local pref="$1" comm="$2" _zirc_echo "-- ${(j: :)@[4,-1]}" if ! [[ -z "$functions[_zirc_command_numeric_${comm}]" ]]; then _zirc_command_numeric_"$comm" "$@" fi } # catchall for unhandled commands function _zirc_command_other { local EXTENDED_GLOB=1 local pref="$1" comm="$2" shift 2 if [[ "$comm" == [0-9]## ]]; then _zirc_command_numeric "$pref" "$comm" "$@" return 0 fi } # }}} # ZLE hooks {{{ # Parse a single line of incoming data function _zirc_handle_incoming_data_piece { local line comm func output line="$1" line=( "${(f)$(_zirc_parse_server_line "$line")}" ) comm="${(U)line[2]}" func="_zirc_command_${comm}" if [[ -z "${functions[${func}]}" ]]; then func="_zirc_command_other" fi "$func" "$line[@]" } # The ZLE informs this when there is data. Grab the data, and then # grab any additional data available (using zselect) and passing all # of this back off to the _zirc_handle_incoming_data_piece function function _zirc_handle_incoming_data { local fds line if [[ "$1" != "$ZIRC_FD" ]]; then zle -I echo "ZIRC: Handling some other file handle???" return 1 fi while true; do if ! read -r line <&$ZIRC_FD; then zle -I zirc_disconnect return 1 fi if [[ "$((##${line[-1]}))" == "13" ]]; then line="${line%?}" fi _zirc_handle_incoming_data_piece "$line" fds=() zselect -r -t 0 -a fds $ZIRC_FD if [[ "${#fds}" != "2" ]]; then break fi done } # }}} # User commands and utility functions used by them {{{ # Write out a message to the server. It puts on the correct line ending # for the IRC protocol too function _zirc_write { local a if [[ -z "$ZIRC_FD" ]]; then return 1 fi if [[ -z "$1" ]]; then return 0 fi a="$@" printf "%s\r

" "$a" >&$ZIRC_FD } # Send the initial connection lines to the server function _zirc_send_connect_lines { _zirc_write "NICK $ZIRC_NICK" _zirc_write "USER $ZIRC_USER $ZIRC_HOST $ZIRC_SERVER :$ZIRC_NAME" } # Input: # channel name (or part of a channel name) # Output: # shortest channel that matches *<input> function _zirc_channel_match { local chan="$1" local chans shortest a chan="*${chan}" chans=( "${ZIRC_CHANNELS[@]}" ) chans=( ${(e):-\${(M)chans:#$chan}} ) if [[ "${#chans}" == "0" ]]; then echo "" return 1 fi shortest=" "; shortest="${(l:1000:: :)shortest}" for a in "${chans[@]}"; do (( ${#a} < ${#shortest} )) && shortest="${a}" done echo "${shortest}" return 0 } # Switch focus. This uses _zirc_channel_match so the globbing will make it # easier to switch channels. # # zirc_switch step # # would change to #gnustep if you were correctly connected to that channel function zirc_switch { local chan="$1" local chans shortest a zirc_connected || { echo "Not connected" ; return 1 } if [[ -z "$chan" ]]; then echo "Usage: $0 <channel>" echo "Switches current channel focus (Current: '${ZIRC_CURRENT}')" echo "This command is only used for channels, use zirc_query for a more" echo "general solution." return 1 fi chan="$(_zirc_channel_match "$chan")" if [[ -z "$chan" ]]; then echo "Could not find anything for '$1'" echo "Current channels: ${(j:,:)ZIRC_CHANNELS}" return 1 fi ZIRC_LAST="$ZIRC_CURRENT" ZIRC_CURRENT="${chan}" echo "Switched to $ZIRC_CURRENT" return 0 } # Just switch focus to the argument. Don't check against anything else. function zirc_query { local query="$1" zirc_connected || { echo "Not connected" ; return 1 } if [[ -z "$query" ]]; then echo "Usage: $0 <user/channel>" echo "Switches current focus. (Current: '${ZIRC_CURRENT}')" echo "No expansion will be done on the parameter. If you are switching" echo "to a channel, you may try zirc_switch instead as it will expand to" echo "the best match without you having to deal with the escaping." return 1 fi ZIRC_LAST="$ZIRC_CURRENT" ZIRC_CURRENT="${query%% *}" echo "Switched to $ZIRC_CURRENT" } # Switch to the last focused window or wherever there was a message last function zirc_last { local a [[ -z "$ZIRC_LAST" ]] && return 0 a="$ZIRC_CURRENT" ZIRC_CURRENT="${ZIRC_LAST}" ZIRC_LAST="$a" echo "Switched to $ZIRC_CURRENT" } # Quit (with optional quit message) function zirc_quit { local msg="${(j: :)@}" zirc_connected || { echo "Not connected" ; return 1 } [[ -z "$msg" ]] && msg="ZIRC $ZIRC_VERSION - 100% zsh, woot." _zirc_write "QUIT :$msg" } # Print out current focus. Could be used to hook into prompts function zirc_focus { zirc_connected || { echo "Not connected" ; return 1 } echo "$ZIRC_CURRENT" } # Print out zirc_* functions function zirc_help { local commands commands=( "${(k)functions[@]}" ) commands=( ${(M)commands:#zirc_*} ) commands=( ${(o)commands} ) commands=( " "${^commands} ) echo "ZIRC Commands:" echo "${(F)commands}" return 0 } # Change nickname to argument function zirc_nick { local nick="$1" zirc_connected || { echo "Not connected" ; return 1 } if [[ -z "$nick" ]]; then echo "Usage: $0 <nick>" echo "Change nickname to <nick>." return 1 fi _zirc_write "NICK ${nick%% *}" } # Message the current focus function zirc_msg { local msg="${(j: :)@}" zirc_connected || { echo "Not connected" ; return 1 } if [[ -z "$msg" ]]; then echo "Usage: $0 <message>" echo "Will message the current focus <message>." echo "Use zirc_query/zirc_switch to change focus. (Current: '${ZIRC_CURRENT}')" return 1 fi if [[ -z "$ZIRC_CURRENT" ]]; then echo "No current focus. Use zirc_query/zirc_switch to change focus." return 1 fi echo "<$ZIRC_NICK:$ZIRC_CURRENT> ${msg}" _zirc_write "PRIVMSG ${ZIRC_CURRENT} :${msg}" } # Message someone (temporarily changing focus then calling zirc_msg) function zirc_pmsg { local who="$1" shift local msg="${(j: :)@}" local temp_current temp_result zirc_connected || { echo "Not connected" ; return 1 } if [[ -z "$msg" ]] || [[ -z "$who" ]]; then echo "Usage: $0 <person> <message>" echo "Will message the <person> the message <message>." echo "Also see zirc_msg." return 1 fi temp_current="$ZIRC_CURRENT" ZIRC_CURRENT="$who" zirc_msg "$msg" temp_result="$?" ZIRC_CURRENT="$temp_current" return "$temp_result" } # Join a channel function zirc_join { local chan="$1" zirc_connected || { echo "Not connected" ; return 1 } if [[ -z "$chan" ]]; then echo "Usage: $0 <channel>" echo "Will join the channel <channel>. If <channel> starts with a letter" echo "or a number, it will be prepended with a '#'" return 1 fi [[ "$chan" == [a-zA-Z0-9]* ]] && chan="#${chan}" _zirc_write "JOIN ${chan%% *}" } # Leave a channel (with optional part message) function zirc_part { local chan="$1" unchan="$1" shift local msg="${(j: :)@}" zirc_connected || { echo "Not connected" ; return 1 } if [[ -z "$chan" ]]; then echo "Usage: $0 <channel> [<msg>]" echo "Will leave the channel <channel> with optional part message <msg>." echo "This routine will use the same matching method as zirc_switch so" echo "you don't have to type the '#' or any other tricky characters" #'" ft=zsh sucks return 1 fi chan="$(_zirc_channel_match "$chan")" if [[ -z "$chan" ]]; then echo "Could not find anything for '$unchan'" echo "Current channels: ${(j:,:)ZIRC_CHANNELS}" return 1 fi _zirc_write "PART ${chan%% *} :${msg}" } # Change the topic in current focus function zirc_topic { local topic="${(j: :)@}" zirc_connected || { echo "Not connected" ; return 1 } if [[ -z "$topic" ]]; then echo "Usage: $0 <topic>" echo "Change the topic in the current channel. Use zirc_switch" echo "to change the channel (Current: '$ZIRC_CURRENT')." return 1 fi _zirc_write "TOPIC ${ZIRC_CURRENT} :${topic}" } # Send a CTCP action to the current focus function zirc_action { local msg="${(j: :)@}" zirc_connected || { echo "Not connected" ; return 1 } if [[ -z "$msg" ]]; then echo "Usage: $0 <message>" echo "Send 3rd person action <message>." echo "Sends to the current focus (Current: '$ZIRC_CURRENT')." return 1 fi echo "* $ZIRC_NICK:$ZIRC_CURRENT ${msg}" _zirc_write "$(printf "PRIVMSG $ZIRC_CURRENT :\001ACTION ${msg}\001")" } # Print out current topic function zirc_checktopic { zirc_connected || { echo "Not connected" ; return 1 } _zirc_write "TOPIC ${ZIRC_CURRENT}" } # Returns success if currently connected function zirc_connected { ! [[ -z "$ZIRC_FD" ]] } # Connect to a server function zirc_connect { if ! [[ -z "$ZIRC_FD" ]]; then zirc_disconnect zirc_connect return fi if [[ -z "$1" ]]; then echo -e "Usage: $0 <server>" _zirc_param_help return 1 fi ZIRC_SERVER="$1" ZIRC_LOWERCASER="_zirc_lowercase_rfc1459" ZIRC_CURRENT="" ZIRC_CHANNELS=() _zirc_param_populate ztcp "$ZIRC_SERVER" "$ZIRC_PORT" || return 1 ZIRC_FD="$REPLY" zle -F "$ZIRC_FD" _zirc_handle_incoming_data _zirc_send_connect_lines echo "Connected to $ZIRC_SERVER on fd #$ZIRC_FD" return 0 } # Disconnect from a server function zirc_disconnect { if [[ -z "$ZIRC_FD" ]]; then return 0 fi echo "Disconnecting from $ZIRC_SERVER..." zle -F "$ZIRC_FD" ztcp -c "$ZIRC_FD" eval "$ZIRC_UNSETSTRING" return 0 } # Setup aliases function zirc_aliases { echo "Setting up some convenience aliases" alias me='zirc_action' alias nick='zirc_nick' alias msg='zirc_msg' alias pmsg='zirc_pmsg' alias quit='zirc_quit' alias ctopic='zirc_topic' alias topic='zirc_checktopic' alias part='zirc_part' alias last='zirc_last' alias join='zirc_join' alias sw='zirc_switch' alias query='zirc_query' alias connect='zirc_connect' alias help='zirc_help' } # }}}3