Advertisement
Braber01

Modifed Zirc

Sep 2nd, 2011
395
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 29.92 KB | None | 0 0
  1. #!/bin/zsh
  2. # vim:noet fdm=marker sw=4 ts=4
  3.  
  4. ZIRC_VERSION="0.2"
  5.  
  6. # ZIRC - A 100% ZSH IRC client
  7. #
  8. # Copyright (C) 2006 by Andrew Ruder <andy@aeruder.net>
  9. # Copyright (C) 2006 by Gergely Nagy <gergely-nagy@gmail.com>
  10. #
  11. # This IRC client is pretty ridiculous, I made it entirely as a joke, but it
  12. # actually works fairly decently for as little work has been put into it.
  13. # And of course, afaik, there are *no* external commands used in the making
  14. # of this program.  No grep, no sed, nothing... pretty cool :)
  15. #
  16. # Guide to using it:
  17. #   Step 1) Source this file.
  18. #           . ./zirc or whatever
  19. #           You can even put this into your .zshrc, it won't hurt anything
  20. #           besides the creation of several _zirc_*/zirc_* functions.
  21. #   Step 2) (Optional) Run zirc_aliases
  22. #           This sets up several aliases to make it easier to use.  Basically
  23. #           it strips the zirc_ front end off of everything.
  24. #   Step 3) (Optional) Run zirc_unquote to turn off autoquoting and
  25. #           zirc_quote to turn it on (default on).  This will quote shell
  26. #           characters as you type on the ZIRC commands.
  27. #   Step 4) Run zirc_connect
  28. #           It'll explain the syntax and the fairly standardized environment
  29. #           variables controlling its behavior.
  30. #   Step 5) Use zirc_msg to message, zirc_pmsg to private message.
  31. #           zirc_switch can change to another channel. (zirc_switch somechan)
  32. #           or
  33. #           zirc_query can change to anything
  34. #   Step 6) zirc_last is very handy as it switches to the channel/user that
  35. #           last said something to you.
  36. #
  37. #   Prompt integration: a few environment variables can help you on your way.
  38. #     $ZIRC_CURRENT = current focus
  39. #     $ZIRC_NICK    = current nickname
  40. #     $ZIRC_SERVER  = connected server
  41. #
  42. # This program is free software; you can redistribute it and/or modify it under
  43. # the terms of the GNU General Public License as published by the Free Software
  44. # Foundation; either version 2 of the License, or (at your option) any later
  45. # version.
  46.  
  47. [[ -z "$modules[zsh/net/tcp]" ]] && zmodload zsh/net/tcp
  48. [[ -z "$modules[zsh/zselect]" ]] && zmodload zsh/zselect
  49.  
  50. ZIRC_PARAMS=( ZIRC_NICK ZIRC_USER ZIRC_NAME ZIRC_PORT ZIRC_HOST )
  51.  
  52. if ! [[ -z "$ZIRC_FD" ]] && ! [[ -z "$functions[zirc_disconnect]" ]] ; then
  53.     zirc_disconnect
  54. fi
  55.  
  56. ZIRC_VARS=( ZIRC_LAST ZIRC_CHANNELS ZIRC_CURRENT ZIRC_LOWERCASER ZIRC_FD ZIRC_SERVER "${ZIRC_PARAMS[@]}" )
  57. ZIRC_UNSETSTRING="unset ${ZIRC_VARS[*]}"
  58. eval "$ZIRC_UNSETSTRING"
  59.  
  60. typeset -g "$ZIRC_VARS[@]"
  61.  
  62. typeset -A ZIRC_PARAM_DEFS
  63. ZIRC_PARAM_DEFS[ZIRC_NICK]="Nickname:\$IRCNICK:$USERNAME"
  64. ZIRC_PARAM_DEFS[ZIRC_USER]="Username:\$IRCUSER:$USERNAME"
  65. ZIRC_PARAM_DEFS[ZIRC_PORT]="Port:\$IRCPORT:8001"
  66. ZIRC_PARAM_DEFS[ZIRC_NAME]="Real name:\$IRCNAME:Ben Raber"
  67. ZIRC_PARAM_DEFS[ZIRC_HOST]="Host name:\$IRCHOST:localhost"
  68.  
  69.  
  70. # alias definitions {{{
  71. typeset -A ZIRC_ALIAS_DEFS
  72. ZIRC_ALIAS_DEFS[me]='zirc_action';
  73. ZIRC_ALIAS_DEFS[nick]='zirc_nick';
  74. ZIRC_ALIAS_DEFS[msg]='zirc_msg';
  75. ZIRC_ALIAS_DEFS[pmsg]='zirc_pmsg';
  76. ZIRC_ALIAS_DEFS[quit]='zirc_quit';
  77. ZIRC_ALIAS_DEFS[ctopic]='zirc_topic';
  78. ZIRC_ALIAS_DEFS[topic]='zirc_checktopic';
  79. ZIRC_ALIAS_DEFS[part]='zirc_part';
  80. ZIRC_ALIAS_DEFS[last]='zirc_last';
  81. ZIRC_ALIAS_DEFS[join]='zirc_join';
  82. ZIRC_ALIAS_DEFS[sw]='zirc_switch';
  83. ZIRC_ALIAS_DEFS[query]='zirc_query';
  84. ZIRC_ALIAS_DEFS[connect]='zirc_connect';
  85. ZIRC_ALIAS_DEFS[help]='zirc_help';
  86. ZIRC_ALIAS_DEFS[mode]='zirc_mode';
  87. ZIRC_ALIAS_DEFS[op]='zirc_op';
  88. ZIRC_ALIAS_DEFS[deop]='zirc_deop';
  89. ZIRC_ALIAS_DEFS[voice]='zirc_voice';
  90. ZIRC_ALIAS_DEFS[devoice]='zirc_devoice';
  91. ZIRC_ALIAS_DEFS[names]='zirc_names';
  92. ZIRC_ALIAS_DEFS[whois]='zirc_whois';
  93. ZIRC_ALIAS_DEFS[who]='zirc_who';
  94. ZIRC_ALIAS_DEFS[kick]='zirc_kick';
  95. ZIRC_ALIAS_DEFS[away]='zirc_away';
  96. # }}}
  97.  
  98.  
  99. # zirc_connect parameter handling {{{
  100.  
  101. # Print out help for the environment variables using the
  102. # ZIRC_PARAM_DEFS and ZIRC_PARAMS variables as a reference
  103. function _zirc_param_help {
  104.     local a b
  105.     echo -e "Environment variables:"
  106.     for a in "${ZIRC_PARAMS[@]}"; do
  107.         b=( ${(s/:/)${ZIRC_PARAM_DEFS[$a]}} )
  108.         echo -e "\t${b[2]} - ${b[1]} (default ${b[3]})"
  109.     done
  110. }
  111.  
  112. # Fills in the variables in ZIRC_PARAMS using the correct
  113. # fallback values specified in ZIRC_PARAM_DEFS
  114. function _zirc_param_populate {
  115.     local a b
  116.     for a in "$ZIRC_PARAMS[@]"; do
  117.         b=( ${(s/:/)${ZIRC_PARAM_DEFS[$a]}} )
  118.         if [ -z "${(e)b[2]}" ]; then
  119.             eval "${a}=\"\${b[3]}\""
  120.         else
  121.             eval "${a}=\"\${(e)b[2]}\""
  122.         fi
  123.     done
  124. }
  125.  
  126. # }}}
  127.  
  128.  
  129. # Lowercasing/string comparison code {{{
  130.  
  131. # Lowercasing according to rfc1459 strictly
  132. function _zirc_lowercase_strict_rfc1459 {
  133.     local msg="${(L)1}"
  134.     msg=${msg//\[/\{}
  135.     msg=${msg//]/\}}
  136.     msg=${msg//\\/\|}
  137.     echo "${msg}"
  138. }
  139.  
  140. # Lowercasing according to rfc1459
  141. function _zirc_lowercase_rfc1459 {
  142.     local msg="$(_zirc_lowercase_strict_rfc1459 "$1")"
  143.     msg=${msg//\~/^}
  144.     echo "${msg}"
  145. }
  146.  
  147. # Lowercasing using standard ascii rules
  148. function _zirc_lowercase_ascii {
  149.     echo "${(L)1}"
  150. }
  151.  
  152. # Lowercasing according to the current server's specs
  153. function _zirc_lowercase {
  154.     "$ZIRC_LOWERCASER" "$1"
  155. }
  156.  
  157. # Case-insensitive compare according to the case-mapping= spec for the server
  158. function _zirc_compare {
  159.     [[ "$("$ZIRC_LOWERCASER" "$1")" == "$("$ZIRC_LOWERCASER" "$2")" ]]
  160. }
  161.  
  162. # Determine if a prefix/word is referring to you
  163. function _zirc_isme {
  164.     _zirc_compare "$ZIRC_NICK" "$(_zirc_prefix_nick "$1")"
  165. }
  166.  
  167. # }}}
  168.  
  169.  
  170. # data from server parsing {{{
  171.  
  172. # Parse a line like
  173. #   :blah!host blah3 blah4 :Message with lots of words
  174. # and output
  175. #   blah!host
  176. #   blah3
  177. #   blah4
  178. #   Message with lots of words
  179. function _zirc_parse_server_line {
  180.     local readval args
  181.     args=()
  182.     readval=( "${(f)$(_zirc_parse_server_prefix "$1")}" )
  183.     args+=( "${readval[1]}" )
  184.     while ! [[ -z "${readval[2]}" ]] ; do
  185.         readval=( "${(f)$(_zirc_parse_server_word "${readval[2]}")}" ) #" Bug in vim highlighting
  186.         if ! [[ -z "${readval[1]}" ]]; then
  187.             args+=( "${readval[1]}" )
  188.         fi
  189.     done
  190.     echo "${(F)args}"
  191. }
  192.  
  193. # Parse a line like
  194. #   :blah!host blah3 blah4
  195. # and print out
  196. #   blah!host
  197. #   blah3 blah4
  198. function _zirc_parse_server_prefix {
  199.     setopt localoptions extendedglob
  200.     local line prefix
  201.     line="${1## #}"
  202.     if [[ "${line[1]}" != ":" ]]; then
  203.         prefix=""
  204.     else
  205.         prefix="${line%% *}"
  206.         if [[ "$prefix" == "$line" ]]; then
  207.             line=""
  208.         else
  209.             line="${line#* }"
  210.         fi
  211.     fi
  212.     echo "${prefix#:}"
  213.     echo "$line"
  214. }
  215.  
  216. # Parse out a single word from a line, so
  217. #   blah3 blah4 :Message
  218. # prints out:
  219. #   blah3
  220. #   blah4 :Message
  221. # again:
  222. #   blah4
  223. #   :Message
  224. # again
  225. #   Message
  226. #   <empty line>
  227. function _zirc_parse_server_word {
  228.     setopt localoptions extendedglob
  229.     local line word
  230.     line="${1## #}"
  231.     if [[ "${line[1]}" != ":" ]]; then
  232.         word="${line%% *}"
  233.         if [[ "$word" == "$line" ]]; then
  234.             line=""
  235.         else
  236.             line="${line#* }"
  237.         fi
  238.     else
  239.         word="${line#:}"
  240.         line=""
  241.     fi
  242.     echo "$word"
  243.     echo "$line"
  244. }
  245.  
  246. # Split a prefix and get nick (nick!host)
  247. #   Input: nick!host or nick
  248. #   Output:
  249. #     <empty-line>
  250. function _zirc_prefix_nick {
  251.     local a
  252.     a=( "${(f)$(_zirc_split_prefix "$1")}" )
  253.     echo "${a[1]}"
  254. }
  255.  
  256. # Split a prefix and get host (nick!host)
  257. #  Input: nick!host
  258. #  Output:
  259. #    host
  260. #  Input: nick
  261. #  Output:
  262. #    <empty-line>
  263. function _zirc_prefix_host {
  264.     local a
  265.     a=( "${(f)$(_zirc_split_prefix "$1")}" )
  266.     echo "${a[2]}"
  267. }
  268.  
  269. # Split a prefix
  270. # Input: nick!host
  271. # Output:
  272. #   nick
  273. #   host
  274. # Input: nick
  275. # Output:
  276. #   nick
  277. #   <empty-line>
  278. function _zirc_split_prefix {
  279.     local a
  280.     a=( ${(s:!:)1} )
  281.     [[ ${#a} == "1" ]] && a+=( '' )
  282.     echo "${(F)a}"
  283. }
  284.  
  285. # }}}
  286.  
  287.  
  288. # CTCP handling {{{
  289.  
  290. # Print out the generic ctcp message
  291. # Args: prefix command where ctcp msg
  292. function _zirc_generic_ctcp {
  293.     local pref="$1" comm="$2"
  294.     local where="$3" ctcp="$4"
  295.     local msg="$5"
  296.     local who="$(_zirc_prefix_nick "$pref")"
  297.  
  298.     _zirc_echo -n "<CTCP> <$who"
  299.     _zirc_isme "$where" || _zirc_echo -n ":$where"
  300.     _zirc_echo "> $ctcp $msg"
  301. }
  302.  
  303. # Write out a CTCP request
  304. # Args: prefix command where ctcp msg
  305. function _zirc_ctcp_request_write {
  306.     local msg
  307.     if ! [[ -z "$2" ]] && ! [[ -z "$3" ]]; then
  308.         msg="$2 $3"
  309.     else
  310.         msg="$2"
  311.     fi
  312.  
  313.     _zirc_write "`printf "PRIVMSG %s :\001%s\001" "$1" "$msg"`"
  314. }
  315.  
  316. # Write out a CTCP reply
  317. # Args: where ctcp message
  318. function _zirc_ctcp_reply_write {
  319.     local msg
  320.     if ! [[ -z "$2" ]] && ! [[ -z "$3" ]]; then
  321.         msg="$2 $3"
  322.     else
  323.         msg="$2"
  324.     fi
  325.  
  326.     _zirc_write "`printf "NOTICE %s :\001%s\001" "$1" "$msg"`"
  327. }
  328.  
  329. # Handle a VERSION request
  330. function _zirc_ctcp_request_VERSION {
  331.     _zirc_generic_ctcp "$@"
  332.     local pref="$1"
  333.     local who="$(_zirc_prefix_nick "$pref")"
  334.  
  335.     _zirc_ctcp_reply_write "$who" "VERSION" "ZIRC $ZIRC_VERSION - 100% zsh!!"
  336. }
  337.  
  338. # Handle a PING request
  339. function _zirc_ctcp_request_PING {
  340.     local pref="$1" msg="$5"
  341.     local who="$(_zirc_prefix_nick "$pref")"
  342.     _zirc_echo "Received a CTCP PING from $who"
  343.  
  344.     _zirc_ctcp_reply_write "$who" "PING" "$5"
  345. }
  346.  
  347. # Handle an ACTION
  348. function _zirc_ctcp_reply_ACTION {
  349.     local pref="$1" where="$3" msg="$5"
  350.     local who="$(_zirc_prefix_nick "$pref")"
  351.  
  352.     if ( _zirc_isme "$where" ); then
  353.         _zirc_compare "$ZIRC_CURRENT" "$who" || ZIRC_LAST="$who"
  354.         _zirc_echo "*** * $who $msg"
  355.     else
  356.         _zirc_echo -n "* $who"
  357.         _zirc_compare "$ZIRC_CURRENT" "$where" || {
  358.             ZIRC_LAST="$where"
  359.             _zirc_echo -n ":$where"
  360.         }
  361.         _zirc_echo " $msg"
  362.     fi
  363. }
  364.  
  365. # Handle ACTION requests just like replies
  366. function _zirc_ctcp_request_ACTION {
  367.     _zirc_ctcp_reply_ACTION "$@"
  368. }
  369.  
  370. # Handle all other CTCP requests
  371. function _zirc_ctcp_request_other {
  372.     _zirc_generic_ctcp "$@"
  373. }
  374.  
  375. # Handle all other CTCP replies
  376. function _zirc_ctcp_reply_other {
  377.     _zirc_generic_ctcp "$@"
  378. }
  379.  
  380. # Parse the CTCP stuff and call the appropriate CTCP function above
  381. # args: pref command where ctcp+message
  382. function _zirc_command_CTCP {
  383.     local pref="$1" comm="$2"
  384.     local who="$(_zirc_prefix_nick "$pref")"
  385.     shift 2
  386.     local where="$1" msg="$2"
  387.     local ctcp func args ctype
  388.    
  389.     if [[ "$((#msg))" == "1" ]]; then
  390.         msg="${msg#?}"
  391.     fi
  392.  
  393.     if [[ "$((##${msg[-1]}))" == "1" ]]; then
  394.         msg="${msg%?}"
  395.     fi
  396.    
  397.     ctcp="${(U)msg%% *}"
  398.     msg="${msg#* }"
  399.     if [[ "$msg" == "$ctcp" ]]; then
  400.         msg=""
  401.     fi
  402.     ctype="request"
  403.     [[ "$comm" == "NOTICE" ]] && ctype="reply"
  404.  
  405.     func="_zirc_ctcp_${ctype}_${ctcp}"
  406.  
  407.     if [[ -z "${functions[${func}]}" ]]; then
  408.         func="_zirc_ctcp_${ctype}_other"
  409.     fi
  410.  
  411.     args=( "$pref" "$comm" "$where" "$ctcp" "$msg" )
  412.  
  413.     "${func}" "$args[@]"
  414. }
  415.  
  416. # }}}
  417.  
  418.  
  419. # Server command handling {{{
  420.  
  421. # An echo that should be used by anything automatically
  422. # called (commands).  It invalidates the current prompt line first.
  423. function _zirc_echo {
  424.     zle -I
  425.     echo "$(tput setaf 1;tput bold) $@ $(tput sgr0)"
  426. }
  427.  
  428. # Handle private messages
  429. function _zirc_command_PRIVMSG {
  430.     local pref="$1" comm="$2"
  431.     shift 2
  432.     local who="$(_zirc_prefix_nick "$pref")"
  433.     local where="$1" msg="$2"
  434.     if [[ "$((#msg))" == "1" ]]; then
  435.         _zirc_command_CTCP "$pref" "$comm" "$where" "$msg"
  436.         return 0
  437.     fi
  438.  
  439.     if ( _zirc_isme "$where" ); then
  440.         _zirc_compare "$ZIRC_CURRENT" "$who" || ZIRC_LAST="$who"
  441.         _zirc_echo "*** <$who> $msg"
  442.     else
  443.         _zirc_echo -n "<$who"
  444.         _zirc_compare "$where" "$ZIRC_CURRENT" || {
  445.             _zirc_echo -n ":$where"
  446.             ZIRC_LAST="$where"
  447.         }
  448.         _zirc_echo "> $msg"
  449.     fi
  450. }
  451.  
  452. # Handle nickname changes
  453. function _zirc_command_NICK {
  454.     local pref="$1" newnick="$3"
  455.     local who="$(_zirc_prefix_nick "$pref")"
  456.  
  457.     if [[ "$who" == "$ZIRC_CURRENT" ]]; then
  458.         ZIRC_CURRENT="${newnick}"
  459.     fi
  460.  
  461.     _zirc_isme "$pref" && ZIRC_NICK="$newnick"
  462.  
  463.     _zirc_echo "$who is now known as $newnick"
  464. }
  465.  
  466. # Handle channel joins
  467. function _zirc_command_JOIN {
  468.     local pref="$1" comm="$2"
  469.     shift 2
  470.     local who="$(_zirc_prefix_nick "$pref")"
  471.     local at="$(_zirc_prefix_host "$pref")"
  472.     local where="$1"
  473.  
  474.     _zirc_echo "$who ($at) has joined $where"
  475.     _zirc_isme "$pref" && {
  476.         ZIRC_LAST="$ZIRC_CURRENT"
  477.         ZIRC_CURRENT="$where"
  478.         ZIRC_CHANNELS+=("$where")
  479.     }
  480. }
  481.  
  482. # Handle channel parts
  483. function _zirc_command_PART {
  484.     local pref="$1" comm="$2" where="$3" msg="$4"
  485.     local who="$(_zirc_prefix_nick "$pref")"
  486.  
  487.     _zirc_echo "$who has left $where ($msg)"
  488.     _zirc_isme "$pref" && {
  489.         [[ "$ZIRC_CURRENT" == "$where" ]] && ZIRC_CURRENT="$ZIRC_LAST"
  490.         ZIRC_CHANNELS[(r)$where]=()
  491.     }
  492. }
  493.  
  494. # Handle people quitting
  495. function _zirc_command_QUIT {
  496.     local pref="$1" comm="$2" msg="$3"
  497.     local who="$(_zirc_prefix_nick "$pref")"
  498.  
  499.     _zirc_echo "$who has quit IRC ($msg)"
  500. }
  501.  
  502. # Handle topic changes
  503. function _zirc_command_TOPIC {
  504.     local pref="$1" comm="$2" where="$3" msg="$4"
  505.     local who="$(_zirc_prefix_nick "$pref")"
  506.  
  507.     _zirc_echo "$who has changed the topic in $where to '$msg'"
  508. }
  509.  
  510. # Handle mode changes
  511. function _zirc_command_MODE {
  512.     local pref="$1" comm="$2" object="$3" mode="$4"
  513.     local who="$(_zirc_prefix_nick "$pref")"
  514.     local rest
  515.     rest=( "${@[4,-1]}" )
  516.     rest=( " "${^rest} )
  517.     rest=${(j::)rest}
  518.  
  519.     _zirc_echo "$who sets mode $mode ${object}${rest}"
  520. }
  521.  
  522. # Handle invites
  523. function _zirc_command_INVITE {
  524.     local pref="$1" comm="$2" where="$4"
  525.     local who="$(_zirc_prefix_nick "$pref")"
  526.  
  527.     _zirc_echo "$who has invited you to $where"
  528. }
  529.  
  530. # Handle kicks
  531. function _zirc_command_KICK {
  532.     local pref="$1" comm="$2" where="$3" user="$4" msg="$5"
  533.     local who="$(_zirc_prefix_nick "$pref")"
  534.  
  535.     _zirc_echo "$user was kicked from $where by $who ($msg)"
  536. }
  537.  
  538. # Handle pong messages (shouldn't get these generally, but just in case)
  539. function _zirc_command_PONG {
  540. }
  541.  
  542. # Handle notices, although we just forward this onto the privmsg code
  543. function _zirc_command_NOTICE {
  544.     _zirc_command_PRIVMSG "$@"
  545.     return
  546. }
  547.  
  548. # Handle wallops
  549. function _zirc_command_WALLOPS {
  550.     local pref="$1" comm="$2" msg="$3"
  551.     local who="$(_zirc_prefix_nick "$pref")"
  552.     _zirc_echo "Wallops from $who: $msg"
  553. }
  554.  
  555. # Handle IRC Errors
  556. function _zirc_command_ERROR {
  557.     local pref="$1" comm="$2"
  558.     shift 2
  559.     _zirc_echo "ERROR: ${(j: :)@}"
  560. }
  561.  
  562. # Handle server pings
  563. function _zirc_command_PING {
  564.     local pref="$1" comm="$2"
  565.     shift 2
  566.     _zirc_write "PONG :$1"
  567. }
  568.  
  569. # RPL_WELCOME handler... this will (among other things)
  570. # inform us of our true nickname
  571. function _zirc_command_numeric_001 {
  572.     ZIRC_NICK="$3"
  573. }
  574.  
  575. # RPL_ISUPPORT this tells us how to handle casemapping
  576. function _zirc_command_numeric_005 {
  577.     case "$4" in
  578.         *casemapping=rfc1459*)
  579.             ZIRC_LOWERCASER="_zirc_lowercase_rfc1459"
  580.             ;;
  581.         *casemapping=strict-rfc1459*)
  582.             ZIRC_LOWERCASER="_zirc_lowercase_strict_rfc1459"
  583.             ;;
  584.         *casemapping=ascii*)
  585.             ZIRC_LOWERCASER="_zirc_lowercase_ascii"
  586.             ;;
  587.     esac
  588. }
  589.  
  590. # Handle numeric commands
  591. function _zirc_command_numeric {
  592.     local pref="$1" comm="$2"
  593.     _zirc_echo "-- ${(j: :)@[4,-1]}"
  594.     if ! [[ -z "$functions[_zirc_command_numeric_${comm}]" ]]; then
  595.         _zirc_command_numeric_"$comm" "$@"
  596.     fi
  597. }
  598.  
  599. # catchall for unhandled commands
  600. function _zirc_command_other {
  601.     setopt localoptions extendedglob
  602.     local pref="$1" comm="$2"
  603.     shift 2
  604.     if [[ "$comm" == [0-9]## ]]; then
  605.         _zirc_command_numeric "$pref" "$comm" "$@"
  606.         return 0
  607.     fi
  608. }
  609.  
  610. # }}}
  611.  
  612.  
  613. # ZLE hooks {{{
  614.  
  615. # Parse a single line of incoming data
  616. function _zirc_handle_incoming_data_piece {
  617.     local line comm func output
  618.     line="$1"
  619.  
  620.     line=( "${(f)$(_zirc_parse_server_line "$line")}" )
  621.  
  622.     comm="${(U)line[2]}"
  623.     func="_zirc_command_${comm}"
  624.  
  625.     if [[ -z "${functions[${func}]}" ]]; then
  626.         func="_zirc_command_other"
  627.     fi
  628.  
  629.     "$func" "$line[@]"
  630. }
  631.  
  632. # The ZLE informs this when there is data.  Grab the data, and then
  633. # grab any additional data available (using zselect) and passing all
  634. # of this back off to the _zirc_handle_incoming_data_piece function
  635. function _zirc_handle_incoming_data {
  636.     local fds line
  637.  
  638.     if [[ "$1" != "$ZIRC_FD" ]]; then
  639.         zle -I
  640.         echo "ZIRC: Handling some other file handle???"
  641.         return 1
  642.     fi
  643.  
  644.     while true; do
  645.         if ! read -r line <&$ZIRC_FD; then
  646.             zle -I
  647.             zirc_disconnect
  648.             return 1
  649.         fi
  650.         if [[ "$((##${line[-1]}))" == "13" ]]; then
  651.             line="${line%?}"
  652.         fi
  653.  
  654.         _zirc_handle_incoming_data_piece "$line"
  655.  
  656.         fds=()
  657.         zselect -r -t 0 -a fds $ZIRC_FD
  658.         if [[ "${#fds}" != "2" ]]; then
  659.             break
  660.         fi
  661.     done
  662. }
  663.  
  664. # }}}
  665.  
  666.  
  667. # User commands and utility functions used by them {{{
  668.  
  669. # Write out a message to the server.  It puts on the correct line ending
  670. # for the IRC protocol too
  671. function _zirc_write {
  672.     local a
  673.  
  674.     if [[ -z "$ZIRC_FD" ]]; then
  675.         return 1
  676.     fi
  677.  
  678.     if [[ -z "$1" ]]; then
  679.         return 0
  680.     fi
  681.  
  682.     a="$@"
  683.     printf "$(tput setaf 1;tput bold) %s\r\n" "$a $(tput sgr0)" >&$ZIRC_FD
  684. }
  685.  
  686. # Send the initial connection lines to the server
  687. function _zirc_send_connect_lines {
  688.     _zirc_write "NICK $ZIRC_NICK"
  689.     _zirc_write "USER $ZIRC_USER $ZIRC_HOST $ZIRC_SERVER :$ZIRC_NAME"
  690. }
  691.  
  692. # Input:
  693. #   channel name (or part of a channel name)
  694. # Output:
  695. #   shortest channel that matches *<input>
  696. function _zirc_channel_match {
  697.     local chan="$1"
  698.     local chans shortest a
  699.  
  700.     chan="*${chan}"
  701.     chans=( "${ZIRC_CHANNELS[@]}" )
  702.     chans=( ${(e):-\${(M)chans:#$chan}} )
  703.  
  704.     if [[ "${#chans}" == "0" ]]; then
  705.         echo ""
  706.         return 1
  707.     fi
  708.  
  709.     shortest=" "; shortest="${(l:1000:: :)shortest}"
  710.  
  711.     for a in "${chans[@]}"; do
  712.         (( ${#a} < ${#shortest} )) && shortest="${a}"
  713.     done
  714.    
  715.     echo "${shortest}"
  716.     return 0
  717. }
  718.  
  719. # Switch focus.  This uses _zirc_channel_match so the globbing will make it
  720. # easier to switch channels.
  721. #
  722. #   zirc_switch step
  723. #
  724. # would change to #gnustep if you were correctly connected to that channel
  725. function zirc_switch {
  726.     local chan="$1"
  727.     local chans shortest a
  728.     zirc_connected || { echo "$(tput setaf 1;tput bold) Not connected $(tput sgr0)" ; return 1 }
  729.     if [[ -z "$chan" ]]; then
  730.         echo "$(tput setaf 1;tput bold) Usage: $0 <channel>"
  731.         echo "Switches current channel focus (Current: '${ZIRC_CURRENT}')"
  732.         echo "This command is only used for channels, use zirc_query for a more"
  733.         echo "general solution. $(tput sgr0)"
  734.         return 1
  735.     fi
  736.  
  737.     chan="$(_zirc_channel_match "$chan")"
  738.  
  739.     if [[ -z "$chan" ]]; then
  740.         echo "$(tput setaf 1;tput bold) Could not find anything for '$1'"
  741.         echo "Current channels: ${(j:,:)ZIRC_CHANNELS} $(tput sgr0)"
  742.         return 1
  743.     fi
  744.  
  745.     ZIRC_LAST="$ZIRC_CURRENT"
  746.     ZIRC_CURRENT="${chan}"
  747.     echo "$(tput setaf 1;tput bold) Switched to $ZIRC_CURRENT $(tput sgr0)"
  748.     return 0
  749. }
  750.  
  751. # Sets channel modes
  752. function zirc_mode {
  753.     local modes="${(j: :)@}"
  754.  
  755.     if [[ -z "$modes" ]]; then
  756.         echo "$(tput setaf 1;tput bold) Usage: $0 <modes>"
  757.         echo "Set channel modes to <modes>."
  758.         echo "Sends to the current focus (Current: '$ZIRC_CURRENT'). $(tput sgr0)"
  759.         return 1
  760.     fi
  761.  
  762.     zirc_connected || { echo "$(tput setaf 1;tput bold) Not connected $(tput sgr0)" ; return 1 }
  763.     _zirc_write "MODE ${ZIRC_CURRENT} ${modes}"
  764. }
  765.  
  766. # Set a single mode for a list of users
  767. function _zirc_batch_mode {
  768.     local mode="$1"
  769.     shift
  770.     local users="${(j: :)@}"
  771.  
  772.     for user in $users; do
  773.         zirc_mode "$mode" "$user"
  774.     done
  775. }
  776.  
  777. # Give operator status to user(s)
  778. function zirc_op {
  779.     if [[ -z "$@" ]]; then
  780.         echo "$(tput setaf 1;tput bold) Usage: $0 <users>"
  781.         echo "Give operator status to <users>."
  782.         echo "Works on the current focus (Current: '$ZIRC_CURRENT') $(tput sgr0)."
  783.         return 1
  784.     fi
  785.  
  786.     zirc_connected || { echo "$(tput setaf 1;tput bold) Not connected $(tput sgr0)" ; return 1}
  787.  
  788.     _zirc_batch_mode "+o" $@
  789. }
  790.  
  791. # Revoke operator status from user(s)
  792. function zirc_deop {
  793.     if [[ -z "$@" ]]; then
  794.         echo "$(tput setaf 1;tput bold) Usage: $0 <users>"
  795.         echo "Revoke operator status from <users>."
  796.         echo "Works on the current focus (Current: '$ZIRC_CURRENT'). $(tput sgr0)"
  797.         return 1
  798.     fi
  799.  
  800.     zirc_connected || { echo  "$(tput setaf 1;tput bold) Not connected $(tput sgr0)" ; return 1}
  801.  
  802.     _zirc_batch_mode "-o" $@
  803. }
  804.  
  805. # Give a voice flag to user(s)
  806. function zirc_voice {
  807.     if [[ -z "$@" ]]; then
  808.         echo "$(tput setaf 1;tput bold) Usage: $0 <users>"
  809.         echo "Give a voice flag to <users>."
  810.         echo "Works on the current focus (Current: '$ZIRC_CURRENT'). $(tput sgr0)"
  811.         return 1
  812.     fi
  813.  
  814.     zirc_connected || { echo "$(tput setaf 1;tput bold) Not connected $(tput sgr0)" ; return 1}
  815.  
  816.     _zirc_batch_mode "+v" $@
  817. }
  818.  
  819. # Revoke the voice flag from user(s)
  820. function zirc_devoice {
  821.     if [[ -z "$@" ]]; then
  822.         echo "$(tput setaf 1;tput bold) Usage: $0 <users>"
  823.         echo "Revoke the voice flag from <users>."
  824.         echo "Works on the current focus (Current: '$ZIRC_CURRENT'). $(tput sgr0)"
  825.         return 1
  826.     fi
  827.  
  828.     zirc_connected || { echo "$(tput setaf 1;tput bold) Not connected $(tput sgr0)" ; return 1}
  829.  
  830.     _zirc_batch_mode "-v" $@
  831. }
  832.  
  833. # Query the names on a channel
  834. function zirc_names {
  835.     zirc_connected || { echo "$(tput setaf 1;tput bold) Not connected $(tput sgr0)" ; return 1}
  836.  
  837.     _zirc_write "NAMES $ZIRC_CURRENT"
  838. }
  839.  
  840. # Issue a WHOIS request
  841. function zirc_whois {
  842.     if [[ -z "$1" ]]; then
  843.         echo "$(tput setaf 1;tput bold) Usage: $0 <user>"
  844.         echo "Get detailed information about <user>. $(tput sgr0)"
  845.         return 1
  846.     fi
  847.  
  848.     zirc_connected || { echo "$(tput setaf 1;tput bold) Not connected $(tput sgr0)" ; return 1}
  849.  
  850.     _zirc_write "WHOIS $1"
  851. }
  852.  
  853. # Issue a WHO request
  854. function zirc_who {
  855.     local chan="${1:-${ZIRC_CURRENT}}"
  856.  
  857.     zirc_connected || { echo "$(tput setaf 1;tput bold) Not connected $(tput sgr0)" ; return 1}
  858.  
  859.     _zirc_write "WHO $chan"
  860. }
  861.  
  862. # Kick user from the current channel
  863. function zirc_kick {
  864.     if [[ -z "$@" ]]; then
  865.         echo "$(tput setaf 1;tput bold) Usage: $0 <user> [<reason>]"
  866.         echo "Kick <users> from the current channel, due to <reason>."
  867.         echo "Works on the current focus (Current: '$ZIRC_CURRENT'). $(tput sgr0)"
  868.         return 1
  869.     fi
  870.  
  871.     zirc_connected || { echo "$(tput setaf 1;tput bold) Not connected $(tput sgr0)" ; return 1}
  872.  
  873.     local user=$1
  874.     shift
  875.  
  876.     _zirc_write "KICK $ZIRC_CURRENT $user ${@:+:$@}"
  877. }
  878.  
  879. # Sets/unsets the automatic away message
  880. function zirc_away {
  881.     zirc_connected || { echo "$(tput setaf 1;tput bold) Not connected $(tput sgr0)" ; return 1}
  882.  
  883.     _zirc_write "AWAY ${@:+:$@}"
  884. }
  885.  
  886. # Just switch focus to the argument.  Don't check against anything else.
  887. function zirc_query {
  888.     local query="$1"
  889.     zirc_connected || { echo "$(tput setaf 1;tput bold) Not connected $(tput sgr0)" ; return 1 }
  890.     if [[ -z "$query" ]]; then
  891.         echo "$(tput setaf 1;tput bold) Usage: $0 <user/channel>"
  892.         echo "Switches current focus. (Current: '${ZIRC_CURRENT}')"
  893.         echo "No expansion will be done on the parameter.  If you are switching"
  894.         echo "to a channel, you may try zirc_switch instead as it will expand to"
  895.         echo "the best match without you having to deal with the escaping. $(tput sgr0)"
  896.         return 1
  897.     fi
  898.     ZIRC_LAST="$ZIRC_CURRENT"
  899.     ZIRC_CURRENT="${query%% *}"
  900.     echo "$(tput setaf 1;tput bold) Switched to $ZIRC_CURRENT $(tput sgr0)"
  901. }
  902.  
  903. # Switch to the last focused window or wherever there was a message last
  904. function zirc_last {
  905.     local a
  906.     [[ -z "$ZIRC_LAST" ]] && return 0
  907.     a="$ZIRC_CURRENT"
  908.     ZIRC_CURRENT="${ZIRC_LAST}"
  909.     ZIRC_LAST="$a"
  910.     echo "$(tput setaf 1;tput bold) Switched to $ZIRC_CURRENT $(tput sgr0)"
  911. }
  912.  
  913. # Quit (with optional quit message)
  914. function zirc_quit {
  915.     local msg="${(j: :)@}"
  916.     zirc_connected || { echo "$(tput setaf 1;tput bold) Not connected $(tput sgr0)" ; return 1 }
  917.  
  918.     [[ -z "$msg" ]] && msg="ZIRC $ZIRC_VERSION - 100% zsh, woot."
  919.  
  920.     _zirc_write "QUIT :$msg"
  921. }
  922.  
  923. # Print out current focus.  Could be used to hook into prompts
  924. function zirc_focus {
  925.     zirc_connected || { echo "$(tput setaf 1;tput bold) Not connected $(tput sgr0)" ; return 1 }
  926.     echo "$(tput setaf 1;tput bold) $ZIRC_CURRENT $(tput sgr0)"
  927. }
  928.  
  929. # Print out zirc_* functions and alias mappings
  930. function zirc_help {
  931.     local commands a
  932.     commands=( "${(k)functions[@]}" )
  933.     commands=( ${(M)commands:#zirc_*} )
  934.     commands=( ${(o)commands} )
  935.     commands=( "        "${^commands} )
  936.     echo "$(tput setaf 1;tput bold) ZIRC Commands:"
  937.     echo "${(F)commands}"
  938.  
  939.     echo
  940.     echo "Aliases (if using zirc_aliases):"
  941.     for a in "${(o@)${(k)ZIRC_ALIAS_DEFS[@]}}"; do
  942.         echo "${(l.12...)a} => ${ZIRC_ALIAS_DEFS[$a]} $(tput sgr0)"
  943.     done
  944.  
  945.     return 0
  946.  
  947. }
  948.  
  949. # Change nickname to argument
  950. function zirc_nick {
  951.     local nick="$1"
  952.     zirc_connected || { echo "$(tput setaf 1;tput bold) Not connected $(tput sgr0)" ; return 1 }
  953.  
  954.     if [[ -z "$nick" ]]; then
  955.         echo "$(tput setaf 1;tput bold) Usage: $0 <nick>"
  956.         echo "Change nickname to <nick>. $(tput sgr0)"
  957.         return 1
  958.     fi
  959.  
  960.     _zirc_write "NICK ${nick%% *}"
  961. }
  962.  
  963. # Message the current focus
  964. function zirc_msg {
  965.     local msg="${(j: :)@}"
  966.     zirc_connected || { echo "$(tput setaf 1;tput bold) Not connected $(tput sgr0)" ; return 1 }
  967.     if [[ -z "$msg" ]]; then
  968.         echo "$(tput setaf 1;tput bold) Usage: $0 <message>"
  969.         echo "Will message the current focus <message>."
  970.         echo "Use zirc_query/zirc_switch to change focus. (Current: '${ZIRC_CURRENT}') $(tput sgr0)"
  971.         return 1
  972.     fi
  973.     if [[ -z "$ZIRC_CURRENT" ]]; then
  974.         echo "$(tput setaf 1;tput bold) No current focus.  Use zirc_query/zirc_switch to change focus. $(tput sgr0)"
  975.         return 1
  976.     fi
  977.  
  978.     echo "$(tput setaf 1;tput bold) <$ZIRC_NICK:$ZIRC_CURRENT> ${msg} $(tput sgr0)"
  979.     _zirc_write "PRIVMSG ${ZIRC_CURRENT} :${msg}"
  980. }
  981.  
  982. # Message someone (temporarily changing focus then calling zirc_msg)
  983. function zirc_pmsg {
  984.     local who="$1"
  985.     shift
  986.     local msg="${(j: :)@}"
  987.     local temp_current temp_result
  988.  
  989.     zirc_connected || { echo "$(tput setaf 1;tput bold) Not connected $(tput sgr0)" ; return 1 }
  990.     if [[ -z "$msg" ]] || [[ -z "$who" ]]; then
  991.         echo "$(tput setaf 1;tput bold) Usage: $0 <person> <message>"
  992.         echo "Will message the <person> the message <message>."
  993.         echo "Also see zirc_msg. $(tput sgr0)"
  994.         return 1
  995.     fi
  996.     temp_current="$ZIRC_CURRENT"
  997.     ZIRC_CURRENT="$who"
  998.     zirc_msg "$msg"
  999.     temp_result="$?"
  1000.     ZIRC_CURRENT="$temp_current"
  1001.     return "$temp_result"
  1002. }
  1003.  
  1004. # Join a channel
  1005. function zirc_join {
  1006.     local chan="$1"
  1007.     zirc_connected || { echo "$(tput setaf 1;tput bold) Not connected $(tput sgr0)" ; return 1 }
  1008.     if [[ -z "$chan" ]]; then
  1009.         echo "$(tput setaf 1;tput bold) Usage: $0 <channel>"
  1010.         echo "Will join the channel <channel>.  If <channel> starts with a letter"
  1011.         echo "or a number, it will be prepended with a '#' $(tput sgr0)"
  1012.         return 1
  1013.     fi
  1014.     [[ "$chan" == [a-zA-Z0-9]* ]] && chan="#${chan}"
  1015.  
  1016.     _zirc_write "JOIN ${chan%% *}"
  1017. }
  1018.  
  1019. # Leave a channel (with optional part message)
  1020. function zirc_part {
  1021.     local chan="$1" unchan="$1"
  1022.     shift
  1023.     local msg="${(j: :)@}"
  1024.     zirc_connected || { echo "$(tput setaf 1;tput bold) Not connected $(tput sgr0)" ; return 1 }
  1025.     if [[ -z "$chan" ]]; then
  1026.         echo "$(tput setaf 1;tput bold) Usage: $0 <channel> [<msg>]"
  1027.         echo "Will leave the channel <channel> with optional part message <msg>."
  1028.         echo "This routine will use the same matching method as zirc_switch so"
  1029.         echo "you don't have to type the '#' or any other tricky characters $(tput sgr0)" #'" ft=zsh sucks
  1030.         return 1
  1031.     fi
  1032.     chan="$(_zirc_channel_match "$chan")"
  1033.  
  1034.     if [[ -z "$chan" ]]; then
  1035.         echo "$(tput setaf 1;tput bold) Could not find anything for '$unchan'"
  1036.         echo "Current channels: ${(j:,:)ZIRC_CHANNELS} $(tput sgr0)"
  1037.         return 1
  1038.     fi
  1039.  
  1040.     _zirc_write "PART ${chan%% *} :${msg}"
  1041. }
  1042.  
  1043. # Change the topic in current focus
  1044. function zirc_topic {
  1045.     local topic="${(j: :)@}"
  1046.     zirc_connected || { echo "$(tput setaf 1;tput bold) Not connected $(tput sgr0)" ; return 1 }
  1047.     if [[ -z "$topic" ]]; then
  1048.         echo "$(tput setaf 1;tput bold) Usage: $0 <topic>"
  1049.         echo "Change the topic in the current channel.  Use zirc_switch"
  1050.         echo "to change the channel (Current: '$ZIRC_CURRENT'). $(tput sgr0)"
  1051.         return 1
  1052.     fi
  1053.  
  1054.     _zirc_write "TOPIC ${ZIRC_CURRENT} :${topic}"
  1055. }
  1056.  
  1057. # Send a CTCP action to the current focus
  1058. function zirc_action {
  1059.     local msg="${(j: :)@}"
  1060.     zirc_connected || { echo "$(tput setaf 1;tput bold) Not connected $(tput sgr0)" ; return 1 }
  1061.     if [[ -z "$msg" ]]; then
  1062.         echo "$(tput setaf 1;tput bold) Usage: $0 <message>"
  1063.         echo "Send 3rd person action <message>."
  1064.         echo "Sends to the current focus (Current: '$ZIRC_CURRENT'). $(tput sgr0)"
  1065.         return 1
  1066.     fi
  1067.  
  1068.     echo "* $ZIRC_NICK:$ZIRC_CURRENT ${msg}"
  1069.     _zirc_write "$(printf "PRIVMSG $ZIRC_CURRENT :\001ACTION ${msg}\001")"
  1070. }
  1071.  
  1072. # Print out current topic
  1073. function zirc_checktopic {
  1074.     zirc_connected || { echo "$(tput setaf 1;tput bold) Not connected $(tput sgr0)" ; return 1 }
  1075.     _zirc_write "TOPIC ${ZIRC_CURRENT}"
  1076. }
  1077.  
  1078. # Returns success if currently connected
  1079. function zirc_connected {
  1080.     ! [[ -z "$ZIRC_FD" ]]
  1081. }
  1082.  
  1083. # Connect to a server
  1084. function zirc_connect {
  1085.     if ! [[ -z "$ZIRC_FD" ]]; then
  1086.         zirc_disconnect
  1087.         zirc_connect
  1088.         return
  1089.     fi
  1090.  
  1091.     if [[ -z "$1" ]]; then
  1092.         echo -e "$(tput setaf 1;tput bold) Usage: $0 <server> $(tput sgr0)"
  1093.         _zirc_param_help
  1094.         return 1
  1095.     fi
  1096.  
  1097.     ZIRC_SERVER="$1"
  1098.     ZIRC_LOWERCASER="_zirc_lowercase_rfc1459"
  1099.     ZIRC_CURRENT=""
  1100.     ZIRC_CHANNELS=()
  1101.  
  1102.     _zirc_param_populate
  1103.  
  1104.     ztcp "$ZIRC_SERVER" "$ZIRC_PORT" || return 1
  1105.     ZIRC_FD="$REPLY"
  1106.     zle -F "$ZIRC_FD" _zirc_handle_incoming_data
  1107.  
  1108.     _zirc_send_connect_lines
  1109.  
  1110.     echo "$(tput setaf 1;tput bold) Connected to $ZIRC_SERVER on fd #$ZIRC_FD $(tput sgr0)"
  1111.     return 0
  1112. }
  1113.  
  1114. # Disconnect from a server
  1115. function zirc_disconnect {
  1116.     if [[ -z "$ZIRC_FD" ]]; then
  1117.         return 0
  1118.     fi
  1119.     echo "$(tput setaf 1;tput bold) Disconnecting from $ZIRC_SERVER... $(tput sgr0)"
  1120.     zle -F "$ZIRC_FD"
  1121.     ztcp -c "$ZIRC_FD"
  1122.     eval "$ZIRC_UNSETSTRING"
  1123.     return 0
  1124. }
  1125.  
  1126. # Setup aliases
  1127. function zirc_aliases {
  1128.     local a
  1129.     echo "$(tput setaf 1;tput bold) Setting up some convenience aliases:"
  1130.     for a in "${(o@)${(k)ZIRC_ALIAS_DEFS[@]}}"; do
  1131.         eval "alias ${a}=\"\${ZIRC_ALIAS_DEFS[\$a]}\""
  1132.         echo "${(l.12...)a} => ${ZIRC_ALIAS_DEFS[$a]} $(tput sgr0)"
  1133.     done
  1134.    
  1135. }
  1136.  
  1137. # Widget for autoquoting everything
  1138. function _zirc_quote_magic {
  1139.     setopt localoptions noksharrays extendedglob
  1140.  
  1141.     local -A applicable
  1142.     applicable=( zirc_action 1 zirc_msg 1 zirc_pmsg 2 me 1 msg 1 pmsg 2 \
  1143.                  zirc_topic 1 ctopic 1 zirc_quit 1 quit 1 zirc_part 2 part 2
  1144.                  join 1 zirc_join 1 )
  1145.  
  1146.     local qkey="${(q)KEYS}"
  1147.    
  1148.     if [[ "$KEYS" != "$qkey" ]]; then
  1149.         local lbuf="$LBUFFER$qkey" arg
  1150.         local -a words
  1151.         words=("${(@Q)${(z)lbuf}}")
  1152.  
  1153.         arg=${applicable[${words[1]}]}
  1154.         ! [[ -z "$arg" ]] && [[ "${#words}" == "$(( arg + 1 ))" ]] && \
  1155.             LBUFFER="${LBUFFER}\\"
  1156.     fi
  1157.     zle .self-insert
  1158. }
  1159.  
  1160. # Setup quote magic
  1161. function zirc_quote {
  1162.     zle -N self-insert _zirc_quote_magic
  1163. }
  1164. zirc_quote
  1165.  
  1166. # Unsetup quote magic
  1167. function zirc_unquote {
  1168.     zle -A .self-insert self-insert
  1169. }
  1170.  
  1171. # }}}3
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement