home *** CD-ROM | disk | FTP | other *** search
/ ftp.update.uu.se / ftp.update.uu.se.2014.03.zip / ftp.update.uu.se / pub / irc / Kiwi.4.39.el < prev    next >
Text File  |  1996-11-11  |  429KB  |  11,672 lines

  1. ;(set (make-local-variable 'debug-on-error) t)
  2. ;;;;;;;;;;;;;;;;;;;;;;;;;;; -*- Mode: Emacs-Lisp -*- ;;;;;;;;;;;;;;;;;;;;;;;;;;
  3. ;; Kiwi.el --- A user interface for the Internet Relay Chat
  4. (defconst irc-version "Kiwi v4.39 for GNU Emacs" "Current Kiwi version.")
  5. (defconst irc-ftp-version "4.39" "Current FTP'able version.")
  6. (defconst irc-ftp-file-names (list (format "Kiwi.%s.el" irc-ftp-version)
  7.                    (format "Kiwi.%s.elc" irc-ftp-version)
  8.                    "Kiwi.README"))
  9. (defconst irc-ftp-source (list (list "FTP.Update.UU.SE" "pub/irc"
  10.                      irc-ftp-file-names)
  11.                    (list "FTP.FUNet.FI" "pub/unix/irc/Emacs"
  12.                      irc-ftp-file-names)))
  13. (defconst irc-hacker "Klaus.Zeuge@Student.DoCS.UU.SE"
  14.   "Email address of the person to send complaints and ideas too.")
  15. ;;;;;;;;;
  16. ;; To do:
  17. ;;;;;;;;; FOOBAR
  18. ;; v4.39 Tue Nov 12 01:40:53 1996    sojge@Student.DoCS.UU.SE
  19. ;;    - BUGFIX: missing arg to format in RPL 475
  20. ;; v4.38 Tue Nov 12 00:49:51 1996    sojge@Student.DoCS.UU.SE
  21. ;;    - Add w3.el support, bind url loader to RET in read area
  22. ;;    - Understand UNDERNET PING xxx arguments
  23. ;;    - Display CTCP SOURCE replies URL stylish
  24. ;;    - Added RPL 437 (channel/nick temporary unavailable)
  25. ;; v4.37 Sun Sep  8 21:33:43 1996    sojge@Student.DoCS.UU.SE
  26. ;;    - Changed FTP sites.
  27. ;; v4.36 Fri Sep  6 19:21:56 1996    sojge@Student.DoCS.UU.SE
  28. ;;    - Message 325 (channel creation time), 338 (login time for a
  29. ;;      user) and 339 (time when the topic of a channel was set)
  30. ;; v4.35 Mon Aug 26 00:07:03 1996    sojge@Student.DoCS.UU.SE
  31. ;;    - Better Undernet handling in various places.
  32. ;;    - BUGFIX: make it harder to issue /WHO command w/o arument.
  33. ;;    - New value for irc-map-keyboard-ISO-646-SE2-to-ISO-8859-1.
  34. ;; v4.34 Fri Feb  9 19:38:02 1996    sojge@Student.DoCS.UU.SE
  35. ;;    - Use last-command-char instead of last-input-char.
  36. ;;    - Obsoleted irc-explain-who-mode, moved to code to 352 handler.
  37. ;;    - Added undernet message 329, 333.
  38. ;;    - If emacs-version > 18, assume irc-emacs-knows-ISO8859-1 to t.
  39. ;;    - Added RPL262.
  40. ;;    - Made irc-startup-hook non-depended on LUSERS commands, moved it to
  41. ;;      CLIENT-SYNCH like mechanism (CLIENT-START)
  42. ;;      - Added 250 highest connect count.
  43. ;;    - Added a "whois x x" in irc-execute-info.
  44. ;;    - Added ignore stuff in notify detector, RPL303.
  45. ;;    - Added 409 no origin spec'ed (from /quo ping).
  46. ;;    - Reply 442 keeps changing, more kludging added.
  47. ;;    - BUGFIX, now understands 002 message "ircd2.8/dog3-super.pl7"
  48. ;; v4.33 Tue Dec 13 18:59:10 1994    sojge@Student.DoCS.UU.SE
  49. ;;    - Added new variable irc-scroll-step.
  50. ;;    - Added better knoweldge of &channels.
  51. ;;    - Show own nickname in ping replies on screen from others.
  52. ;;    - Cleaned up server informatio in /LINKS reply.
  53. ;;    - Better regexp when parsing 203:205 messages.
  54. ;;    - Put \< and \> around nick regexp for backtalk.
  55. ;;    - IRC-servers now understands command "TOPIC #C"
  56. ;;    - BUGFIX: 2.8.20 has a new 204 format with funky timer.
  57. ;; v4.32 Mon Aug  8 02:53:16 1994    sojge@Student.DoCS.UU.SE
  58. ;;    - BUGFIX: server 2.8.20 has new 317 message.
  59. ;;    - Added status line counter irc-reply-count for /who, /names, /links.
  60. ;;    - Added new /signal detect for /notify detect/lost sight messages.
  61. ;;    - Added new variable irc-map-keyboard-ISO-646-SE2-to-ISO-8859-1
  62. ;;      to be used if one wants irc-self-insert to map certain keystrokes.
  63. ;;    - Changed irc-self-insert to be able to map from ISO 646-SE2 to
  64. ;;      ISO 8859-1.
  65. ;;    - Fixed typo in docstring of irc-time-diff.
  66. ;;    - Use irc-userhost in irc-parse-channel.
  67. ;; v4.31 Tue Oct 19 20:59:11 1993    sojge@Student.DoCS.UU.SE
  68. ;;    - BUGFIX: don't crash if CTCP quote is last in string.
  69. ;;    - BUGFIX: name buffer accoring to connected TCP-port, not default
  70. ;;      TCP-port.
  71. ;;    - Better handling of channel topic display.
  72. ;;    - Added handling of ERR 422 and 443, and RPL 249.
  73. ;;    - Clean up CTCP VERSION reply before displaying it.
  74. ;; v4.30 Tue Aug 24 20:52:21 1993    sojge@Student.DoCS.UU.SE
  75. ;;    - BUG FIX: erroneous format string fixed when handling CTCP ECHO reply.
  76. ;;    - Bug fix in irc-execute-notify, don't try to irc-forget a non nick.
  77. ;;    - Added backtalk to documentation of /signal.
  78. ;;    - Made variable irc-port (ie the TCP port used to connect to an IRC
  79. ;;      server) buffer local so different sessions can use diffferent ports.
  80. ;;    - Added handling of RPL 392.
  81. ;;    - Better handling of RPL 322.
  82. ;;    - Now cleans up QUIT messages.
  83. ;;    - Added handling ERR 422, no MOTD file.
  84. ;;    - Minor betterification in character mapping.
  85. ;; v4.29 Thu Aug 12 03:24:57 1993    sojge@Student.DoCS.UU.SE
  86. ;;    - If DEL pressed while point is at first postion in input region,
  87. ;;      scroll down page instead of beep.
  88. ;;    - More channel modes explained in irc-explain-mode (k and v).
  89. ;;    - Force emacs to offer to save the Kiwi buffer before exiting emacs.
  90. ;;    - Splitted up irc-parse-RPL so it's byte-compile'able with v18 emacs.
  91. ;;    - Remove the CTCP MOOD command as no one else used it.
  92. ;;    - As there are a lot of old clients out there, send several CTCP pings.
  93. ;;    - Unless debug-on-error is non-nil, don't crash when finding dots in
  94. ;;      host names, nicks etc.
  95. ;;    - New function irc-time-diff used to not send ISON commands more often
  96. ;;      than every 60 second.
  97. ;;    - New handling of topic, see /HELP TOPIC.
  98. ;;    - Don't care what user tries to /VERSION, let server decide if it
  99. ;;      makes sense.
  100. ;;    - Added handling of RPL 305, 306, 371, 374, 392, 394.
  101. ;;    - Added handling of RPL 242, 243, 244, 253, 261.
  102. ;;    - New format in TRACE output in RPL 200, 211.
  103. ;;    - Better parsing of "hello this is ircd version xxx" string at startup.
  104. ;;    - Added handling of ERR 436, 444, 445, 446, 467, 475.
  105. ;;    - Some minor changes in the CTCP handling. Nothing important.
  106. ;;    - make-local-variable doesn't set the variable in emacs v19, so needed
  107. ;;      to add a set in several places. NOW RUNS WITH GNU EMACS VERSION 19.
  108. ;;    - Fumbled around some more with character set convertings. Should go
  109. ;;      the v19 way, in the future.
  110. ;; v4.28 Mon Apr 19 15:48:45 1993    sojge@Student.DoCS.UU.SE
  111. ;;    - Made client somewhat compliant to ircd 2.8.
  112. ;;    - Added some (as of yet incomplete) support for different character
  113. ;;      sets like ISO 8859-1 and SIS E47.
  114. ;;    - Changed output of /WHO
  115. ;;    - Bugfixed irc-lowlevel-dequote to not crash when getting erroneous
  116. ;;      messages breaking the CNTRL/P quoting.
  117. ;;    - Bugfixed irc-execute-event.
  118. ;;    - Added CTCP MOOD. No /MOOD command yet, though.
  119. ;;    - Clean up a users full name in WHO replies.
  120. ;; v4.27 Mon Sep 14 19:17:23 1992    sojge@Student.DoCS.UU.SE
  121. ;;    - Better handling of versions through irc-ftp-* variables.
  122. ;;    - Added variable irc-show-japanese-characters to get better control
  123. ;;      about in what way japanese characters are inserted into buffer.
  124. ;;    - Spiffed up CTCP VERSION handling to comply to CTCP.mem v13.
  125. ;;    - Added flag irc-drop-ircII-text-kludge-control-characters for those
  126. ;;      users who WANT to see ^B, ^V and ^_ in text.
  127. ;;    - Ignore CNTRL/B, CNTRL/V and CNTRL/_ in incoming messages, as those
  128. ;;      are used by the ircII client to toggle reverse, underline and bold
  129. ;;      attributes of text.
  130. ;;    - Added variable irc-emacs-knows-ISO8859-1.
  131. ;;    - Fixed timing problem when receiving a PRIVMSG just after changing
  132. ;;      the nickname of oneself.
  133. ;; v4.26 Thu Aug 20 05:17:00 1992    sojge@Student.DoCS.UU.SE
  134. ;;    - Assorted small fixes.
  135. ;;    - Some new table headers (like for WHO).
  136. ;;    - Added RPL369, end of WHOWAS.
  137. ;;    - Added L line reply handling (RPL241).
  138. ;;    - Be nicer when sending automatic warnings.
  139. ;;    - Better handling of CTCP PING replies.
  140. ;;    - Reordered most global variable initialisations.
  141. ;; v4.25 Fri May 29 21:00:32 1992    sojge@Student.DoCS.UU.SE
  142. ;;    - Added user modes (eg /mode sojge -o)
  143. ;;    - Handles display of a channel's ban list (ie reply to /mode #x -b).
  144. ;;    - Better handling of some STATS replies.
  145. ;;    - Fixed irc-parse-quit.
  146. ;;    - Fixed irc-parse-kick.
  147. ;;    - Take care of v2.7.2 message ERROR: Closing Link.
  148. ;;    - Added CTCP commands ECHO, PING, SOURCE.
  149. ;;    - Started on a crude but better /IGNORE command.
  150. ;;    - Made Kiwi display unknown NOTICE's in block style.
  151. ;;    - Added /PING command, based on CTCP. Coded by Kimmo.Suominen@lut.fi.
  152. ;;    - Started on inout and output convertion tables to displat different
  153. ;;      character sets on different equipment.
  154. ;; 4.24 Mon Feb 24 17:01:09 1992    Klaus-Zeuge@DoCS.UU.SE
  155. ;;    - Still more RPL312 hacking. Hopefully looks OK on a 2.6.2 server now.
  156. ;; 4.23 Sat Feb 22 20:57:27 1992    Klaus.Zeuge@DoCS.UU.SE
  157. ;;    - Added real version number and edit history.
  158. ;; 4.22 Sat Feb 22 17:23:41 1992    Klaus.Zeuge@DoCS.UU.SE
  159. ;;    - Bugfixed CTCP VERSION reply from ircII.
  160. ;; 4.21 Sat Feb 22 16:38:05 1992    Klaus.Zeuge@DoCS.UU.SE
  161. ;;    - Removed annoying bug which mixed up different hash tables.
  162. ;;    - /mode can set modes for a user.
  163. ;;    - Added Q and Y to /stats.
  164. ;;    - /notify, a new command helping to see when your friends enter IRC.
  165. ;;    - /topic understands #channels, both when querying and setting.
  166. ;;    - /whois takes an optional first argument with name of server which
  167. ;;      should answer the whois question.
  168. ;;    - /quit now takes an optional reason.
  169. ;;    - Made /quote send an illegal command to server to help synchronizing.
  170. ;;    - Created variables irc-notify-looked-for and irc-notify-detected.
  171. ;;    - Added user mode in irc-explain-mode, added frontend functions
  172. ;;      irc-explain-user-mode and irc-explain-channel-mode.
  173. ;;    - Cope with different RPL312 styles.
  174. ;;    - Doing a somewhat better job at parsing ircII's ugly CTCP VERSION
  175. ;;      replies.
  176. ;;    - Cope with new RPL201-209, 211, 212, 213-219, 221.
  177. ;;    - Cope with some new NOTICE's.
  178. ;;    - Cope with new format of "Received SQUIT" NOTICE.
  179. ;;    - Cosmetic change in presenting other persons QUIT reasons.
  180. ;;    - Renamed irc-notifies into irc-events (lessens confusion with /notify)
  181. ;;    - Recognize the 500 series of ERR's from server.
  182. ;;    - Do a a sleep-for after EVERY received line from server.
  183. ;;    - Moved logging in *debug* buffer into irc-log-in-debug-buffer.
  184. ;; v4.20 Wed Dec 18 06:33:57 1991    Klaus.Zeuge@DoCS.UU.SE
  185. ;;    - Change a!b@c on incoming messages into a in irc-parse-server-msg.
  186. ;;      (Can you say kludge? I *knew* you could!)
  187. ;;    - Added RPL353 and RPL352 as front ends for NAMREPLY and WHOREPLY.
  188. ;;    - Parse 2.7(.0) version string correctly.
  189. ;;    - Better value for irc-msg-cont-used when reporting a channels mode.
  190. ;;    - Added Kimmo's code for detecting people on IRC using the ISON
  191. ;;      mechanism, irc-execute-notify. Also his irc-notify-list etc.
  192. ;;    - Added Kimmo's code for /ME and /DESCRIBE commands for CTCP ACTION.
  193. ;;    - Added Kimmo's code for recognizing CTCP ACTION commands.
  194. ;;    - Added fixes to keep Kiwi.el from choking on 2.7 messages.
  195. ;;      Fixed RPL messages are: 206, 209, 301, 304, 352, 353, 354,
  196. ;;      367, 368, 371, 373, 383, 384. Thank you Kimmo Suominen <kim@lut.fi>
  197. ;;      for supplying fixes.
  198. ;;    - Made comand "/join #channel +p" and friends kosher.
  199. ;;    - Added : as /MSG like command again after getting requests for it.
  200. ;;    - Threw out my irc-current-time based on writing irc-idle-scratch-file
  201. ;;      and replaced it by one donated by Stephen Ma <ma_s@maths.su.oz.au>.
  202. ;;    - Removed bug in irc-execute-signal.
  203. ;;    - Fixed parse error in irc-parse-pong.
  204. ;;    - More defensive handling of RPL319.
  205. ;; v4.19 Wed Nov 13 15:18:00 1991    Klaus.Zeuge@DoCS.UU.SE
  206. ;;    - Removed forgotten disabling of /KILL command. Ehum...
  207. ;;    - Use function make-temp-name when naming irc-idle-scratch-file.
  208. ;;    - Better formatting in /membership display.
  209. ;;    - Made irc-nuke-whitespace remove trailing spaces too.
  210. ;;    - Understand USERHOST replies (RPL302).
  211. ;;    - More 442 messages understood. Sigh.
  212. ;;    - Incoming TOPIC messages might contain channel name field.
  213. ;;    - USERS reply might contain word "display". Still valid.
  214. ;;    - Cope with 2.6.2e type of TRACE link lines.
  215. ;;    - "Understand" reason field in incoming QUIT messages.
  216. ;;    - Added Kims (kim@lut.fi) fix for 2.6.2e type of LUSER reply.
  217. ;;    - Fixed bug wtih dropped first character when user says "/mode * o u".
  218. ;; v4.18 Tue Oct 22 06:46:49 1991    Klaus.Zeuge@DoCS.UU.SE
  219. ;;    - Moved creation of irc-count-incoming-messages to irc-mode from
  220. ;;      irc-parse-server-msg.
  221. ;;    - Changed irc-truncate-buffer to chop down to irc-minimum-size whenever
  222. ;;      buffer has grown to irc-maximum-size.
  223. ;;    - Made irc-maximum-size = 64KB.
  224. ;;    - Added irc-minimum-size = 32KB.
  225. ;;    - Made most hash table twice as big.
  226. ;; v4.17 Sun Oct 20 17:05:01 1991    Klaus.Zeuge@DoCS.UU.SE
  227. ;;    - Rewrote most calls to string-match so they don't depend on . in
  228. ;;      regexps, as . doesn't match \n.
  229. ;;    - Made CTCP handling more iterative (recursive handling turned out
  230. ;;      to exhaust stacks in worst cases).
  231. ;;    - Made a few more variables buffer local.
  232. ;;    - Added low level quoting of \000, \n, \r, \020 and changed CTCP level
  233. ;;      quoting to use only \001 and \\.
  234. ;;    - Better irc-execute-stats.
  235. ;;    - Replaced all "\\s " by " " and all "\\S " by "[^: ]". Hopefully
  236. ;;      works better.
  237. ;;    - Crude RPL303 handling (reply to ISON).
  238. ;;    - Ripped out irc-maintain-tree! Hooray! Replaced by hash table code
  239. ;;      BUT named the new functions irc-remember, irc-recall, irc-forget.
  240. ;;      This speeded up /NAMES from some 5 minutes to some 10 seconds.
  241. ;; v4.16 Tue Sep 17 21:07:01 1991    Klaus.Zeuge@DoCS.UU.SE
  242. ;;    - When seeing idle time from IrcII clients, translate the large number
  243. ;;      of seconds into days, hours, minutes and seconds.
  244. ;;    - Writing to /dev/null to keep track of idle isn't portable. Use a
  245. ;;      temporary file in the users home directory instead.
  246. ;; v4.15 Thu Aug 22 13:46:03 1991    sojge@mizar.docs.uu.se
  247. ;;    - If user connects to server at host foo.bar.se and foo.se is an
  248. ;;      alias for rela.name.se, Kiwi gets confused. Now irc-server is
  249. ;;      set to real (ie generic) name from the servers Welcome message.
  250. ;;    - Fixed the macro subfield so it won't evaluate at compile time.
  251. ;;      Sigh. Stupid sojge. Thank you Lennart Staflin, Link|ping.
  252. ;;    - Fixed irc-parse-RPL: 317 does NOT give victims nick.
  253. ;;    - Fixed irc-maintain-tree to not crash when removing a service.
  254. ;;    - Added "Notice unauthorized connect" in irc-parse-notice.
  255. ;;    - Added CTCP query and reply for "FINGER". Hopefully this is added in
  256. ;;      a portable way, but I don't really KNOW ... :-(
  257. ;;    - Made irc-is-receiver recognize foo@bar.dom as valid receiver.
  258. ;; v4.14 Mon Aug 12 10:15:05 1991    sojge@mizar.docs.uu.se
  259. ;;    - Fixed /MODE command to work even when saying "/mode ..." in the
  260. ;;      buffer, not only when using C-c m.
  261. ;;    - Fixed some ERR-reply parsing code to grok new format.
  262. ;;    - Added /LEAVE 0 to leave all channels, and made /JOIN 0 just stop
  263. ;;      talking to the current channel.
  264. ;;    - Better nickname control, new scheme with irc-nick-used to keep track
  265. ;;      of what nick we have.
  266. ;;    - Renamed irc-linkstree into irc-linksinfo.
  267. ;;    - Kludged the mess with 2.6 servers first being names 2.6pre19,
  268. ;;      later 2.6.1a so the latter gets a HIGHER irc-edit-version number.
  269. ;;    - Parse RPL 364 messages, ie answers to /LINKS in 2.6.1 servers.
  270. ;;    - For now, ignore message 318.
  271. ;; v4.13 Thu Jun 13 10:28:31 1991    sojge@mizar.docs.uu.se
  272. ;;    - Handle ERR_NICKNAMEINUSE (433) at "login" time.
  273. ;;    - More homogenous command parsing (both /-style and keybound).
  274. ;;    - Cache subscribed channel names.
  275. ;;    - Name  Kiwi buffer "*Kiwi-<server>*".
  276. ;;    - Always run in "slow speed terminal" mode.
  277. ;;    - Shorter messages displayed when seeing a KILL, skipped path.
  278. ;;    - Renamed irc-hosttree into irc-servernames.
  279. ;;    - Added code to put communication in -*debug* buffer IFF it exists.
  280. ;;    - Changed regexp for host names yet again.
  281. ;;    - When getting the windows width, make sure it's the Kiwi window.
  282. ;;    - Prepared function irc to handle several sessions.
  283. ;;    - Handle some 2.6pre19 messages (324, MODE, 403).
  284. ;;    - Bound C-c i to /info.
  285. ;;    - Changed C-c m from /motd to /mode.
  286. ;;    - Fixed misfeature for v18.57 GNU Emacs. Several return values from
  287. ;;      function process-status are valid. Don't start a new session when
  288. ;;      an old one is running.
  289. ;;    - Fixed bug in showing LIST or NAMES reply of Kanjii channel.
  290. ;;    - Clean up channel names as they can contain cntrl-chars too.
  291. ;;    - Fixed display of time to be nicer.
  292. ;;    - Make the (interactive)-part of the irc-execute-* commands more alike
  293. ;;      each other.
  294. ;;    - Bugfix: understand ESC in channel names in a few more places.
  295. ;;    - Bugfix: understand "i" etc, not only "+i" when parsing MODE.
  296. ;;    - Made /COMMAND be shown in buffer when doing command by keys.
  297. ;;    - Amazingly how yours truly can mess up code! Fixed /LEAVE again :-)
  298. ;; v4.12 Sun Mar  3 02:45:21 1991    sojge@mizar.docs.uu.se
  299. ;;    - Changed wording on ctcp (client-to-client protocol) answer for
  300. ;;      a VERSION query.
  301. ;;    - Added C-c C-k to do irc-execute-kill.
  302. ;;    - Bugfixed irc-execute-leave so it works when typing /LEAVE not just
  303. ;;      when typing C-c q.
  304. ;;    - Better handling of /STATS C replies from remote servers.
  305. ;;    - Handle error after /kick user when user's not on channel.
  306. ;; v4.11 Fri Mar  1 16:31:04 1991    sojge@mizar.docs.uu.se
  307. ;;    - Bugfix, corrected misspelled variable for when replying to unkown
  308. ;;      client-to-client PRIVMSG.
  309. ;; v4.10 Thu Feb 28 20:06:05 1991    sojge@mizar.docs.uu.se
  310. ;;    - New behaivour of /WHO, see /HELP WHO.
  311. ;;    - Various bugfixes. (Mostly due to bound keys).
  312. ;;    - Replaced irc-read-user/host by irc-read-object.
  313. ;; v4.9 Wed Feb 27 20:29:58 1991    sojge@mizar.docs.uu.se
  314. ;;    - Added quoting of messages between CNTRL/A:s.
  315. ;;    - Better grok of WALLOPS.
  316. ;;    - Remember correct spelling of a services nickname when seeing
  317. ;;      NOTICES's from one.
  318. ;;    - Bugfixed /CONNECT which w/o "remoteserver" goofed.
  319. ;; v4.8 Wed Feb 27 03:57:50 1991    sojge@mizar.docs.uu.se
  320. ;;    - More initialisation help.
  321. ;;    - Changed client-to-client protocol in non-backward compatible way.
  322. ;;    - OK'ed "/version mizar*".
  323. ;;    - Better handling of /join 0 when on #channel. Updates irc-channel.
  324. ;;    - Changed handling of unknown NOTICE's to be treated as PRIVMSG's.
  325. ;;    - Fixed bug when replying to CLIENT ERRMSG.
  326. ;;    - Show irc-channel in status line.
  327. ;;    - Always send two ^A's, even if to queries/answers are in a row.
  328. ;;    - Made /msg grok broadcast addresses ($server, #host) when enabled.
  329. ;;    - Fixed bugs in /kick.
  330. ;;    - Better help for how to install your personal IRC initiation.
  331. ;; v4.7 Sun Feb  3 03:51:59 1991    sojge@mizar.docs.uu.se
  332. ;;    - Take care of some new styled NOTICE's from the server.
  333. ;;    - Cleaned up the code of irc-parse-priv.
  334. ;;    - Bugfixed irc-parse-kick to keep better track of where we are.
  335. ;;    - Added command /SERVICE.
  336. ;; v4.6 Fri Feb  1 04:03:31 1991    sojge@mizar.docs.uu.se
  337. ;;    - Better handling of /WHOWAS.
  338. ;;    - Changed string from "Kiwi Operator" into "Kiwi, Operator" while
  339. ;;      enabled.
  340. ;; v4.5 Fri Feb  1 02:24:00 1991    sojge@mizar.docs.uu.se
  341. ;;    - Added command /USERINFO to set a string which can be queried by other
  342. ;;      users. Augmented commands /INFO and /VERSION to query the user
  343. ;;      settable string and to query some client version from a users client.
  344. ;;    - Added knowledge of some more NOTICE's from the server.
  345. ;;    - Better handling of STATS, both in giving command (/STATS) and
  346. ;;      parsing L type replies (ie how much data). Added /HELP STATS.
  347. ;;    - Display another field in WHOIS/WHOWAS replies, showing servers text
  348. ;;      field from message 312.
  349. ;;    - Added in irc-parse-notice case for "*** ..." messages.
  350. ;;    - Bugfixed irc-execute-help, so it deals with aliases and topics which
  351. ;;      aren't commands.
  352. ;;    - Changed clients name from sojge-irc.el to Kiwi.el
  353. ;;      (Kiwi initially was irc.el).
  354. ;;    - Added varibales irc-msg-info-pre and -post for letting user select
  355. ;;      how information (default eg: [Foo has joined channel +Bar], the [
  356. ;;      and ] characters) messages start and end.
  357. ;;    - Statistics display nicyfied.
  358. ;; v4.4 Mon Dec 17 17:51:24 1990    sojge@mizar.docs.uu.se
  359. ;;    - Added column alignment (irc-msg-cont-used) for RPL322 and RPL323
  360. ;;      messages (RPL_LIST and RPL_LISTEND).
  361. ;;    - Bugfix: prevents client from crashing (when connected to a 2.6-server
  362. ;;      and doing a TRACE for a nonexistent server) by adding some
  363. ;;      code the for 402 ERR reply (ERR_NOSUCHSERVER).
  364. ;; v4.3 Sun Dec 16 19:19:00 1990    sojge@mizar.docs.uu.se
  365. ;;    - Added case for trace reply "UNKNOWN" in irc-parse-notice.
  366. ;;    - Added key C-c = to do a /MEMBER command.
  367. ;;    - Bugfix: changed general regexp in irc-parse-server-msg to not allow
  368. ;;      spaces in the server part.
  369. ;;    - Made irc-execute-whois handle the /WHOWAS command.
  370. ;;    - Tell the clients version too, after a /VERSION.
  371. ;;    - Bugfix: rewrote irc-execute-topic to put the (interactive) "command"
  372. ;;      in "topmode".
  373. ;;    - Save username in 2.6 kind of USER-traces.
  374. ;;    - Bugfix: Don't remove bogus irc-nick from irc-nicknames on startup
  375. ;;      when setting first nick after default nick failed.
  376. ;; v4.2 Sat Dec 15 04:14:22 1990    sojge@mizar.docs.uu.se
  377. ;;    - Bugfix in irc-parse-server-msg: NOTICE's don't have a : before them
  378. ;;      (except the optional :server part).
  379. ;;    - Can't set topic of a #channel, changed irc-execute-topic.
  380. ;;    - Bugfix: irc-parse-notice now recognizes IRC OPERs as users in traces.
  381. ;;    - Made "NOTICE -- Received kill" equivalente to older
  382. ;;      "NOTICE: Received kill".
  383. ;; v4.1 Thu Dec 13 13:35:43 1990    sojge@mizar.docs.uu.se
  384. ;;    - Zapped irc-news to contain little, but current, information.
  385. ;;    - Corrected bug in alignment of output of who-replies for
  386. ;;      servers w/o end-of-who markes (hello 2.6.pre14!) in
  387. ;;      irc-parse-whoreply.
  388. ;;    - Added knowledge of some trace messages in irc-parse-notice.
  389. ;;    - Fixed bug in irc-parse-notice, so the number of invisble users
  390. ;;      will be displayed if you're an enabled irc operator.
  391. ;;      Thank's heu@byron.u.washington.edu.
  392. ;;    - Fixed irc-execute-links to only reset list of known hosts on
  393. ;;      a LINKS of all the world. (Ie don't reset on LINKS *.SE).
  394. ;;    - Spiffed up sojge-irc's grok of which privmsg go where, changed
  395. ;;      way irc-parse-priv talks to irc-parse-public.
  396. ;;    - Added /MEMBER to show which channels the user's listening and
  397. ;;      talking to.
  398. ;;    - Indicate ircII's CNTRL/B's by *'s.
  399. ;;    - Scrapped [You have joined/left]-messages, instead tell user which
  400. ;;      she's listening and writing to, if any.
  401. ;;    - Added NOTICE-pattern matching of OPER to be analogous to USER
  402. ;;      and CHANOP.
  403. ;;      Thank's kim@lut.fi.
  404. ;;    - Swapped key definitions of C-c C-q and C-c q.
  405. ;;      Thank's kim@lut.fi.
  406. ;;    - Made irc-parse-public look for single old channel in
  407. ;;      irc-subscribed-channels.
  408. ;;    - Added better support for irc-subscribed-channels.
  409. ;;    - irc-parse-RPL, 472: s/inventation/invitation/.
  410. ;;    - Made /WHOWASRPL's be written correctly.
  411. ;;    - Rewrote irc-parse-channel to be better in coping with #channels.
  412. ;;    - Added #channels to be recognized in irc-is-named-channel and in
  413. ;;      irc-is-channelname.
  414. ;;    - Fixed typo in irc-parse-notice.
  415. ;; v4.0 Fri Nov 16 07:06:02 1990    sojge@mizar.docs.uu.se
  416. ;;      Seems to work with both v2.5.1 and v2.6pre14 servers.
  417. ;;    - Made irc-execute-msg send with PRIVMSG is irc-channel is a #channel.
  418. ;;    - Added PART when on 2.6 server in irc-execute-leave.
  419. ;;    - Added JOIN when on 2.6 server in irc-execute-join.
  420. ;;    - Added 2.6 level reply message 317 in irc-parse-RPL.
  421. ;;    - Added 2.6 level commands JOIN and PART in irc-parse-server-msg and
  422. ;;      irc-parse-channel.
  423. ;;    - On nonmatcher NOTICE, just give the notice to the user with out
  424. ;;      frightening her with big WARNING signs.
  425. ;;    - Removed buggy string-match in irc-parse-notice for svarte being
  426. ;;      matched against a terminal (rt).
  427. ;;    - irc-parse-RPL: set irc-msg-cont-used when receiving message 314
  428. ;;      (RPL_WHOWASUSER).
  429. ;;    - Made confirmation when sending to several users/channels at once
  430. ;;      being written one confirmation per line.
  431. ;; v3.14 Thu Nov  1 19:47:09 1990    sojge@mizar.docs.uu.se
  432. ;;    - Made /OOPS work without an argument, if non given, ask for one.
  433. ;;    - Added possible bugfix in irc-parse-RPL for message 322.
  434. ;;    - irc-execute-command: don't put "'s around help w/ possible commands.
  435. ;;    - irc-insert-most: use right-most argument of irc-choose-break-point.
  436. ;;    - irc-insert: use right-most argument of irc-choose-break-point.
  437. ;;    - irc-choose-break-point: use parameter right-most, not (window-width).
  438. ;;    - irc-parse-notice: slightly new "no users logged in" message.
  439. ;;    - irc-parse-notice: write "serverlink", not "connection" in /TRACES.
  440. ;;    - irc-parse-wallops: set irc-msg-cont-used to max window-width / 2.
  441. ;;    - irc-parse-priv: set irc-msg-cont-used to max window-width / 2.
  442. ;;    - irc-parse-public: set irc-msg-cont-used to max window-width / 2.
  443. ;;    - irc-parse-channel: prevent negative string length in pd.
  444. ;; v3.13 Tue Oct  9 04:35:51 1990    sojge@mizar.docs.uu.se
  445. ;;    - Sigh, when do I learn not to release code when being ++tired?
  446. ;;      Fixed a newborn bug in irc-execute-msg.
  447. ;; v3.12 Tue Oct  9 03:49:14 1990    sojge@mizar.docs.uu.se
  448. ;;    - Made a quick and dirty bugfix to prevent crashing in irc-insert-more.
  449. ;;      Sort of works. Sigh.
  450. ;;    - Fixed bug in irc-parse-server-msg, do accept NOTICEs from "strange"
  451. ;;      origins...
  452. ;;    - Set global irc-msg-cont-used in irc-parse-RPL while parsing WHOIS
  453. ;;      replies.
  454. ;;    - Removed two bugs in irc-insert-more.
  455. ;;    - Made /WHOIS STRING trying to get information even if STRING isn't
  456. ;;      remembered in irc-nicknames as being present.
  457. ;;    - Made /WHO USER do a WHOIS USER, while /WHO CHANNEL does a
  458. ;;      WHO CHANNEL.
  459. ;;    - Made irc-execute-wallops confirm if irc-confirm is non-nil.
  460. ;; v3.11 Thu Aug 30 17:41:18 1990    sojge@mizar.docs.uu.se
  461. ;;    - Sigh, fixed bug in irc-execute-whowas. I'd better do a RPLACA...
  462. ;; v3.10 Thu Aug 30 15:47:36 1990    sojge@mizar.docs.uu.se
  463. ;;    - Added irc-execute-whowas (long due).
  464. ;;    - Fixed som other minor bugs. I hope.
  465. ;;    - BUGFIX in irc-remove-from-tree, do comparsion in upcase.
  466. ;;    - Made irc-execute-msg tell if receivers are users or channels.
  467. ;;    - Fixed bug in irc-is-channel. ("-77?" is NOT a channel ID).
  468. ;;    - Recognize Kanji message and replace with generic string.
  469. ;; v3.9 Wed Aug 22 08:07:21 1990    sojge@mizar.docs.uu.se
  470. ;;    - Added a rudimentary function irc-execute-kick.
  471. ;;    - Wrote predicate irc-is-channelname.
  472. ;;    - Updated predicate irc-is-nickname to better reflect reality.
  473. ;;    - Made irc-execute-msg grok channel's as receipants.
  474. ;;    - Added simplistic irc-execute-mode function.
  475. ;;    - FIXED BUG in irc-find-to by rewriting it.
  476. ;;    - Made message 421 grok 2.5 messages too.
  477. ;;    - Added function irc-parse-kick.
  478. ;;    - Added some more (let ((irc-msg-cont-used ...) around irc-insert's.
  479. ;;    - Made irc-explain-mode work.
  480. ;;    - Changed count in irc-execute-send so irc-msg-sent is right justified.
  481. ;; v3.8 Sun Aug 19 04:55:31 1990    sojge@mizar.docs.uu.se
  482. ;;    - BUGFIX: v3.6 introduced bug making it hard to join negative channels,
  483. ;;      now it's easy again.
  484. ;; v3.7 Sat Aug 18 23:48:56 1990    sojge@mizar.docs.uu.se
  485. ;;    - Set irc-msg-cont-used before calling irc-insert for some lists.
  486. ;;    - Understand ERR_NOTONCHANNEL message.
  487. ;;    - Don't explecitly request MOTD (message of the day) when connected
  488. ;;      to v2.5 servers or later. They give it anyway.
  489. ;;    - Don't show the "no topic set" messages from remote old server
  490. ;;      at topic changes.
  491. ;;    - Collect server names in irc-parse-RPL.
  492. ;;    - Added irc-split-lines to make better line splits in irc-insert.
  493. ;; v3.6 Fri Aug 17 04:41:19 1990    sojge@mizar.docs.uu.se
  494. ;;    - Changed format of how the status in a WHO listing appears.
  495. ;;    - Ignore error messages from other old server complaining MODE being
  496. ;;      an unknown command.
  497. ;;    - Understands the WHO-reply statuses "channel operator"
  498. ;;      and "channe operator and IRC operator".
  499. ;;    - Sort of understands reply message 316 .
  500. ;;    - Join channel 007, not +007 at "/join 007" (ie no prepending of + when
  501. ;;      first letter in channelname is a digit).
  502. ;;    - Understand reply message 324.
  503. ;;    - Say "using default" after a "/query *".
  504. ;; v3.5 Thu Jun 14 07:23:51 1990    sojge@emil.csd.uu.se
  505. ;;    - Teached /KILL to understand comments.
  506. ;;    - Added a simplistic header to linreply display.
  507. ;;    - Make it possible for away messages to start with :.
  508. ;;    - Save nickname in irc-parse-wallops.
  509. ;; v3.4 Mon Jun 11 03:55:08 1990    sojge@emil.csd.uu.se
  510. ;;    - Added operator level command /CONNECT.
  511. ;;    - Remapped C-C C-S to be irc-execute-squit.
  512. ;;    - Added operator level command /SQUIT.
  513. ;;    - Added operator level command /WALLOPS.
  514. ;;    - Added some support for mnemonic channel ID's, ie not only numbers
  515. ;;      but also strings can identify a channel. Probaly a bit buggy.
  516. ;;      Problem: How long can an ID be?
  517. ;;    - Made irc-channel into a string, from being a number.
  518. ;;    - Made /WHO SOJGE show a one line WHO reply (plus header) about SOJGE,
  519. ;;      ie not doing a WHOIS for SOJGE. Will probaly change.
  520. ;; v3.3 Wed Jun  6 07:26:57 1990    sojge@emil.csd.uu.se
  521. ;;    - Keep statistics on LIST replies in a new way.
  522. ;;    - Made irc-add-to-tree do it's string comparsions in upper case, this
  523. ;;      prevents the same name in two different cases to be stored.
  524. ;;    - Corrected minor bug in irc-parse-notice about reconizing USERS
  525. ;;      replies.
  526. ;;    - Changed (irc-insert "foo\nbar") into 
  527. ;;      (irc-insert "foo") (irc-insert "bar")
  528. ;;    - Made the "IRC halted" message a bit more flashy.
  529. ;; v3.2 Mon Jun  4 19:59:00 1990    sojge@emil.csd.uu.se
  530. ;;    - When on a fast terminal (see irc-terminal-is-slow), don't bother
  531. ;;      to collect various replies in temporary storage lists. Display the
  532. ;;      unsorted entrys as fast as they come in.
  533. ;;    - Improved handling of /USERS replies.
  534. ;; v3.1 Sat May 26 03:05:46 1990    sojge@emil.csd.uu.se
  535. ;;    - Corrected bug which prevented LINK to actually display any data...
  536. ;; v3.0 Sat May 26 02:21:52 1990    sojge@emil.csd.uu.se
  537. ;;    - Changed version from 1.9 to 3.0 in one step.
  538. ;;    - Set irc-nick according to incoming NOTICE messages.
  539. ;;    - Made the WHOREPLY header be displayed when the first reply comes in.
  540. ;;    - Understand message 314, RPL_WHOWASUSER.
  541. ;;    - Renamed irc-nameslist (former irc-whotree) into irc-nicknames.
  542. ;;    - Added case for "no motd at server", both for 2.4 and pre 2.4 servers.
  543. ;;    - Beautified "IRC server xx runs version yy" message.
  544. ;;    - Added irc-execute-version.
  545. ;;    - Added irc-execute-motd.
  546. ;; v1.9 Sat May 19 14:44:58 1990    sojge@emil.csd.uu.se
  547. ;;    - Wrote irc-parse-pong to collect host name from ping messages.
  548. ;;    - Made irc-extract-hosts skip parts between between nodename and "!".
  549. ;;    - Made WHO lists more mnemonic.
  550. ;;    - Made LINREPLYs be gathered in a variable before sorting and
  551. ;;      displaying it even for 2.2 type servers.
  552. ;;    - Make client ask for the message of the day (MOTD) when seeing
  553. ;;      the (final line of the) servers welcome message, not at "start up".
  554. ;;    - Look as far as 1/3 of the line from the right when choosing a
  555. ;;      break point in irc-insert. Makes a few listing look better on
  556. ;;      a 80 column screen.
  557. ;;    - Take care of "unknown connection" message in irc-parse-notice.
  558. ;; v1.8 Thu May 17 00:53:20 1990    sojge@emil.csd.uu.se
  559. ;;    - Say "use /HELP" if user seems totaly confused on channel 0.
  560. ;;    - Fixed bug in irc-parse-whoreply, don't add header to irc-whotree.
  561. ;;    - Say "no users" on a 2.4 (or later) server if user issued /who 
  562. ;;      for an empty channel.
  563. ;; v1.7 Wed May 16 23:34:01 1990    sojge@emil.csd.uu.se
  564. ;;    - Show time when being pinged, not every x minutes.
  565. ;;    - Don't crash if server closed connection, reopen it,
  566. ;;    - Skip some messages like START OF MOTD ...
  567. ;;    - Show what remote server, if any, a message came from.
  568. ;;    - Take care of a bunch of new NOTICE messages.
  569. ;;    - Understand new (server v2.4) type of welcome message.
  570. ;;    - Ignore empty lines from server.
  571. ;;    - Moved logic about format of different information keeping trees
  572. ;;      into irc-maintain-tree.
  573. ;;    - Made (most) error messages start with a % sign.
  574. ;;    - Renamed IRC-WHOTREE into IRC-NAMESTREE.
  575. ;;    - Keeps track of what version the used server is, and depending on it
  576. ;;      uses (or not) the fact that it's possible to gather WHOREPLYs and
  577. ;;      LINREPLYs before displaying it. Exploits the "end of who/links"
  578. ;;      message from the server.
  579. ;;    - Understands new MOTD notices, collects data until end-of-motd-list.
  580. ;;    - Better handling of extracting hostnames from different places.
  581. ;;      Uses irc-extract-hostname.
  582. ;;    - Made irc-maintain-tree use upcase and irc-extract-hostname on items
  583. ;;      for irc-hosttree.
  584. ;;    - Now extracts info from MOTD replies.
  585. ;; v1.6 Mon Apr  9 22:25:22 1990    sojge@emil.csd.uu.se
  586. ;;    - Improved handling of %-signs in messages (data part so to say) by
  587. ;;      doing a s/%/%%/ in functions irc-parse-public and irc-parse-privmsg.
  588. ;; v1.5 Mon Apr  9 17:32:51 1990    sojge@emil.csd.uu.se
  589. ;;    - Extract server names from KILL messages paths.
  590. ;; v1.4 Fri Apr  6 01:30:46 1990    sojge@emil.csd.uu.se
  591. ;;    - Removed s/%/%%/ from irc-parse-server-msg.
  592. ;;    - Let function irc check that the *IRC* buffer has an open stream
  593. ;;      "process" associated with it before trying to switch to the buffer.
  594. ;;      This is handy when the stream has been closed.
  595. ;; v1.3 Tue Apr  3 23:51:38 1990    sojge@emil.csd.uu.se
  596. ;;    - Made irc.el cope with new format on some NOTICE messages.
  597. ;;      (:server NOTICE ...)
  598. ;; v1.2 Fri Mar 30 03:42:31 1990    sojge@emil.csd.uu.se
  599. ;;    - Changed protocol, initiate with USER <username> * * <realname> now.
  600. ;;    - Changed misc. error messages to start with %.
  601. ;;    - Made a few "server message unkown" messages tell where they are
  602. ;;      in the code.
  603. ;;    - Added code to make WHOIS * invokde WHOIS for all users.
  604. ;;    - Made irc-parse-channel set irc-msg-cont-used.
  605. ;;    - Added and removed code for automatic greeting of new joiners to
  606. ;;      channels, in irc-parse-channel. But this doesn't seem to be enough.
  607. ;;      More debugging needed ...
  608. ;;    - Made irc.el understand MOTD messages from server, not reliying on
  609. ;;      all lines in MOTD file starting with a blank.
  610. ;; v1.1 Mon Mar 26 03:37:03 1990    sojge@emil.csd.uu.se
  611. ;;    - Cleaned up some more, in how things are displayed. Servers
  612. ;;      domain names are displayed in upper case, in
  613. ;;      irc-parse-linrpl and their information text "as is". Some
  614. ;;      headers  are underlined.
  615. ;;    - Corrected (?) bug in irc-parse-RPL which handled RPL_MOTD
  616. ;;      messages incorrectly.
  617. ;; v1.0 Wed Feb 28 21:53:49 1990    sojge@emil.csd.uu.se
  618. ;;    - Changed look and feel by introducing a couple of variables
  619. ;;      and removing the conserve-space kludge. Apperence is now user
  620. ;;      settable.
  621. ;;    - Rewritten buggy irc-insert so it works. No more infinite looping.
  622. ;;    - Added a few key bindings.
  623. ;;    - Made irc-parse-RPL (at RPL_WHOISSERVER) and irc-parse-notice add
  624. ;;      information to the irc-hostlist, just like irc-parse-linreply does.
  625. ;; v0.9 Sometime 1989    flax@mizar.docs.uu.se
  626. ;;    - Made irc-linreply add to a list of known hosts so completion of
  627. ;;      host names in irc-execute-admin and others will work. Neat.
  628. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  629. ;; Author          : David C Lawrence           <tale@pawl.rpi.edu>
  630. ;; Created On      : Wed Jun 14 22:22:57 1989
  631. ;; Last major modification: Jonas Flygare
  632. ;; Last minor modification: Klaus Zeuge
  633. ;; Last Modified On: Wed Jan 24 00:54:29 1990
  634. ;; Update Count    : 100
  635. ;; Status          : Stable
  636. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  637. ;;  Copyright (C) 1989  David C Lawrence
  638.  
  639. ;;  This program is free software; you can redistribute it and/or modify
  640. ;;  it under the terms of the GNU General Public License as published by
  641. ;;  the Free Software Foundation; either version 1, or (at your option)
  642. ;;  any later version.
  643.  
  644. ;;  This program is distributed in the hope that it will be useful,
  645. ;;  but WITHOUT ANY WARRANTY; without even the implied warranty of
  646. ;;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  647. ;;  GNU General Public License for more details.
  648.  
  649. ;;  You should have received a copy of the GNU General Public License
  650. ;;  along with this program; if not, write to the Free Software
  651. ;;  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  652.  
  653. ;; Comments and/or bug reports about this interface should be directed to:
  654. ;;     Dave Lawrence          <tale@{pawl,itsgw}.rpi.edu>
  655. ;;     76 1/2 13th Street     +1 518 273 5385
  656. ;;     Troy NY 12180          Generally available on IRC as "tale"
  657.  
  658. ;; History         
  659. ;; 27-Sep-1989        Gnu Maint Acct    (gnu at life.pawl.rpi.edu)
  660. ;;    Last Modified: Wed Sep 27 18:56:19 1989 #6
  661. ;;    * Fixed a misrefenced variable in irc-parse-server-msg so that lines
  662. ;;      which can't be parsed insert only that unparsable line.
  663. ;;    * Added irc-parse-topic and changed irc-signals and irc-notifies
  664. ;;      appropriately.
  665. ;;    * Moved setting of irc-channel to irc-parse-channel from irc-execute-join
  666. ;;      because a channel change isn't guaranteed (ie, trying to change to
  667. ;;      a channel not in 0-10 which has ten users on it).
  668. ;;    * Made irc-message-stamp 'private by default. (Geoff)
  669. ;;    * Made irc-time-stamp 0 by default.      (Also Geoff)
  670. ;;      This tickled an unseen bug in the start-up function which incremented
  671. ;;      irc-last-stamp.  It's fixed now.
  672. ;;    * Fixed a bug with interactive irc-execute-names -- prefix arg was being
  673. ;;      (list ...)ed.
  674. ;;    * Fixed a bug in irc-parse-namreply that dropped a name in the output
  675. ;;      when a line got wrapped.
  676. ;;    * Added /lusers.  I really dislike the name.
  677. ;;    * Added irc-parse-kill.
  678. ;;    * Made irc-execute-msg strip one space after the colon in messages;
  679. ;;      ie, "tale: hi" will send "hi" as a message not " hi".
  680. ;;    * Took out hardcoded width numbers for word-wrapping.  Uses
  681. ;;      (window-width) instead.
  682. ;;    * Added to the regexp for failed nickname changes in irc-parse-error;
  683. ;;      the sentences got changed in the newer servers.
  684. ;;    * Wrapped irc-check-time around display-time-filter for better accuracy
  685. ;;      if a display-time process is running.
  686. ;;    * Made the "IRC Session finished" message include the time.
  687. ;;    * Added irc-conserve-space to imitate the C client message style.  I
  688. ;;      really dislike it aesthetically, but it is handy for people running
  689. ;;      on 24 line screens and at slow baud rates. (Kimmel & others)
  690. ;;    * Support IRCNICK and IRCSERVER environment variables at load time. (Kim)
  691. ;;    * Made /WHO call /WHOIS if given a non-numeric argument.  (Nate)
  692. ;;    * Fixed a bug where an alias would be executed before an exactly matching
  693. ;;      command; ie, alias /WHOALIAS whould execute when /WHO was entered.
  694. ;;    * Runs things in auto-fill-mode with a fill-column of 75 by default.
  695. ;;    * Processes the whole input region as one line instead of line-at-a-time.
  696. ;;    * Made irc-change-alias for non-interactive setting/removing of aliases;
  697. ;;      ie, via irc-mode-hook.  No frills.  (Chris & Nate)
  698. ;;    * _Finally_ got around to adding parsing of numeric notices for new
  699. ;;      servers.
  700.  
  701. ;; Need backquote.el for our macros.
  702. (require 'backquote)
  703.  
  704.  
  705. ;; Defined variables
  706.  
  707. (defvar irc-abusive-ignore nil
  708.   "If non nil, send back a message to persons being ignored, instead of
  709. being silent, while throwing away messages from them.")
  710.  
  711.  
  712. (defvar irc-alias-alist
  713.   '(
  714.     ("?" . "help")            ; Abbrevation
  715.     ("BYE" . "quit")
  716.     ("CHANNEL" . "join")
  717.     ("END" . "quit")            ; Plenty of ways out
  718.     ("EXIT" . "quit")
  719.     ("IDLE" . "who")            ; for people too used to Connect
  720.     ("L" . "list")            ; Abbrevation
  721.     ("M" . "msg")            ; Abbrevation
  722.     ("MS" . "msg")            ; Abbrevation
  723.     ("N" . "names")            ; Abbrevation
  724.     ("QUERY" . "send")            ; For people used to the C client
  725.     ("STOP" . "quit")            ; Plenty of ways out
  726.     ("U". "users")            ; Abbrevation
  727.     ("US". "users")            ; Abbrevation
  728.     ("USE". "users")            ; Abbrevation
  729.     ("USER". "users")            ; Abbrevation
  730.     ("W" . "who")            ; Abbrevation
  731.     ("WHAT" . "list")            ; /WHAT from Connect
  732.     )
  733.   "An association list of command aliases used in irc-mode.
  734. This is the first list checked when irc-mode is looking for a command and it
  735. is maintained with the /ALIAS and /UNALIAS commands.")
  736.  
  737.  
  738. (make-variable-buffer-local
  739.  (defvar irc-cache-n+s nil
  740.    "Cache of known nicks and servers"))
  741.  
  742.  
  743. (make-variable-buffer-local
  744.  (defvar irc-cache-c+n+s nil
  745.    "Cache of known channels, nicks and servers"))
  746.  
  747.  
  748. (make-variable-buffer-local
  749.  (defvar irc-called-from-buffer nil
  750.    "Flag saying whether a command is called from the irc buffer with /names
  751. or invoked through pressing a key like C-c C-c."))
  752.  
  753.  
  754. (make-variable-buffer-local
  755.  (defvar irc-called-from-buffer nil
  756.    "Flag saying whether a command is called from the irc buffer with /names
  757. or invoked through pressing a key like C-c C-c."))
  758.  
  759.  
  760. (defconst irc-command-alist
  761.     '(("ADMIN" . "admin")        ; Get information about IRC admins
  762.       ("ALIAS" . "alias")        ; Add command aliases
  763.       ("AWAY" . "away")            ; Give som indication of your presenc
  764.       ("CONFIRM" . "confirm")        ; Set message confirmation on or off
  765.       ("DESCRIBE" . "describe")        ; CTCP action.
  766.       ("DIE" . "die")            ; Tell server to die.
  767.       ("EVENT" . "event")        ; Change which events give notification
  768.       ("FINGER" . "finger")        ; CTCP finger.
  769.       ("HELP" . "help")            ; Get help on the /COMMANDs
  770.       ("HERE" . "here")            ; Remove the away mark
  771.       ("IGNORE" . "ignore")        ; Ignore messages from a specified user
  772.       ("INFO" . "info")            ; Information about users and authors
  773.       ("INVITE" . "invite")        ; Ask another user to join your channel
  774.       ("JOIN" . "join")            ; Join a channel
  775.       ("KICK" . "kick")            ; Boot a user from a channel
  776.       ("LEAVE" . "leave")        ; Leave a channel
  777.       ("LINKS" . "links")        ; Show which servers are in the IRC-net
  778.       ("LIST" . "list")            ; Show a list of channels and topics
  779.       ("LUSERS" . "lusers")        ; Get the number of users and servers
  780.       ("MAIL" . "mail")            ; Give commands to the mail subsystem.
  781.       ("ME" . "me")            ; Send a CTCP ACTION message to channel
  782.       ("MEMBERSHIPS" . "memberships")    ; Show subscribed channels.
  783.       ("MODE" . "mode")            ; Change or inspect the mode of a chan
  784.       ("MOTD" . "motd")            ; Message of the day
  785.       ("MSG" . "privmsg")        ; Send a private message to someone
  786.       ("NAMES" . "names")        ; Display nick names on each channel
  787.       ("NEWS" . "news")            ; Show news about client.
  788.       ("NICKNAME" . "nick")        ; Change your IRC nickname
  789.       ("NOTIFY" . "notify")        ; Notify when selected nicks are seen
  790.       ("OOPS" . "oops")            ; Resend a misdirected message
  791.       ("OPER" . "oper")            ; Login as an IRC operator
  792.       ("QUIT" . "quit")            ; Exit IRC
  793.       ("QUOTE" . "quote")        ; Send raw text to the server
  794.       ("PING" . "ping")            ; Send CTCP PING to another user
  795.       ("REDIRECT" . "redirect")        ; Send the last message to someone else
  796.       ("SEND" . "send")            ; Set the implicit send list for msgs's
  797.       ("SERVICE" . "service")        ; Add and subtract to list of automates
  798.       ("SIGNAL" . "signal")        ; Change which events give a signal
  799.       ("STAMP" . "stamp")        ; Set time notification interval
  800.       ("STATS" . "stats")        ; Get statistics from server.
  801.       ("SUMMON" . "summon")        ; Ask a user not on IRC to join it
  802.       ("TIME" . "time")            ; Get the current time from a server
  803.       ("TOPIC" . "topic")        ; Change the topic of the channel
  804.       ("TRACE" . "trace")        ; Show the links between servers
  805.       ("UNALIAS" . "unalias")        ; Remove command aliases
  806.       ("UNIGNORE" . "unignore")        ; Stop ignoring user
  807.       ("USERINFO" . "userinfo")        ; Set information about oneself
  808.       ("USERS" . "users")        ; Show users logged in at a server
  809.       ("VERSION" . "version")        ; Version of a server or a users client
  810.       ("WALLOPS" . "wallops")        ; Send a message to all operators
  811.       ("WHO" . "who")            ; Get list of users and their channels
  812.       ("WHOIS" . "whois")        ; Get longer information about a user
  813.       ("WHOWAS" . "whois"))        ; Check who user who has left IRC was.
  814.   "An association list of the regular commands to which all users have access.
  815. Form is (\"COMMAND\" . \"function\") where \"function\" is that last element in
  816. an irc-execute-* symbol.  See also irc-alias-alist and irc-operator-alist.")
  817.  
  818.  
  819. (defvar irc-confirm t
  820.   "*If non-nil, provide confirmation for messages sent on IRC.
  821. It should be noted that confirmation only indicates where irc-mode
  822. tried to send the message, not whether it was actually received.
  823. Use the /CONFIRM command to change.")
  824.  
  825.  
  826. (make-variable-buffer-local
  827.  (defvar irc-default-to "*;"
  828.    "The default recipient of a message if no : or ; is provided.
  829. \"*\" means the current channel, no matter what it is."))
  830.  
  831.  
  832. (make-variable-buffer-local
  833.  (defvar irc-drop-ircII-text-kludge-control-characters t
  834.    "*If nil, show CNTRL/B, CNTRL/V and CNTRL/_ as ^B. ^V and ^_ in text. These
  835. characters are used as a kludge by the client ircII to toggle the attributes
  836. reverse, underline and bold respectivly in text. If non-nil, drop those three
  837. characters."))
  838.  
  839.  
  840. (defvar irc-emacs-knows-ISO8859-1 (>= (string-to-int emacs-version) 19)
  841.   "*Non-nil if Kiwi shouldn't translate octets in incoming messages with
  842. the high bit set to \xyz strings; nil if translation for such characters
  843. (0240 - 0377) should occur.")
  844.  
  845.  
  846. (make-variable-buffer-local
  847.  (defvar irc-events '(ctcp join nick quit topic)
  848.    "Events in IRC that should get notification messages.
  849. A notification message is just one line to indicate that the event has
  850. occurred.  The \"ctcp\", \"join\", \"nick\", \"quit\" and \"topic\"
  851. events are currently supported by the /EVENT command."))
  852.  
  853.  
  854. (defconst irc-help-topic-alist
  855.     '((";" . "Usage: RECEIVER[,RECEIVER]...; MESSAGE
  856.  
  857. Send a message to one or several receivers.
  858. About the same as /MSG and :, see /HELP : and /HELP MSG.
  859.  
  860. When no receiver is given yet, on a line, and you press ; first on that line,
  861. the last receiver is inserted (this may be a users nickname, a channelname,
  862. a list of receivers, etc)
  863.  
  864. Don't use any spaces left of the ;.")
  865.       (":" . "Usage: RECEIVER [, RECEIVER] ... ; MESSAGE
  866.  
  867. Send a message to one or several receivers.
  868. About the same as /MSG and ;, see /HELP ; and /HELP MSG
  869.  
  870. When no receiver was given yet, and : is inserted first on the line, the
  871. last person you sent to will be the default receiver.
  872.  
  873. Don't use any spaces left of the :.")
  874.       ("STARTUP" . "Initiation and startup
  875.  
  876. To make your GNU Emacs know of this IRC user interface, you can add
  877. the following command to your GNU Emacs initialisation file (normaly
  878. .emacs) in your home directory:
  879.         (autoload 'irc \"Kiwi\"
  880.             \"Internet Relay Chat user interface.\" t nil)
  881.  
  882. This will make your Emacs to load the library file Kiwi.elc or Kiwi.el
  883. when you typing M-x irc RET. The file must be in one of the
  884. directories mentioned in the variable load-path. (You can check this
  885. variables value by typing C-h v load-path RET). You can compile the
  886. file Kiwi.el by typing M-x byte-compile-file RET Kiwi.el RET to get
  887. Kiwi.elc.
  888.  
  889. At startup time of IRC, you may want to initiate some settings and
  890. give some commands. This can be done by setting some variables in your
  891. GNU Emacs initialisation file (normaly called .emacs). Some typical
  892. initialisations may be
  893.  
  894.        (setq irc-server \"minsk.docs.uu.se\"      ;Which server to use.
  895.              irc-msg-public \"%s%9s/%s:  \"       ;How to display public msgs
  896.              irc-pop-on-signal 3                ;Use about 1/3 of screen when
  897.                                                 ; popping up a Kiwi buffer.
  898.              ;; Give some information about yourself, whatever you want.
  899.              irc-userinfo (concat
  900.                            \"Studying computer science at the university of\"
  901.                            \" Uppsala. Call me on +46 18 463253.\")
  902.              ;; Commands to be executed when seeing the Welcome message
  903.              ;; from a server we just connected to.
  904.              irc-startup-hook '(lambda ()
  905.                                 (irc-execute-command \"links *.se\")
  906.                                 (irc-execute-command \"who *.se\")))
  907.  
  908. This will make IRC use about 1/3 of the screen when popping up a
  909. window (this happens for instance when you have deselcted all IRC
  910. windows and someone sends you a message). Also, the information string
  911. for you (which can contain any information you choose) is initiated.
  912. When a server says \"welcome\", you will be shown all active servers
  913. in Sweden (SE) and all active users using IRC in Sweden.
  914.  
  915. Don't give the leading / in the arguments to irc-execute-command.
  916.  
  917. If you want more control over how to display public and/or private messages
  918. (at the time exluding WALLs and WALLOPSs) you can use this clumsy way (be
  919. patient, a more user friendly method is on it's way) of setting the variables
  920. irc-public-insert and irc-private-insert to functions taking 3 strings as
  921. arguments, namely the name of the sender, name of the receiver (user or channel
  922. name normaly) and the message itself (in raw format, after extracting the
  923. client-to-client protocol stuff). All this sums up to, that if you don't know
  924. elisp, you probaly don't want to use this method, or else just change the
  925. control string constants in the examples below.
  926. Examples:
  927.   (setq
  928.    irc-public-insert '(lambda (from to msg)
  929.                (let* ((same-chan (string= (upcase irc-channel)
  930.                           (upcase to)))
  931.                   (hdr
  932.                    (format (if same-chan
  933.                        \"%s %9s:  \"
  934.                        \"%s %9s/%s:  \")
  935.                        (if (and irc-message-stamp
  936.                         (not (eq irc-message-stamp
  937.                              'private)))
  938.                        (irc-get-time)
  939.                        \"\")
  940.                        from
  941.                        to))
  942.                   (irc-msg-cont-used
  943.                    (make-string 
  944.                 (min (length hdr)
  945.                      (/ (window-width (get-buffer-window
  946.                                (current-buffer)))
  947.                     2))
  948.                 ? )))
  949.              (irc-insert
  950.               (concat hdr (irc-clean-up-message msg)))))
  951.    irc-private-insert '(lambda (from to msg)
  952.             (let* ((to-whom
  953.                 (cond ((string= (upcase irc-nick-used)
  954.                         (upcase to))
  955.                        \"*%s %s*  \")
  956.                       ((irc-is-broadcastname to)
  957.                        (concat \"=%s %s BROADCAST to all\"
  958.                            \"users on IRC server(s)\"
  959.                            \" \\\"%s\\\"=  \"))
  960.                       (t \"*%s %s/%s*  \")))
  961.                    (hdr
  962.                 (format to-whom
  963.                     (if (and
  964.                          irc-message-stamp
  965.                          (eq irc-message-stamp
  966.                          'private))
  967.                         (irc-get-time)
  968.                         \"\")
  969.                     from
  970.                     to))
  971.                    (irc-msg-cont-used (make-string 
  972.                            (min (length hdr)
  973.                             (/ (window-width (get-buffer-window (current-buffer)))
  974.                                2))
  975.                            ? )))
  976.               (irc-insert
  977.                (concat hdr (irc-clean-up-message msg))))))
  978.  
  979. Hint: the internal control strings uses 2 or 3 of the %s to write the time,
  980. the senders name and the receivers name. If only 2 %s are given, the receivers
  981. name won't be written.
  982.  
  983. [Note: this is a preliminary version of the help text, please send mail
  984. to Klaus.Zeuge@Student.DoCS.UU.SE if you think it needs to be changed.]"))
  985.   "A-list with car = keyword-string for a topic and cdr = descriptions string
  986. of the keyword.")
  987.  
  988.  
  989. (make-variable-buffer-local
  990.  (defvar irc-history nil
  991.    "A list of messages which irc-mode has processed.
  992. This includes both successfully and unsuccessfully sent messages, starting
  993. with the most recent first.  irc-max-history limits the number of items
  994. that can appear in the list when using irc-add-to-history."))
  995.  
  996.  
  997. (make-variable-buffer-local
  998.  (defvar irc-ignore-automatic-warnings nil
  999.    "*Variable to say whether to to display or not display automatic warnings
  1000. from users. Such warnings start with the marker \"<Automatic warning> \" in
  1001. a message either directly to to, or on a channel. The default and RECOMMENDED
  1002. value is nil, ie to display. Set to non-nil to supress such messages."))
  1003.  
  1004.  
  1005. (make-variable-buffer-local
  1006.  (defvar irc-ignores nil
  1007.    "A list of NICKNAMES whose events will be ignored.
  1008. Messages or other actions (like joining a channel) generated by anyone in
  1009. the list will not be displayed or signalled.  This list is maintained with
  1010. the /IGNORE and /UNIGNORE commands."))
  1011.  
  1012.  
  1013. (make-variable-buffer-local
  1014.  (defvar irc-ignore-trunk nil
  1015.    "A trunk (for now an array of hash tables) of events and nicks to ignore."))
  1016.  
  1017.  
  1018. (defvar irc-map-keyboard-ISO-646-SE2-to-ISO-8859-1 nil
  1019.   "*Set to true if you want the sevenbit ISO 646-SE2 characters @[\]^`{|}~ to
  1020. be mapped into the corrosponding eightbith ISO 8859-1 characters when
  1021. being typed.
  1022.  
  1023. Set to nil to get no such mapping.
  1024.  
  1025. Set to neither t or nil if you want to get the mapping with the case
  1026. for ], [, \\ reversed, i.e. want to have the [ key treated as \344 and
  1027. the { key treated as \304.")
  1028.  
  1029.  
  1030. (defvar irc-max-history 40
  1031.   "*The maximum number of messages retained by irc-mode.
  1032. This limits messages sent, not messages received.  They are stored to be
  1033. easily recalled by irc-history-prev and irc-history-next (C-c C-p and C-c C-n
  1034. by default).")
  1035.  
  1036.  
  1037. (defvar irc-max-server-message-length 512
  1038.   "The maximum length of a message one can send to a server. This include the
  1039. trailing CRLF, so the \"real\" message length is 2 less.")
  1040.  
  1041.  
  1042. (defvar irc-maximum-size (* 64 1024)
  1043.   "*Maximum size that the *Kiwi-server* buffer can attain, in bytes.
  1044. The default value of 64KB represents an average of about 1500 lines, or roughly
  1045. 65 screens on a standard 24 line monitor. See also irc-minimum-size.")
  1046.  
  1047.  
  1048. (defvar irc-message-stamp 'private
  1049.   "*Mark messages received in IRC with the time of their arrival if non-nil.
  1050. If this is the symbol \"private\" or \"public\" then only messages of the
  1051. specified type are marked with the time.  WALL messages are always
  1052. time-stamped.")
  1053.  
  1054.  
  1055. (defvar irc-minimum-size (* 32 1024)
  1056.   "*Minimum size that the *Kiwi-server* buffer will get truncated to after
  1057. hitting the size in irc-maximum-size.")
  1058.  
  1059. (defvar irc-mode-hook nil
  1060.   "*Hook to run after starting irc-mode but before connecting to the server.")
  1061.  
  1062.  
  1063. (defvar irc-mode-map nil
  1064.   "The keymap which irc-mode uses.
  1065.  
  1066. Currently set to: \\{irc-mode-map}")
  1067.  
  1068.  
  1069. (make-variable-buffer-local
  1070.  (defvar irc-msg-info-post (if (boundp 'irc-msg-info-post)
  1071.                    irc-msg-info-post
  1072.                  "]")
  1073.    "*String to end an information message with."))
  1074.  
  1075.  
  1076. (make-variable-buffer-local
  1077.  (defvar irc-msg-info-pre (if (boundp 'irc-msg-info-pre)
  1078.                   irc-msg-info-pre
  1079.                 "[")
  1080.    "*String to start an information message with."))
  1081.  
  1082.  
  1083. (make-variable-buffer-local
  1084.  (defvar irc-msg-cont (if (boundp 'irc-msg-cont)
  1085.               irc-msg-cont
  1086.             (make-string 23 (string-to-char " ")))
  1087.    "*The string put first on a continued line."))
  1088.  
  1089.  
  1090. (make-variable-buffer-local
  1091.  (defvar irc-msg-priv (if (boundp 'irc-msg-priv)
  1092.               irc-msg-priv
  1093.             "==%%s%%%ds == ")
  1094.    "*The string put first on a line where a private message begins,
  1095. using TIME and SENDER strings, and EXTRA string."))
  1096.  
  1097.  
  1098. (make-variable-buffer-local
  1099.  (defvar irc-msg-public (if (boundp 'irc-msg-public)
  1100.                 irc-msg-public
  1101.               "-- %s%9s (on %s) -- ")
  1102.    "*The string put first on a line where a public message begins,
  1103. using TIME string, SENDER string and CHANNEL number"))
  1104.  
  1105.  
  1106. (make-variable-buffer-local
  1107.  (defvar irc-msg-sent (if (boundp 'irc-msg-sent)
  1108.               irc-msg-sent
  1109.             "(Message sent to %s)")
  1110.    "*Message displayed after sending a string to the server.
  1111. Contains TYPE (ie \"channel\" or \"person\") and RECEIVER (ie channel name or
  1112. users nick)."))
  1113.  
  1114.  
  1115. (make-variable-buffer-local
  1116.  (defvar irc-msg-wall (if (boundp 'irc-msg-wall)
  1117.               irc-msg-wall
  1118.             "##%s%s ## ")
  1119.    "*The string put first on a line where awrite all (wall) message begins,
  1120. using TIME and SENDER strings."))
  1121.  
  1122.  
  1123. (make-variable-buffer-local
  1124.  (defvar irc-multiple-leave-in-progress nil
  1125.    "Flag saying whether a multiple /LEAVE command is in progress, so that
  1126. irc-parse-channel shouldn't call irc-show-subscribed-channels."))
  1127.  
  1128.  
  1129. (make-variable-buffer-local
  1130.  (defvar irc-nick (or (getenv "IRCNICK") (user-login-name))
  1131.    "*The nickname with which to enter IRC.
  1132. The default value is set from your login name.  Using /NICKNAME changes it."))
  1133.  
  1134.  
  1135. (defconst irc-legal-session-name "^\\*Kiwi-\\([^/]+\\)/\\([0-9]+\\)\\*$"
  1136.   "A regexp describing a legal session-name. (See irc-get-*-from-session-name).
  1137. Two fields are extracted, the first being a host name, and the second a
  1138. TCP port number.")
  1139.  
  1140.  
  1141. (defvar irc-notify-interval 2
  1142.   "*How often to check for people. The time is in minutes.")
  1143.  
  1144.  
  1145. (defvar irc-oops "Oops ... please ignore that."
  1146.   "*The text to send to the original IRC message recipient when using /OOPS.")
  1147.  
  1148.  
  1149. (defconst irc-operator-alist
  1150.   '(("CONNECT" . "connect")        ; Establish links between servers
  1151.     ("KILL" . "kill")            ; Forcibly remove a user
  1152.     ("REHASH" . "rehash")        ; Reread irc.conf
  1153.     ("SQUIT" . "squit")        ; Quit links between servers
  1154.     ("WALL" . "wall"))        ; Send a message to everyone on IRC
  1155.   "As association list of commands which only an IRC Operator can use.
  1156. It is kept as a separate list so that regular users won't wonder how
  1157. come the commands don't work for them.")
  1158.  
  1159.  
  1160. (make-variable-buffer-local
  1161.  (defvar irc-output-character-set (if (boundp 'irc-output-character-set)
  1162.                       irc-output-character-set
  1163.                     (if irc-emacs-knows-ISO8859-1
  1164.                     'ISO-8859-1
  1165.                       'ASCII))
  1166.    "*Specifies whether the Emacs understands just ASCII (seven bit characters),
  1167. ISO-8859/1 (8 bits) or Kanjii (16 bits). The value is one of the following
  1168. atoms: ASCII ISO-8859-1 KANJII"))
  1169.  
  1170.  
  1171. (defvar irc-pop-on-signal 4
  1172.   "*An integer value means to display the *IRC* buffer when a signal is issued.
  1173. The number represents roughly how much of the Emacs screen to use when
  1174. popping up the IRC window if only one window is visible.  The reciprocal
  1175. is used, so a value of 1 causes the window to appear full-screen, 2 makes
  1176. the window half of the screen, 3 makes it one third, et cetera.  If the value
  1177. is not an integer then no attempt is made to show the *IRC* buffer if it
  1178. is not already visible.")
  1179.  
  1180.  
  1181. (make-variable-buffer-local
  1182.  (defvar irc-port (if (boundp 'irc-port)
  1183.               irc-port
  1184.             (let* ((p (getenv "IRCPORT"))
  1185.                (np (and p (string-to-int p))))
  1186.               (if (and (numberp np) (> np 0) (< np 16384)) np 6667)))
  1187.    "*The port on which the IRC server responds.
  1188. Many sites don't have irc as a named service (ie, it has no entry in
  1189. /etc/inetd.conf) so you might have to set this to a number; the most
  1190. common configuration is to have IRC respond on port 6667. If there is
  1191. an enviroment variable called IRCPORT and it's value is nummeric
  1192. between 1 and 16387, that value is used instead."))
  1193.  
  1194.  
  1195. (defvar irc-private-insert nil
  1196.   "*Hook to be used to insert private messages (PRIVMSG) sent to you.")
  1197.  
  1198.  
  1199. (defvar irc-processes nil
  1200.   "All currently open streams to irc-servers are kept in this list.
  1201. It is used so that the \"irc\" function knows whether to start a new process
  1202. by default.")
  1203.  
  1204.  
  1205. (defvar irc-public-insert nil
  1206.   "*Hook to be used to insert public messages (MSG) sent to channel.")
  1207.  
  1208.  
  1209. (make-variable-buffer-local
  1210.  (defvar irc-reply-count 0
  1211.    "Internal Kiwi variable to keep track of number of replies to /LINKS,
  1212. /NAMES, or /WHO."))
  1213.  
  1214.  
  1215. (make-variable-buffer-local
  1216.  (defvar irc-reply-count-interval 1
  1217.    "Internal Kiwi variable to keep track of how many seconds should
  1218. pass at least between each display of irc-reply-count when waiting
  1219. for the reply of a /LINKS, /NAMES, or /WHO to finnish."))
  1220.  
  1221.  
  1222. (make-variable-buffer-local
  1223.  (defvar irc-reply-count-time '(0 0)
  1224.    "Internal Kiwi variable to keep track of en irc-reply-count was displayed
  1225. last."))
  1226.  
  1227.  
  1228. (make-variable-buffer-local
  1229.  (defvar irc-scroll-step (if (boundp 'irc-scroll-step)
  1230.                  irc-scroll-step
  1231.                  nil)
  1232.    "*The scroll step used by irc-insert. Set to non-number to get
  1233. the nice automatic behaivour you get by default."))
  1234.  
  1235.  
  1236. (make-variable-buffer-local
  1237.  (defvar irc-server (if (boundp 'irc-server)
  1238.             irc-server
  1239.               (or (getenv "IRCSERVER") "irc.ludd.luth.se"))
  1240.    "*The name of the internet host running the IRC daemon.
  1241. IRC servers generally restrict which machines can maintain connetions with
  1242. them, so you'll probably have to find a server in your local domain.
  1243. Initiated from enviroment variable IRCSERVER."))
  1244.  
  1245.  
  1246. (make-variable-buffer-local
  1247.  (defvar irc-show-japanese-characters nil
  1248.    "*If nil, replace Kanjii characters in text by a marker like \"Old Kanjii\"
  1249. followed by a list of integers denoting the 16 bit values of the characters.
  1250. If t, enter the text \"as is\" e.i., keep even the ESCape characters.
  1251. If neither nil nor t, enter the text in \"raw\" mode e.i., replace the ESCapes
  1252. by ^[ and insert the resulting text in the buffer.
  1253. The default is nil."))
  1254.  
  1255.  
  1256. (make-variable-buffer-local
  1257.  (defvar irc-signals '((backtalk t)
  1258.                (detect nil)
  1259.                (invite t)
  1260.                (join nil)
  1261.                (nick nil)
  1262.                (private t)
  1263.                (topic nil)
  1264.                (wall t)
  1265.                        (public nil)
  1266.                (user nil))
  1267.    "Events in IRC that should get signalled when they occur.
  1268. Generally the signal is an audible beep.  The value of irc-signals is an
  1269. association list of events recognized by irc-mode and is maintained with
  1270. the /SIGNAL command."))
  1271.  
  1272.  
  1273. (defvar irc-spacebar-pages t
  1274.   "*When this variable is non-nil, the following keys are in effect when
  1275. point is in the output region.
  1276.  
  1277. SPC      scroll-forward    DEL           scroll-backward
  1278. TAB      previous-line     LFD or RET    next-line")
  1279.  
  1280.  
  1281. (defvar irc-time-stamp 5
  1282.   "*How often to insert a time-stamp into *IRC* buffers.
  1283. The first time one is based from the hour the IRC process was started so that
  1284. values which divide evenly into 60 minutes (like the default of 10) will split
  1285. the hour evenly (as in 13:10, 13:20, 13:30, et cetera).  To disable the
  1286. time-stamping set this variable to 0.  This can be set with the /STAMP command.
  1287.  
  1288. The accuracy of the time-stamping can be improved greatly by running
  1289. M-x display-time; with default settings this guarantees that Emacs will have
  1290. some sort of predictable activity every minute.  If display-time is not running
  1291. and the IRC session is idle, the time-stamp can be up to two minutes late.")
  1292.  
  1293. (defvar irc-translation-table-incoming
  1294.   (cond
  1295.    ((and (boundp 'irc-translation-table-incoming)
  1296.      (arrayp irc-translation-table-incoming)
  1297.      (= 256 (length irc-translation-table-incoming)))
  1298.     irc-translation-table-incoming)
  1299.    ((and (boundp 'irc-translation-table-incoming)
  1300.      (symbolp irc-translation-table-incoming)
  1301.      (eq 'scandinavian irc-translation-table-incoming))
  1302.     irc-translation-table-incoming-scandinavian7)
  1303.    (t nil)
  1304.    (t 'scandinavian7))            ;Obsolete default
  1305.   "*Translation table for incoming characters.
  1306. If non-nil, single characters are translated one by one according to
  1307. this table. The table consists of a 256 elements long array, where each
  1308. element is either a string or nil. If the element is nil, the character
  1309. with the corresponding code is dropped, if the element is a string, the
  1310. string is inserted instead of the character.")
  1311.  
  1312. (defvar irc-translation-table-incoming-scandinavian7
  1313.   '["^@"                ;000
  1314.     "^A"                ;001
  1315.     ""                    ;002    ircII kludge
  1316.     "^C"                ;003
  1317.     "^D"                ;004
  1318.     "^E"                ;005
  1319.     "^F"                ;006
  1320.     "^G"                ;007
  1321.     "^H"                ;010
  1322.     "^I"                ;011
  1323.     "^J\n"                ;012
  1324.     "^K"                ;013
  1325.     "^L"                ;014
  1326.     "^M"                ;015
  1327.     "^N"                ;016
  1328.     ""                    ;017    ircII kludge
  1329.     "^P"                ;020
  1330.     "^Q"                ;021
  1331.     "^R"                ;022
  1332.     "^S"                ;023
  1333.     "^T"                ;024
  1334.     "^U"                ;025
  1335.     ""                    ;026    ircII kludge
  1336.     "^W"                ;027
  1337.     "^X"                ;030
  1338.     "^Y"                ;031
  1339.     "^Z"                ;032
  1340.     "^["                ;033
  1341.     "^\\"                ;034
  1342.     "^]"                ;035
  1343.     "^^"                ;036
  1344.     ""                    ;037    ircII kludge
  1345.     " "                    ;040
  1346.     "!"                    ;041
  1347.     "\""                ;042
  1348.     "#"                    ;043
  1349.     "$"                    ;044
  1350.     "%%"                ;045    Need %% to not disturb format.
  1351.     "&"                    ;046
  1352.     "'"                    ;047
  1353.     "("                    ;050
  1354.     ")"                    ;051
  1355.     "*"                    ;052
  1356.     "+"                    ;053
  1357.     ","                    ;054
  1358.     "-"                    ;055
  1359.     "."                    ;056
  1360.     "/"                    ;057
  1361.     "0"                    ;060
  1362.     "1"                    ;061
  1363.     "2"                    ;062
  1364.     "3"                    ;063
  1365.     "4"                    ;064
  1366.     "5"                    ;065
  1367.     "6"                    ;066
  1368.     "7"                    ;067
  1369.     "8"                    ;070
  1370.     "9"                    ;071
  1371.     ":"                    ;072
  1372.     ";"                    ;073
  1373.     "<"                    ;074
  1374.     "="                    ;075
  1375.     ">"                    ;076
  1376.     "?"                    ;077
  1377.     "@"                    ;100
  1378.     "A"                    ;101
  1379.     "B"                    ;102
  1380.     "C"                    ;103
  1381.     "D"                    ;104
  1382.     "E"                    ;105
  1383.     "F"                    ;106
  1384.     "G"                    ;107
  1385.     "H"                    ;110
  1386.     "I"                    ;111
  1387.     "J"                    ;112
  1388.     "K"                    ;113
  1389.     "L"                    ;114
  1390.     "M"                    ;115
  1391.     "N"                    ;116
  1392.     "O"                    ;117
  1393.     "P"                    ;120
  1394.     "Q"                    ;121
  1395.     "R"                    ;122
  1396.     "S"                    ;123
  1397.     "T"                    ;124
  1398.     "U"                    ;125
  1399.     "V"                    ;126
  1400.     "W"                    ;127
  1401.     "X"                    ;130
  1402.     "Y"                    ;131
  1403.     "Z"                    ;132
  1404.     "["                    ;133
  1405.     "\\"                ;134
  1406.     "]"                    ;135
  1407.     "^"                    ;136
  1408.     "_"                    ;137
  1409.     "`"                    ;140
  1410.     "a"                    ;141
  1411.     "b"                    ;142
  1412.     "c"                    ;143
  1413.     "d"                    ;144
  1414.     "e"                    ;145
  1415.     "f"                    ;146
  1416.     "g"                    ;147
  1417.     "h"                    ;150
  1418.     "i"                    ;151
  1419.     "j"                    ;152
  1420.     "k"                    ;153
  1421.     "l"                    ;154
  1422.     "m"                    ;155
  1423.     "n"                    ;156
  1424.     "o"                    ;157
  1425.     "p"                    ;160
  1426.     "q"                    ;161
  1427.     "r"                    ;162
  1428.     "s"                    ;163
  1429.     "t"                    ;164
  1430.     "u"                    ;165
  1431.     "v"                    ;166
  1432.     "w"                    ;167
  1433.     "x"                    ;170
  1434.     "y"                    ;171
  1435.     "z"                    ;172
  1436.     "{"                    ;173
  1437.     "|"                    ;174
  1438.     "}"                    ;175
  1439.     "~"                    ;176
  1440.     "^?"                ;177
  1441.     "\200"                ;200
  1442.     "~"                    ;201 MSDOS
  1443.     "\202"                ;202
  1444.     "\203"                ;203
  1445.     "{"                    ;204 MSDOS
  1446.     "\205"                ;205
  1447.     "}"                    ;206 MSDOS
  1448.     "\207"                ;207
  1449.     "\210"                ;210
  1450.     "\211"                ;211
  1451.     "\212"                ;212
  1452.     "\213"                ;213
  1453.     "\214"                ;214
  1454.     "\215"                ;215
  1455.     "["                    ;216 MSDOS
  1456.     "]"                    ;217 MSDOS
  1457.     "\220"                ;220
  1458.     "\221"                ;221
  1459.     "\222"                ;222
  1460.     "\223"                ;223
  1461.     "|"                    ;224 MSDOS
  1462.     "\225"                ;225
  1463.     "\226"                ;226
  1464.     "\227"                ;227
  1465.     "\230"                ;230
  1466.     "\\"                ;231 MSDOS
  1467.     "^"                    ;232 MSDOS
  1468.     "\233"                ;233
  1469.     "\234"                ;234
  1470.     "\235"                ;235
  1471.     "\236"                ;236
  1472.     "\237"                ;237
  1473.     " "                    ;240
  1474.     "!"                    ;241
  1475.     "c"                    ;242
  1476.     "#"                    ;243
  1477.     "$"                    ;244
  1478.     "Y"                    ;245
  1479.     "|"                    ;246
  1480.     "$"                    ;247
  1481.     "\""                ;250
  1482.     "c"                    ;251
  1483.     "+"                    ;252
  1484.     "<<"                ;253
  1485.     "!"                    ;254
  1486.     "-"                    ;255
  1487.     "R"                    ;256
  1488.     "~"                    ;257
  1489.     "C"                    ;260
  1490.     "+"                    ;261
  1491.     "2"                    ;262
  1492.     "3"                    ;263
  1493.     "'"                    ;264
  1494.     "u"                    ;265
  1495.     "$"                    ;266
  1496.     "-"                    ;267
  1497.     ","                    ;270
  1498.     "1"                    ;271
  1499.     "0"                    ;272
  1500.     ">>"                ;273
  1501.     "?"                    ;274
  1502.     "?"                    ;275
  1503.     "?"                    ;276
  1504.     "?"                    ;277
  1505.     "A"                    ;300
  1506.     "A"                    ;301
  1507.     "A"                    ;302
  1508.     "A"                    ;303
  1509.     "["                    ;304
  1510.     "]"                    ;305
  1511.     "["                    ;306
  1512.     "C"                    ;307
  1513.     "E"                    ;310
  1514.     "@"                    ;311
  1515.     "E"                    ;312
  1516.     "E"                    ;313
  1517.     "I"                    ;314
  1518.     "I"                    ;315
  1519.     "I"                    ;316
  1520.     "I"                    ;317
  1521.     "D"                    ;320
  1522.     "N"                    ;321
  1523.     "O"                    ;322
  1524.     "O"                    ;323
  1525.     "O"                    ;324
  1526.     "O"                    ;325
  1527.     "\\"                ;326
  1528.     "*"                    ;327
  1529.     "\\"                ;330
  1530.     "U"                    ;331
  1531.     "U"                    ;332
  1532.     "U"                    ;333
  1533.     "^"                    ;334
  1534.     "Y"                    ;335
  1535.     "T"                    ;336
  1536.     "ss"                ;337
  1537.     "a"                    ;340
  1538.     "a"                    ;341
  1539.     "a"                    ;342
  1540.     "a"                    ;343
  1541.     "{"                    ;344
  1542.     "}"                    ;345
  1543.     "{"                    ;346
  1544.     "c"                    ;347
  1545.     "e"                    ;350
  1546.     "`"                    ;351
  1547.     "e"                    ;352
  1548.     "e"                    ;353
  1549.     "i"                    ;354
  1550.     "i"                    ;355
  1551.     "i"                    ;356
  1552.     "i"                    ;357
  1553.     "d"                    ;360
  1554.     "n"                    ;361
  1555.     "o"                    ;362
  1556.     "o"                    ;363
  1557.     "o"                    ;364
  1558.     "o"                    ;365
  1559.     "|"                    ;366
  1560.     "/"                    ;367
  1561.     "|"                    ;370
  1562.     "u"                    ;371
  1563.     "u"                    ;372
  1564.     "u"                    ;373
  1565.     "~"                    ;374
  1566.     "y"                    ;375
  1567.     "t"                    ;376
  1568.     "y"]                ;377
  1569.   "*Translation table for incoming characters to translate from ISO 8859-1
  1570. to SIS E47. Also handles some MSDOS characters.")
  1571.  
  1572.  
  1573. (defvar irc-translation-table-incoming-scandinavian8
  1574.   '["^@"                ;000
  1575.     "^A"                ;001
  1576.     ""                    ;002    ircII kludge
  1577.     "^C"                ;003
  1578.     "^D"                ;004
  1579.     "^E"                ;005
  1580.     "^F"                ;006
  1581.     "^G"                ;007
  1582.     "^H"                ;010
  1583.     "^I"                ;011
  1584.     "^J\n"                ;012
  1585.     "^K"                ;013
  1586.     "^L"                ;014
  1587.     "^M"                ;015
  1588.     "^N"                ;016
  1589.     ""                    ;017    ircII kludge
  1590.     "^P"                ;020
  1591.     "^Q"                ;021
  1592.     "^R"                ;022
  1593.     "^S"                ;023
  1594.     "^T"                ;024
  1595.     "^U"                ;025
  1596.     ""                    ;026    ircII kludge
  1597.     "^W"                ;027
  1598.     "^X"                ;030
  1599.     "^Y"                ;031
  1600.     "^Z"                ;032
  1601.     "^["                ;033
  1602.     "^\\"                ;034
  1603.     "^]"                ;035
  1604.     "^^"                ;036
  1605.     ""                    ;037    ircII kludge
  1606.     " "                    ;040
  1607.     "!"                    ;041
  1608.     "\""                ;042
  1609.     "#"                    ;043
  1610.     "$"                    ;044
  1611.     "%%"                ;045    Need %% to not disturb format.
  1612.     "&"                    ;046
  1613.     "'"                    ;047
  1614.     "("                    ;050
  1615.     ")"                    ;051
  1616.     "*"                    ;052
  1617.     "+"                    ;053
  1618.     ","                    ;054
  1619.     "-"                    ;055
  1620.     "."                    ;056
  1621.     "/"                    ;057
  1622.     "0"                    ;060
  1623.     "1"                    ;061
  1624.     "2"                    ;062
  1625.     "3"                    ;063
  1626.     "4"                    ;064
  1627.     "5"                    ;065
  1628.     "6"                    ;066
  1629.     "7"                    ;067
  1630.     "8"                    ;070
  1631.     "9"                    ;071
  1632.     ":"                    ;072
  1633.     ";"                    ;073
  1634.     "<"                    ;074
  1635.     "="                    ;075
  1636.     ">"                    ;076
  1637.     "?"                    ;077
  1638.     "\311"                ;100
  1639.     "A"                    ;101
  1640.     "B"                    ;102
  1641.     "C"                    ;103
  1642.     "D"                    ;104
  1643.     "E"                    ;105
  1644.     "F"                    ;106
  1645.     "G"                    ;107
  1646.     "H"                    ;110
  1647.     "I"                    ;111
  1648.     "J"                    ;112
  1649.     "K"                    ;113
  1650.     "L"                    ;114
  1651.     "M"                    ;115
  1652.     "N"                    ;116
  1653.     "O"                    ;117
  1654.     "P"                    ;120
  1655.     "Q"                    ;121
  1656.     "R"                    ;122
  1657.     "S"                    ;123
  1658.     "T"                    ;124
  1659.     "U"                    ;125
  1660.     "V"                    ;126
  1661.     "W"                    ;127
  1662.     "X"                    ;130
  1663.     "Y"                    ;131
  1664.     "Z"                    ;132
  1665.     "\304"                ;133
  1666.     "\326"                ;134
  1667.     "\305"                ;135
  1668.     "\334"                ;136
  1669.     "_"                    ;137
  1670.     "\351"                ;140
  1671.     "a"                    ;141
  1672.     "b"                    ;142
  1673.     "c"                    ;143
  1674.     "d"                    ;144
  1675.     "e"                    ;145
  1676.     "f"                    ;146
  1677.     "g"                    ;147
  1678.     "h"                    ;150
  1679.     "i"                    ;151
  1680.     "j"                    ;152
  1681.     "k"                    ;153
  1682.     "l"                    ;154
  1683.     "m"                    ;155
  1684.     "n"                    ;156
  1685.     "o"                    ;157
  1686.     "p"                    ;160
  1687.     "q"                    ;161
  1688.     "r"                    ;162
  1689.     "s"                    ;163
  1690.     "t"                    ;164
  1691.     "u"                    ;165
  1692.     "v"                    ;166
  1693.     "w"                    ;167
  1694.     "x"                    ;170
  1695.     "y"                    ;171
  1696.     "z"                    ;172
  1697.     "\344"                ;173
  1698.     "\366"                ;174
  1699.     "\345"                ;175
  1700.     "\374"                ;176
  1701.     "^?"                ;177
  1702.     "\200"                ;200
  1703.     "\374"                ;201 MSDOS
  1704.     "\202"                ;202
  1705.     "\203"                ;203
  1706.     "\344"                ;204 MSDOS
  1707.     "\205"                ;205
  1708.     "\345"                ;206 MSDOS
  1709.     "\207"                ;207
  1710.     "\210"                ;210
  1711.     "\211"                ;211
  1712.     "\212"                ;212
  1713.     "\213"                ;213
  1714.     "\214"                ;214
  1715.     "\215"                ;215
  1716.     "\305"                ;216 MSDOS
  1717.     "\304"                ;217 MSDOS
  1718.     "\220"                ;220
  1719.     "\221"                ;221
  1720.     "\222"                ;222
  1721.     "\223"                ;223
  1722.     "\366"                ;224 MSDOS
  1723.     "\225"                ;225
  1724.     "\226"                ;226
  1725.     "\227"                ;227
  1726.     "\230"                ;230
  1727.     "\326"                ;231 MSDOS
  1728.     "\334"                ;232 MSDOS
  1729.     "\233"                ;233
  1730.     "\234"                ;234
  1731.     "\235"                ;235
  1732.     "\236"                ;236
  1733.     "\237"                ;237
  1734.     "\240"                ;240
  1735.     "\241"                ;241
  1736.     "\242"                ;242
  1737.     "\243"                ;243
  1738.     "\244"                ;244
  1739.     "\245"                ;245
  1740.     "\246"                ;246
  1741.     "\247"                ;247
  1742.     "\250"                ;250
  1743.     "\251"                ;251
  1744.     "\252"                ;252
  1745.     "\253"                ;253
  1746.     "\254"                ;254
  1747.     "\255"                ;255
  1748.     "\256"                ;256
  1749.     "\257"                ;257
  1750.     "\260"                ;260
  1751.     "\261"                ;261
  1752.     "\262"                ;262
  1753.     "\263"                ;263
  1754.     "\264"                ;264
  1755.     "\265"                ;265
  1756.     "\266"                ;266
  1757.     "\267"                ;267
  1758.     "\270"                ;270
  1759.     "\271"                ;271
  1760.     "\272"                ;272
  1761.     "\273"                ;273
  1762.     "\274"                ;274
  1763.     "\275"                ;275
  1764.     "\276"                ;276
  1765.     "\277"                ;277
  1766.     "\300"                ;300
  1767.     "\301"                ;301
  1768.     "\302"                ;302
  1769.     "\303"                ;303
  1770.     "\304"                ;304
  1771.     "\305"                ;305
  1772.     "\306"                ;306
  1773.     "\307"                ;307
  1774.     "\310"                ;310
  1775.     "\311"                ;311
  1776.     "\312"                ;312
  1777.     "\313"                ;313
  1778.     "\314"                ;314
  1779.     "\315"                ;315
  1780.     "\316"                ;316
  1781.     "\317"                ;317
  1782.     "\320"                ;320
  1783.     "\321"                ;321
  1784.     "\322"                ;322
  1785.     "\323"                ;323
  1786.     "\324"                ;324
  1787.     "\325"                ;325
  1788.     "\326"                ;326
  1789.     "\327"                ;327
  1790.     "\330"                ;330
  1791.     "\331"                ;331
  1792.     "\332"                ;332
  1793.     "\333"                ;333
  1794.     "\334"                ;334
  1795.     "\335"                ;335
  1796.     "\336"                ;336
  1797.     "\337"                ;337
  1798.     "\340"                ;340
  1799.     "\341"                ;341
  1800.     "\342"                ;342
  1801.     "\343"                ;343
  1802.     "\344"                ;344
  1803.     "\345"                ;345
  1804.     "\346"                ;346
  1805.     "\347"                ;347
  1806.     "\350"                ;350
  1807.     "\351"                ;351
  1808.     "\352"                ;352
  1809.     "\353"                ;353
  1810.     "\354"                ;354
  1811.     "\355"                ;355
  1812.     "\356"                ;356
  1813.     "\357"                ;357
  1814.     "\360"                ;360
  1815.     "\361"                ;361
  1816.     "\362"                ;362
  1817.     "\363"                ;363
  1818.     "\364"                ;364
  1819.     "\365"                ;365
  1820.     "\366"                ;366
  1821.     "\367"                ;367
  1822.     "\370"                ;370
  1823.     "\371"                ;371
  1824.     "\372"                ;372
  1825.     "\373"                ;373
  1826.     "\374"                ;374
  1827.     "\375"                ;375
  1828.     "\376"                ;376
  1829.     "\377"]                ;377
  1830.   "*Translation table for incoming characters to translate from SIS E47
  1831. to ISO 8859-1. Also handles some MSDOS characters.")
  1832.  
  1833.  
  1834. (make-variable-buffer-local
  1835.  (defvar irc-userinfo (if (boundp 'irc-userinfo)
  1836.               irc-userinfo
  1837.               nil)
  1838.    "*If non-nil, a user settable string to be replied with when the client is
  1839. queried by some other user."))
  1840.  
  1841.  
  1842.  
  1843.  
  1844. ;;; Macros
  1845. ;;;
  1846. (defmacro subfield (str n)
  1847.   "Return a substring of STR. The substring is field N, as used in the latest
  1848. string-match."
  1849.   (` (if (and (numberp (match-beginning (, n)))
  1850.           (numberp (match-end (, n))))
  1851.      (substring (, str) (match-beginning (, n)) (match-end (, n)))
  1852.      "")))
  1853.  
  1854.  
  1855. ;;; Handle host names.
  1856. ;;;
  1857. ;;; First a constant regular expression string matching only host names.
  1858. ;;;
  1859. (defconst irc-hostname "^[A-Za-z][A-Za-z0-9.-.---]*$"
  1860.   "A regexp matching a string if and only if the string is a hostname.")
  1861.  
  1862.  
  1863. (defconst irc-hostname-complement "\\(^\\.\\|\\.$\\)")
  1864.  
  1865.  
  1866. ;;; See RFC 952
  1867. (defconst irc-hostname-chars '(?a ?b ?c ?d ?e ?f ?g ?h ?i ?j ?k ?l ?m
  1868.                    ?n ?o ?p ?q ?r ?s ?t ?u ?v ?w ?x ?y ?z
  1869.                    ?A ?B ?C ?D ?E ?F ?G ?H ?I ?J ?K ?L ?M
  1870.                    ?N ?O ?P ?Q ?R ?S ?T ?U ?V ?W ?X ?Y ?Z
  1871.                    ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9 ?- ?.))
  1872.  
  1873.  
  1874. (defun irc-is-hostname (name)
  1875.   "Returns t if the NAME is a hostname, nil else.
  1876. This functions is more paranoid (Hello RFC 952!) than the IRC servers."
  1877.   (and (stringp name)
  1878.        (not (not (and (string-match irc-hostname name)
  1879.               (string-match "\\." name)
  1880.               (not (string-match (regexp-quote irc-hostname-complement)
  1881.                      name)))))))
  1882.  
  1883.  
  1884. (defun irc-is-nickname (name)
  1885.   "Returns t if the NAME is a valid nick name in IRC."
  1886.   (and (numberp (string-match (concat "^[]A-Z[\\^_a-z{|}~`]"
  1887.                       "[]A-Z0-9[\\_^a-z{|}~`-`---]*$")
  1888.                   name))
  1889.        (not (numberp (string-match "\n" name)))))
  1890.  
  1891.  
  1892. (defun irc-is-channelname (name)
  1893.   "Returns t if NAME is a valid channel identification."
  1894.   (or (and (irc-server-has-multijoinable-channels)
  1895.        (or (= ?# (aref name 0))
  1896.            (= ?& (aref name 0)))
  1897.        (irc-is-named-channel name))
  1898.       (and (irc-server-has-non-numeric-channel-names)
  1899.        (= ?+ (aref name 0))
  1900.        (irc-is-named-channel name))
  1901.       (and (numberp (string-match "^ *-?[0-9]+ *$" name))
  1902.        (irc-is-named-channel (concat "+" name)))))
  1903.  
  1904.  
  1905. (defun irc-is-broadcastname (name)
  1906.   "Return t if NAME is a valid broadcast address, ie is a server- or hostname
  1907. containing wildcards prepended by $ (server) or # (host). Broadcasts came at
  1908. the same time as #channels."
  1909.   (and (irc-server-has-multijoinable-channels)
  1910.        (or (= ?$ (aref name 0)) (= ?# (aref name 0)))))
  1911.  
  1912.  
  1913. (defun irc-is-named-channel (name)
  1914.   "Return t if NAME is a valid nummeric channel identification."
  1915.   (or (and (irc-server-has-multijoinable-channels)
  1916.        (numberp (string-match "^[&#+][]/a-zA-Z#+{}[^~()*!@.,0-9_-_---]*$"
  1917.                   name)))
  1918.       (and (irc-server-has-non-numeric-channel-names)
  1919.        (numberp (string-match "^+[]/a-zA-Z+{}[^~()*!@.,0-9_-_---]*$"
  1920.                   name)))))
  1921.  
  1922.  
  1923. (defun irc-is-multijoinable-channel (channel)
  1924.   "True if CHANNEL is a multijoinable channel, ie a channel one can listen
  1925. to along several other multijoinable channels. This feature was introduced in
  1926. server version 2.6."
  1927.   (and (stringp channel)
  1928.        (or (= (aref channel 0) ?#)
  1929.        (= (aref channel 0) ?&))))
  1930.  
  1931.  
  1932. (defun irc-is-receiver (obj)
  1933.   "True if STR could be either a nick or channel name.
  1934. If user is an enabled irc operator, broadcast addresses are OK too."
  1935.   (or (string= "*" obj)
  1936.       (irc-is-nickname obj)
  1937.       (and (string-match "^\\([^@]+\\)@\\([^@]+\\)$" obj)
  1938.        (let ((pre (subfield obj 1))
  1939.          (post (subfield obj 2)))
  1940.          (and (irc-is-nickname pre)
  1941.           (irc-is-hostname post))))
  1942.       (irc-is-channelname obj)
  1943.       (and irc-operator (irc-is-broadcastname obj))))
  1944.  
  1945.  
  1946. (defun irc-format-channel (channel &optional width)
  1947.   "Format a CHANNEL identification (name, number or * (ie private)) to be left
  1948. justified in a 15 character wide field. Ie make what the format string %-15s
  1949. SHOULD do. If the channel equals irc-channel, ie the current channel, it is
  1950. postpended with a %.
  1951.  
  1952. Arguments are a string with the channel ID, and optional a number saying how
  1953. wide the resulting string should be at least. If none is given, 15 is used as
  1954. the default."
  1955.   (let* ((w (max 0 (or (and (numberp width) width) 15)))
  1956.      (isnamed (irc-is-named-channel channel))
  1957.      (c (cond ((string= "*" channel) "Private")
  1958.           ((string= channel irc-channel) (concat channel "%"))
  1959.           (t channel)))
  1960.      (rpad (make-string (max 0 (- w (length c))) ? )))
  1961.     (concat c rpad)))
  1962.  
  1963.  
  1964. (defun irc-extract-hostname (s)
  1965.   "Extract the hostname part from the STRING, ignoring a trailing comment.
  1966. The string doesn't start with a host name, return nil."
  1967.   (let ((i 0)
  1968.     (len (length s)))
  1969.     (while (and (< i len)
  1970.         (memq (string-to-char (substring s i))
  1971.               irc-hostname-chars))
  1972.       (setq i (1+ i)))
  1973.     (if (irc-is-hostname (substring s 0 i))
  1974.     (substring s 0 i)
  1975.     nil)))
  1976.  
  1977.  
  1978. (defun irc-extract-hosts (path)
  1979.   "Extract and remember the different hosts mentioned in the path string,
  1980. \"h1!h2!h3!x\" where x is either a host or a nick name."
  1981.   (let* ((first-host (irc-extract-hostname path))
  1982.      (first-! (string-match "!" path))
  1983.      (len (length first-host)))
  1984.     (cond ((string= path "") nil)
  1985.       ((and (not first-host) first-!)
  1986.        (irc-extract-hosts (substring path (1+ first-!))))
  1987.       ((not first-host) nil)
  1988.       (t (irc-extract-hosts (substring path len))))))
  1989.  
  1990. ;; keymap
  1991. ;; what i tend to like for keys might be very different from what most people
  1992. ;; find useful; in fact i tend to type the /COMMANDs more than use any bindings
  1993.  
  1994. ;; there are more things bound here just so people can see the different
  1995. ;; things available to them
  1996. (or irc-mode-map
  1997.     (progn
  1998.       (setq irc-mode-map (make-keymap))
  1999.       (define-key irc-mode-map "\C-j"        'irc-process-input)
  2000.       (define-key irc-mode-map "\C-m"        'irc-process-input)
  2001.       (define-key irc-mode-map "\C-i"        'irc-tab)
  2002.       (define-key irc-mode-map "\C-c\C-a"    'irc-execute-alias)
  2003.       (define-key irc-mode-map "\C-c\C-c"    'irc-execute-names)
  2004.       (define-key irc-mode-map "\C-c\C-h"    'irc-execute-help)
  2005.       (define-key irc-mode-map "\C-c\C-i"    'irc-execute-invite)
  2006.       (define-key irc-mode-map "\C-c\C-j"    'irc-execute-join)
  2007.       (define-key irc-mode-map "\C-c\C-k"    'irc-execute-kill)
  2008.       (define-key irc-mode-map "\C-c\C-l"    'irc-execute-list)
  2009.       (define-key irc-mode-map "\C-c\C-m"    'irc-history-menu)
  2010.       (define-key irc-mode-map "\C-c\C-n"    'irc-history-next)
  2011.       (define-key irc-mode-map "\C-c\C-o"    'irc-execute-oops)
  2012.       (define-key irc-mode-map "\C-c\C-p"    'irc-history-prev)
  2013.       (define-key irc-mode-map "\C-c\C-q"    'irc-execute-quote)
  2014.       (define-key irc-mode-map "\C-c\C-r"    'irc-execute-redirect)
  2015.       (define-key irc-mode-map "\C-c\C-s"    'irc-execute-squit)
  2016.       (define-key irc-mode-map "\C-c\C-t"    'irc-execute-topic)
  2017.       (define-key irc-mode-map "\C-c\C-u"    'irc-kill-input)
  2018.       (define-key irc-mode-map "\C-c\C-v"    'irc-execute-version)
  2019.       (define-key irc-mode-map "\C-c\C-w"    'irc-execute-who)
  2020.       (define-key irc-mode-map "\C-c\C-?"    'irc-kill-input)
  2021.       ;; it's nice to bind to a key while in development, but regular users
  2022.       ;; wonder about it in production.
  2023.       ;; (define-key irc-mode-map "\C-c " 'irc-pong)
  2024.       (define-key irc-mode-map "\C-c#" 'irc-execute-lusers)
  2025.       (define-key irc-mode-map "\C-c=" 'irc-execute-memberships)
  2026.       (define-key irc-mode-map "\C-c?" 'describe-mode)
  2027.       (define-key irc-mode-map "\C-ca" 'irc-execute-admin)
  2028.       (define-key irc-mode-map "\C-cc" 'irc-execute-connect)
  2029.       (define-key irc-mode-map "\C-cf" 'irc-execute-finger)
  2030.       (define-key irc-mode-map "\C-ci" 'irc-execute-info)
  2031.       (define-key irc-mode-map "\C-ck" 'irc-execute-quit)
  2032.       (define-key irc-mode-map "\C-cl" 'irc-execute-links)
  2033.       (define-key irc-mode-map "\C-cm" 'irc-execute-mode)
  2034.       (define-key irc-mode-map "\C-cn" 'irc-execute-news)
  2035.       (define-key irc-mode-map "\C-co" 'irc-execute-oper)
  2036.       (define-key irc-mode-map "\C-cp" 'irc-yank-prev-command)
  2037.       (define-key irc-mode-map "\C-cq"    'irc-execute-leave)
  2038.       (define-key irc-mode-map "\C-cs" 'irc-execute-summon)
  2039.       (define-key irc-mode-map "\C-ct" 'irc-execute-trace)
  2040.       (define-key irc-mode-map "\C-cu" 'irc-execute-users)
  2041.       (define-key irc-mode-map "\C-cv" 'irc-version)
  2042.       (define-key irc-mode-map "\C-cw" 'irc-execute-whois)
  2043.       (define-key irc-mode-map "\C-?"  'irc-del-backward-char)
  2044.       ;; make any self-inserting keys call irc-self-insert
  2045.       (mapcar (function
  2046.                (lambda (key)
  2047.         (define-key irc-mode-map key 'irc-self-insert)))
  2048.           (append
  2049.            (where-is-internal 'self-insert-command nil nil)
  2050.            '(" " "!" "\"" "#" "$" "%" "&" "'"
  2051.          "(" ")" "*" "+" "," "-" "." "/"
  2052.          "0" "1" "2" "3" "4" "5" "6" "7"
  2053.          "8" "9" ":" ";" "<" "=" ">" "?"
  2054.          "@" "A" "B" "C" "D" "E" "F" "G"
  2055.          "H" "I" "J" "K" "L" "M" "N" "O"
  2056.          "P" "Q" "R" "S" "T" "U" "V" "W"
  2057.          "X" "Y" "Z" "[" "\\" "]" "^" "_"
  2058.          "`" "a" "b" "c" "d" "e" "f" "g"
  2059.          "h" "i" "j" "k" "l" "m" "n" "o"
  2060.          "p" "q" "r" "s" "t" "u" "v" "w"
  2061.          "x" "y" "z" "{" "|" "}" "~")))))
  2062.  
  2063. ;; filters (mostly irc-parse-*)
  2064. ;; Filtering of server messages from reception to insertion in the buffer
  2065. ;; are all done on this page.  In particular, if a new server message has
  2066. ;; to be dealt with, it should be added in the irc-parse-server-msg function.
  2067. (defun irc-filter (proc str)
  2068.   "Filtering procedure for IRC server messages.
  2069. It waits until everything up to a newline is accumulated before handing the
  2070. string over to irc-parse-server-msg to be processed.  If irc-pop-on-signal
  2071. is an integer and a signal is issued then the *IRC* buffer will be displayed.
  2072.  
  2073. Unless irc-maximum-size is zero or negative, truncate the Kiwi buffer to
  2074. be no larger than irc-maximum-size. If it is larger, truncate it to
  2075. the size irc-minimum-size."
  2076.   (let* ((ibuf (process-buffer proc))
  2077.          bell irc-mark-to-point new-point old-irc-mark win)
  2078.     (save-excursion
  2079.       (set-buffer ibuf)
  2080.       ;; still can't tell why i need this; sure, i probably change point
  2081.       ;; in ibuf.  but so what?  set-window-point should clean up after that.
  2082.       ;; it works with it though and not without it, so it stays.
  2083.       (save-excursion 
  2084.     ;; trim buffer if needed
  2085.     (if (> irc-maximum-size 0)
  2086.         (irc-truncate-buffer irc-maximum-size irc-minimum-size))
  2087.         (setq irc-mark-to-point   ; so we can restore relative position later
  2088.               (- (point) (setq old-irc-mark (goto-char irc-mark)))
  2089.               ;; just glue str to the end of any partial line that's there
  2090.               irc-scratch (concat irc-scratch str))
  2091.         ;; see if it is time for a message
  2092.         (irc-check-time)
  2093.         (while (string-match "\n" irc-scratch) ; do as many lines as possible
  2094.           ;; first use irc-scratch for the dp returned by irc-parse-server-msg
  2095.           (setq irc-scratch (irc-parse-server-msg irc-scratch)
  2096.         bell (cdr irc-scratch) ; issue a signal?
  2097.                 ;; now irc-scratch is what it was, minus the line parsed
  2098.                 irc-scratch (car irc-scratch))
  2099.           (if bell
  2100.           (progn
  2101.         ;; issue a signal; no need to trash someone's kbd-macro over it
  2102.         (ding 'no-terminate)
  2103.         (irc-minibuffer-message "%sBell in %s%s"
  2104.                     irc-msg-info-pre
  2105.                     (buffer-name ibuf)
  2106.                     irc-msg-info-post))))
  2107.         ;; if point was in front of the irc-mark, new-point is figured relative
  2108.         ;; to the old mark, otherwise it is relative to the new one
  2109.         (setq new-point (+ (if (< irc-mark-to-point 0) old-irc-mark irc-mark)
  2110.                            irc-mark-to-point))))
  2111.     ;; update point based on whether the buffer is visible
  2112.     ;; we have a real problem here if there is more than one window displaying
  2113.     ;; the process-buffer and the user is not in the first canonical one.
  2114.     ;; i haven't yet determined a nice way to solve this
  2115.     (if (setq win (if (eq (window-buffer) ibuf)    ;930224/PS: Use selected
  2116.               (selected-window)    ; window if it shows that buffer.
  2117.               (get-buffer-window ibuf)))
  2118.     (set-window-point win new-point)
  2119.     (save-excursion (set-buffer ibuf) (goto-char new-point)))
  2120.     ;; if *IRC* isn't visible, a bell was issued and irc-pop-on-signal is an
  2121.     ;; integer then show the buffer.
  2122.     (if (and (integerp irc-pop-on-signal) bell (not win))
  2123.     (progn
  2124.       (setq win (selected-window))
  2125.       (if (/= (irc-count-windows 'no-mini) 1)
  2126.           (display-buffer ibuf) ;don't futz with sizes if more than 1 win's
  2127.           ;; we might be in the mininbuffer at the moment, so insure that
  2128.           ;; this happens starting in the current regular window
  2129.           (select-window (next-window win 'no-mini))
  2130.           ;; full screen doesn't get handled well by the algorithm
  2131.           ;; for the rest
  2132.           (if (= irc-pop-on-signal 1)
  2133.           (set-window-buffer (selected-window) ibuf)
  2134.           (split-window nil
  2135.                 (if (fboundp 'frame-height)
  2136.                     (- (frame-height)
  2137.                        (/ (frame-height) irc-pop-on-signal))
  2138.                   (- (screen-height)
  2139.                      (/ (screen-height) irc-pop-on-signal))))
  2140.           (display-buffer ibuf)
  2141.           ;; perhaps we need to go back to the minibuffer
  2142.           (select-window win)))))))
  2143.  
  2144.  
  2145. (defun irc-string-display-length (str)
  2146.   "Return the number of display positions a string would take when
  2147. being displayed by GNU-emacs. A character can be displayed in 1, 2 or
  2148. 4 positions. Also a TAB can be 1 to 8 positions wide.
  2149.  
  2150. This function is pessimistic, and will rather return a too large count than a
  2151. too small."
  2152.   (let ((len 0)
  2153.     (i (length str))
  2154.     (x 0))
  2155.     (while (> i 0)
  2156.       (setq i (1- i)
  2157.         x (+ x (let ((c (aref i str)))
  2158.              (cond
  2159.                ((= c \t) 8)    ;TAB.
  2160.                ((or (< c ?\040) (= c ?\177)) ;Normal CNTRL character.
  2161.             (if ctl-arrow 2 4)) ;^X or \030 notation.
  2162.                ((< c ?\177) 1) ;Regular character.
  2163.                ((< c ?\240) 4) ;Eight bit "CNTRL" chararacter.
  2164.                ((< c ?\400)
  2165.             (cond ((eq irc-output-character-set 'ASCII) 4)
  2166.                   ((eq irc-output-character-set 'ISO-8859-1) 1)
  2167.                   (t 4)))
  2168.                (t 4))))))
  2169.     x))
  2170.  
  2171.  
  2172. (defun irc-clean-up-message (str)
  2173.   "Exchange all \"%\" with \"%%\" in STR. Also exchange CNTRL/X in STR
  2174. with ^X. Substitute a ^B for CNTRL/B (which is used by ircII to togle the
  2175. boldness of text) if irc-drop-ircII-text-kludge-control-characters is true,
  2176. or else drop the character. As a further kudo, replace japanese characters
  2177. coded with JIS etc unless irc-show-japanese-characters is nil."
  2178.   (let* ((clean "")
  2179.      (dirty-chars (concat "%"
  2180.                   "\000\001\002\003\004\005\006\007"
  2181.                   "\010\011\012\013\014\015\016\017"
  2182.                   "\020\021\022\023\024\025\026\027"
  2183.                   "\030\031\032\033\034\035\036\037"
  2184.  
  2185.                   "\177"
  2186.                   
  2187.                   "\200\201\202\203\204\205\206\207"
  2188.                   "\210\211\212\213\214\215\216\217"
  2189.                   "\220\221\222\223\224\225\226\227"
  2190.                   "\230\231\232\233\234\235\236\237"
  2191.  
  2192.                   (if irc-emacs-knows-ISO8859-1
  2193.                   ""
  2194.                   (concat "\240\241\242\243\244\245\246\247"
  2195.                       "\250\251\252\253\254\255\256\257"
  2196.                       "\260\261\262\263\264\265\266\267"
  2197.                       "\270\271\272\273\274\275\276\277"
  2198.                       "\300\301\302\303\304\305\306\307"
  2199.                       "\310\311\312\313\314\315\316\317"
  2200.                       "\320\321\322\323\324\325\326\327"
  2201.                       "\330\331\332\333\334\335\336\337"
  2202.                       "\340\341\342\343\344\345\346\347"
  2203.                       "\350\351\352\353\354\355\356\357"
  2204.                       "\360\361\362\363\364\365\366\367"
  2205.                       "\370\371\372\373\374\375\376\377"))
  2206.                   ""))
  2207.      (dirty (concat "[" dirty-chars "]"))
  2208.      (non-dirty (concat "[^" dirty-chars "]")))
  2209.     (if (symbolp irc-translation-table-incoming)
  2210.     (cond ((eq 'scandinavian7 irc-translation-table-incoming)
  2211.            (setq irc-translation-table-incoming
  2212.              irc-translation-table-incoming-scandinavian7))
  2213.           ((eq 'scandinavian8 irc-translation-table-incoming)
  2214.            (setq irc-translation-table-incoming
  2215.              irc-translation-table-incoming-scandinavian8))))
  2216.     (while (or (string-match dirty str)
  2217.            (and irc-translation-table-incoming
  2218.             (string< "" str)))
  2219.       (let ((split (cond ((and (or (eq irc-show-japanese-characters t)
  2220.                    (eq irc-show-japanese-characters nil))
  2221.                    (string-match (concat
  2222.                           "^ ?\033$\\([@AB]\\)\\([^\033]*"
  2223.                           "\\)\033\\([()]. ?\\)")
  2224.                          str))
  2225.               (cond
  2226.                 ((eq irc-show-japanese-characters t)
  2227.                  (let* ((pre (subfield str 1))
  2228.                     (msg (subfield str 2))
  2229.                     (trail (subfield str 3)))
  2230.                  (cons (concat "\033$"
  2231.                        pre
  2232.                        (irc-clean-up-message msg)
  2233.                        trail))
  2234.                    (substring str (match-end 0))))
  2235.                 ((eq irc-show-japanese-characters nil)
  2236.                  (let ((msgend (match-end 0))
  2237.                    (type (substring str
  2238.                             (match-beginning 1)
  2239.                             (match-end 1))))
  2240.                    (cons (concat irc-msg-info-pre
  2241.                          (cond ((string= type "@")
  2242.                             "Old Kanjii: ")
  2243.                            ((string= type "A")
  2244.                             "Probaly chinese: ")
  2245.                            ((string= type "B")
  2246.                             "Modern Kanjii: ")
  2247.                            (t "Unkown 16-bit: "))
  2248.                          (irc-clean-up-message
  2249.                           (irc-translate-kanji
  2250.                            (substring str
  2251.                               (match-beginning 2)
  2252.                               (match-end 2))))
  2253.                          irc-msg-info-post
  2254.                          " ")
  2255.                      (substring str msgend))))
  2256.                 (t (irc-insert (concat "%%Bug in japanese part of"
  2257.                            " irc-clean-up-message."))
  2258.                    (cons (substring str 0 (match-end 0))
  2259.                      (substring str (match-end 0))))))
  2260.              ((not (null irc-translation-table-incoming))
  2261.               (cons (aref irc-translation-table-incoming
  2262.                       (aref str 0))
  2263.                 (substring str 1)))
  2264.              ((and (>= (aref str 0) ?\200) ;8 bit?
  2265.                    (or (< (aref str 0) ?\240)
  2266.                    (not (eq irc-output-character-set
  2267.                         'ISO-8859-1))))
  2268.               (cons (concat (format "\\%o" (aref str 0)))
  2269.                 (substring str 1)))
  2270.              ((string-match (concat "^" non-dirty "*%") str)
  2271.               (cons (concat (substring str 0 (1- (match-end 0)))
  2272.                     "%%")
  2273.                 (substring str (match-end 0))))
  2274.              ((= (aref str 0) ?\t)
  2275.               (cons "^I" (substring str 1)))
  2276.              ((= (aref str 0) ?\177)
  2277.               (cons "^?" (substring str 1)))
  2278.              ((and irc-drop-ircII-text-kludge-control-characters
  2279.                    (irc-member-general (aref str 0)
  2280.                            '(?\002 ?\017 ?\026 ?\037)
  2281.                            '=))
  2282.               (cons "" (substring str 1)))
  2283.              ((and (>= (aref str 0) ?\000)
  2284.                    (<= (aref str 0) ?\037))
  2285.               (cons
  2286.                (concat "^" (char-to-string (+ ?@ (aref str 0))))
  2287.                (substring str 1)))
  2288.              ((string-match (concat "^" non-dirty "+") str)
  2289.               (cons (substring str
  2290.                        (match-beginning 0)
  2291.                        (match-end 0))
  2292.                 (substring str (match-end 0))))
  2293.              (t (cons (substring str 0 1) (substring str 1))))))
  2294.     (setq clean (concat clean (car split))
  2295.           str (cdr split))))
  2296.     (concat clean str)))
  2297.  
  2298.  
  2299. (defun irc-translate-kanji (str)
  2300.   "Translate a japanese Kanjicoded message in STR into nummeric codes.
  2301. Just exchange every two octet sequence into their nummeric codes."
  2302.   (let ((retval ""))
  2303.     (while (>= (length str) 2)
  2304.       (let ((double (+ (* (aref str 0) 256) (aref str 1))))
  2305.     (setq retval (format "%s%s%d"
  2306.                  retval
  2307.                  (if (string= "" retval) "" " ")
  2308.                  double)
  2309.           str (substring str 2))))
  2310.     (if (> (length str) 0)
  2311.     (format "ODD %d" (aref str 0))
  2312.     retval)))
  2313.  
  2314.  
  2315. (defun irc-parse-server-msg (str)
  2316.   "Take the first line from STR and pass it on to the appropriate irc-parse-*
  2317. function.  If the message is one which irc-mode doesn't recognize, just display
  2318. it as the raw server message.
  2319.  
  2320. It returns a dotted-pair whose car is the remainder of STR after the first
  2321. newline and whose cdr is either t or nil, indicating whether a signal should
  2322. be issued."
  2323.   (let ((n (string-match "\r" str)))
  2324.     (while n
  2325.       (setq str (concat (substring str 0 n)
  2326.             (substring str (1+ n)))
  2327.         n (string-match "\r" str))))
  2328.   (let* ((nl (string-match "\n" str)) 
  2329.      (eol (or nl (length str)))
  2330.      (line (substring str 0 eol))
  2331.      (dummy (irc-log-in-debug-buffer (concat "  " line)))
  2332.      (new (or (string-match "^:\\([^! :]+\\)!\\([^@ :]+\\)@\\([^ :]+\\)"
  2333.                 line)))
  2334.      (triple (if new (cons (subfield line 1)
  2335.                    (cons (subfield line 2)
  2336.                      (subfield line 3)))))
  2337.      (rest (if new (substring line (match-end 0))))
  2338.      (irc-userhost (if new
  2339.                (format " <%s@%s>"
  2340.                    (car (cdr triple)) (cdr (cdr triple)))
  2341.                ""))
  2342.      (line (if new (format ":%s%s" (car triple) rest) line))
  2343.      (last-NOTICE-rcv irc-last-NOTICE-rcv)
  2344.      (last-NOTICE-src irc-last-NOTICE-src))
  2345.     (if (not nl)
  2346.     (irc-insert "%%WARNING: got incomplete line from server! No newline."))
  2347.     (setq irc-last-NOTICE-rcv ""
  2348.       irc-last-NOTICE-src "")
  2349.     (if (not (boundp 'irc-count-incoming-messages))
  2350.     (progn
  2351.       (message "?Kiwi: Variable irc-count-incoming-messages unbound")
  2352.       (set (make-local-variable 'irc-count-incoming-messages) nil)))
  2353.     (if (not (numberp irc-count-incoming-messages))
  2354.     (progn
  2355.       (message "?Kiwi: irc-count-incoming-messages=%d, not a number"
  2356.            irc-count-incoming-messages)
  2357.       (setq irc-count-incoming-messages 0)))
  2358.     (setq line (irc-lowlevel-dequote line)
  2359.       irc-count-incoming-messages (1+ irc-count-incoming-messages))
  2360.     (if (= 0 (% irc-count-incoming-messages 50))
  2361.     (irc-send (concat "PONG " irc-server)))
  2362.     (cons
  2363.      ;; the part of str not being parsed.
  2364.      (substring str (1+ (string-match "\n" str)))
  2365.      (cond
  2366.        ;; each function here should return t or nil indicating whether
  2367.        ;; to issue a signal.  Some of these regexps are fugly because
  2368.        ;; of inconsistent protocol use by the servers.  Fortunately Jarkko
  2369.        ;; is fixing that.
  2370.        ((string-match "^ *$" line) nil)    ;Ignore empty lines.
  2371.        ((string-match "^:[^: ]+ +MSG " line) (irc-parse-public line))
  2372.        ((string-match "^:[^: ]+ +CHANNEL " line) (irc-parse-channel line))
  2373.        ((string-match "^:[^ ]+ +JOIN " line) (irc-parse-channel line))
  2374.        ((string-match "^:[^: ]+ +PART " line) (irc-parse-channel line))
  2375.        ((string-match "^:[^: ]+ +INVITE " line) (irc-parse-invite line))
  2376.        ((string-match "^:[^: ]+ +NICK " line) (irc-parse-nick line))
  2377.        ((string-match "^:[^: ]+ +WALL " line) (irc-parse-wall line))
  2378.        ((string-match "^:[^: ]+ +WALLOPS " line) (irc-parse-wallops line))
  2379.        ((string-match "^:[^: ]+ +QUIT " line) (irc-parse-quit line))
  2380.        ((string-match "^:[^: ]+ +KICK " line) (irc-parse-kick line))
  2381.        ((string-match "^:[^: ]+ +KILL " line) (irc-parse-kill line))
  2382.        ((string-match "^:[^: ]+ +TOPIC " line) (irc-parse-topic line))
  2383.        ((string-match "^:[^: ]+ +MODE " line) (irc-parse-mode-reply line))
  2384.        ((string-match "^:[^: ]+ +[023][0-9][0-9][^0-9]" line)
  2385.     (irc-parse-RPL line))
  2386.        ((string-match "^:[^: ]+ +[4-5][0-9][0-9][^0-9]" line)
  2387.     (irc-parse-ERR line))
  2388.        ((string-match (concat "^\\(:?\\)\\([^: ]*\\) *NOTICE"
  2389.                   " +\\([^: ]+\\) *:"
  2390.                   "\\([^\001]*\001[^\001]*\001\\)")
  2391.               line)
  2392.     (setq irc-last-NOTICE-rcv last-NOTICE-rcv
  2393.           irc-last-NOTICE-src last-NOTICE-src)
  2394.     (let* ((colon (subfield line 1))
  2395.            (from (subfield line 2))
  2396.            (to (subfield line 3))
  2397.            (msg (concat (subfield line 4)
  2398.                 (substring line (match-end 0))))
  2399.            (frm (if (string= "" from) irc-server from)))
  2400.       (if (irc-is-nickname frm)
  2401.           (irc-remember frm 'irc-nicknames))
  2402.       (while (string-match "^\\([^\001]*\\)\\(\001[^\001]*\001\\)" msg)
  2403.         (let ((start (subfield msg 1))
  2404.           (ctcp (subfield msg 2))
  2405.           (end (substring msg (match-end 0))))
  2406.           (setq msg (concat start end))
  2407.           (if (string= "\001\001" ctcp)
  2408.           (setq msg (concat msg "\001"))
  2409.           (irc-parse-CLIENT-answer frm to ctcp))))
  2410.       (if (not (string-match "^ *$" msg))
  2411.           (irc-parse-server-msg
  2412.            (concat colon from " NOTICE " to " :" msg "\n")))))
  2413.        ((string-match "^\\(:[^: ]* +\\)?NOTICE " line)
  2414.     (setq irc-last-NOTICE-rcv last-NOTICE-rcv
  2415.           irc-last-NOTICE-src last-NOTICE-src)
  2416.     (irc-parse-notice line))
  2417.        ((string-match (concat "^\\(:?\\)\\([^: ]*\\) *PRIVMSG"
  2418.                   " +\\([^ ]+\\) +:"
  2419.                   "\\([^\001]*\001[^\001]*\001\\)") 
  2420.               line)
  2421.     (let* ((colon (subfield line 1))
  2422.            (from (subfield line 2))
  2423.            (to (subfield line 3))
  2424.            (msg (concat (subfield line 4)
  2425.                 (substring line (match-end 0))))
  2426.            (frm (if (string= "" from) irc-server from)))
  2427.       (if (irc-is-nickname frm)
  2428.           (irc-remember frm 'irc-nicknames))
  2429.       (while (string-match "^\\([^\001]*\\)\\(\001[^\001]*\001\\)" msg)
  2430.         (let ((start (subfield msg 1))
  2431.           (ctcp (subfield msg 2))
  2432.           (end (substring msg (match-end 0))))
  2433.           (setq msg (concat start end))
  2434.           (if (string= "\001\001" ctcp)
  2435.           (setq msg (concat msg "\001"))
  2436.           (irc-parse-CLIENT-query frm to ctcp))))
  2437.       (if (not (string-match "^ *$" msg))
  2438.           (irc-parse-server-msg
  2439.            (concat colon from " PRIVMSG " to " :" msg "\n")))))
  2440.        ((string-match "^\\(:[^: ]* +\\)?PRIVMSG " line)
  2441.     (irc-parse-priv line))
  2442.        ((string-match "^PING " line) (irc-pong line))
  2443.        ((string-match "^\\(:[^: ^]* +\\)?PONG " line)
  2444.     (irc-parse-pong line))
  2445.        ((string-match "^ERROR " line) (irc-parse-error line))
  2446.        ((string-match "^WHOREPLY " line) (irc-parse-whoreply line))
  2447.        ((string-match "^NAMREPLY " line) (irc-parse-namreply line))
  2448.        ((string-match "^LINREPLY " line) (irc-parse-linreply line))
  2449.        (t (irc-insert (concat "%%Received unkown message from server,"
  2450.                   " in function irc-parse-server-msg:"))
  2451.       (irc-insert "%% \"%s\" (cleaned up line)."
  2452.               (irc-clean-up-message line))
  2453.       (irc-insert (concat "%% Please let %s know about this;"
  2454.                   " it might be a bug.")
  2455.               irc-hacker)
  2456.       nil)))))
  2457.  
  2458.  
  2459. (defun irc-parse-channel (str)
  2460.   "Examine CHANNEL, JOIN and PART messages from the IRC server.
  2461. CHANNEL indicates a user entering or leaving the channel which you are
  2462. on, JOIN indicates a user entering a channel and PART indicates a user
  2463. leaving the channel. If the user is not being ignored and \"join\" is
  2464. in irc-events, a message is inserted indicating the change.  A
  2465. message is always provided as confirmation if the user is the irc-mode
  2466. user.
  2467.  
  2468. This function returns t if a bell should be issued for the \"join\" event,
  2469. nil otherwise."
  2470.   (if (not (or (string-match (concat "^: *\\([^ ]+\\) +\\(JOIN\\)"
  2471.                      " +:?\\([^ ]+\\) +\\([^ ]*\\) *$")
  2472.                  str)
  2473.            (string-match (concat "^: *\\([^ ]+\\) +\\(JOIN\\)"
  2474.                      " +:?\\([^ ]+\\) *\\(\\)$")
  2475.                  str)
  2476.            (string-match (concat "^: *\\([^ ]+\\) +\\(PART\\)"
  2477.                      " +:?\\([^ ]+\\) +\\([^ ]*\\) *$")
  2478.                  str)
  2479.            (string-match (concat "^: *\\([^ ]+\\) +\\(PART\\)"
  2480.                      " +:?\\([^ ]+\\) *\\(\\)$")
  2481.                  str)
  2482.            (string-match (concat "^: *\\([^ ]+\\) +\\(CHANNEL\\)"
  2483.                      " +:?\\([^ ]+\\) *\\(\\)$")
  2484.                  str)))
  2485.       (progn (irc-insert (concat "%%Unknown format on command from server,"
  2486.                  " please notify %s, it migh be a bug.")
  2487.              irc-hacker)
  2488.          (irc-insert "%% str=\"%s\"." str)
  2489.          (irc-insert "%% Function irc-parse-channel."))
  2490.       (let* ((user (subfield str 1))
  2491.          (type (subfield str 2))
  2492.          (channel (subfield str 3))
  2493.          (mode (subfield str 4))
  2494.          (left (or (string= type "PART")
  2495.                (and (string= type "CHANNEL") (string= channel "0"))))
  2496.          (pd (make-string (max 0 (1- (length channel))) ? ))
  2497.          (cont (concat irc-msg-cont pd)))
  2498.     (if (string= user irc-nick-used)
  2499.         (progn
  2500.           (if left
  2501.           (irc-forget channel 'irc-subscribed-channels)
  2502.           (irc-remember channel 'irc-subscribed-channels)))
  2503.         )
  2504.     (if (string= user irc-nick-used)
  2505.         (progn
  2506.           (if left
  2507.           (if (irc-server-has-multijoinable-channels)
  2508.               (if (or (string= (upcase channel) (upcase irc-channel))
  2509.                   (string= irc-channel "0"))
  2510.               (progn
  2511.                 (setq irc-channel "0")
  2512.                 (irc-show-subscribed-channels))
  2513.               (progn
  2514.                 (if nil
  2515.                 (irc-remember channel
  2516.                           'irc-subscribed-channels))
  2517.                 (irc-show-subscribed-channels)))
  2518.               (progn
  2519.             (if nil
  2520.                 (irc-remember irc-channel
  2521.                       'irc-subscribed-channels))
  2522.             (setq irc-channel "0")
  2523.             (irc-show-subscribed-channels)))
  2524.           (progn (setq irc-channel channel)
  2525.              (if nil
  2526.                  (irc-remember channel 'irc-subscribed-channels))
  2527.              (irc-send (concat "MODE " irc-channel))
  2528.              (irc-show-subscribed-channels))))
  2529.         (if (and (not (irc-recall user 'irc-ignored-ppl))
  2530.              (memq 'join irc-events))
  2531.         (progn
  2532.           (if left
  2533.               (irc-insert "%s%s%s has LEFT channel %s%s"
  2534.                   irc-msg-info-pre
  2535.                   user
  2536.                   irc-userhost
  2537.                   (if (irc-server-has-multijoinable-channels)
  2538.                       channel
  2539.                       irc-channel)
  2540.                   irc-msg-info-post)
  2541.               (progn
  2542.             (irc-remember user 'irc-nicknames)
  2543.             (irc-insert "%s%s%s has JOINED channel %s%s"
  2544.                     irc-msg-info-pre
  2545.                     user
  2546.                     irc-userhost
  2547.                     channel
  2548.                     irc-msg-info-post)))
  2549.           )
  2550.         (irc-signal user 'join)))))) ; check for signal for join
  2551.  
  2552.  
  2553. (defun irc-parse-CLIENT-answer (sndr rcvr str)
  2554.   "Examine a client answer message from another client.
  2555.  
  2556. Generally, incoming message will look like \"^ACLIENT keyword arg1 .. argN^A\"
  2557. one or several pasted together."
  2558.   (if (irc-recall sndr 'irc-ignored-ppl)
  2559.       ;; Ignored person.
  2560.       (setq str ""))
  2561.   (if (not (string-match "^\001\\([^\001]*\\)\001$" str))
  2562.       (progn (irc-insert "%%Got non-clientmessage in irc-parse-CLIENT-answer:")
  2563.          (irc-insert "%% \"%s\" (str)." str)
  2564.          (irc-insert "%% Please tell %s, probaly en internal error."
  2565.              irc-hacker))
  2566.     (setq str (irc-ctcp-dequote
  2567.            (substring str (match-beginning 1) (match-end 1)))))
  2568.   (if (not (string-match (concat " *\\([^\001 \t]+\\)"    ;1 keyword
  2569.                  " *:?"            ;optional colon
  2570.                  " *\\([^\001]*\\)"        ;2 data
  2571.                  " *$")
  2572.              str))
  2573.       (if (string< "" str)
  2574.       (progn (irc-insert "%%Received unknown CTCP answer message:")
  2575.          (irc-insert "%% \"%s\" (str)." (irc-clean-up-message str))
  2576.          (irc-insert "%% This is probaly NOT a bug.")))
  2577.       (let* ((keyw (subfield str 1))
  2578.          (args (subfield str 2))
  2579.          (pre (concat irc-msg-info-pre "User \"" sndr "\" "))
  2580.          (irc-msg-cont-used (make-string (length pre) ? )))
  2581.     (cond
  2582.       ((string= keyw "ACTION")    ;Ignore ACTION replies.
  2583.        )
  2584.       ((string= keyw "CLIENTINFO")
  2585.        (irc-insert (concat "%sis using a client which is using the"
  2586.                    " client-to-client-protocol keyword %s in the"
  2587.                    " following way: %s%s")
  2588.                pre keyw args irc-msg-info-post))
  2589.       ((string= keyw "ECHO")
  2590.        (irc-insert "%sechoed back \"%s\" to us with (CTCP) ECHO%s"
  2591.                pre args irc-msg-info-post))
  2592.       ((string= keyw "PING")
  2593.        (cond ((not (string-match "^[0-9]+$" args))
  2594.           (irc-insert (concat "%%Received bogus (CTCP) PING reply from"
  2595.                       " user %s: \"%s\".")
  2596.                   sndr args))
  2597.          (t (let* ((cur (car (cdr (irc-current-time))))
  2598.                (rep (string-to-int args))
  2599.                (ans (- cur rep))
  2600.                (tos (/ (* 10 (if (< ans 0)
  2601.                          (+ cur (- 65536 rep))
  2602.                          ans))
  2603.                    2))
  2604.                (int-part (/ tos 10))
  2605.                (dec-part  (- tos (* 10 int-part))))
  2606.               (irc-insert (concat "%sis about %d.%d seconds"
  2607.                       " away from you, %s%s")
  2608.                   pre int-part dec-part irc-nick-used
  2609.                   irc-msg-info-post)))))
  2610.       ((string= keyw "ERRMSG")
  2611.        (cond ((string-match "^PING +RELAY +\\([0-9]+\\)\\( +:.*\\)? *$"
  2612.                 args)
  2613.           (irc-parse-CLIENT-answer sndr
  2614.                        rcvr
  2615.                        (format "\001PING %s\001"
  2616.                            (subfield args 1))))
  2617.          ((string-match "^ACTION " args)
  2618.           ;; Ignore complaints about CTCP ACTION.
  2619.           )
  2620.          (t (irc-insert (concat "%%Errormessage from client of"
  2621.                     " user %s: \"%s\".")
  2622.                 sndr args))))
  2623.       ((string= keyw "FINGER")
  2624.        (let* ((data (if (string-match (concat "^ *Please +check +"
  2625.                           "my +USERINFO +instead"
  2626.                           " *:")
  2627.                       args)
  2628.                 (substring args (match-end 0))
  2629.                 args)))
  2630.          (if (string-match (concat "^\\(.* +Idle *\\)\\(for +\\)?"
  2631.                        "\\([0-9]+\\) *seconds? *$")
  2632.                    data)
  2633.          (let* ((m (subfield data 1))
  2634.             (idle (subfield data 3))
  2635.             (xpre (concat "\"" (irc-clean-up-message m)))
  2636.             (idle-time (string-to-int idle))
  2637.             (xpost (if (= 1 idle-time) "second" "seconds"))
  2638.             (idle-string (if (>= idle-time 60)
  2639.                      (format "%s %s\" (%s)"
  2640.                          idle
  2641.                          xpost
  2642.                          (irc-sec-to-time idle-time))
  2643.                      (concat idle " " xpost "\""))))
  2644.            (irc-insert "%shas FINGER-info %s%s"
  2645.                    pre
  2646.                    (concat xpre idle-string)
  2647.                    irc-msg-info-post))
  2648.          (irc-insert "%shas fingerinfo \"%s\"%s"
  2649.                  pre data irc-msg-info-post))))
  2650.       ((string= keyw "SOURCE")
  2651.        (cond
  2652.          ((string-match "^ *$" args)
  2653.           (irc-insert "%sEnd of source site listing%s"
  2654.               irc-msg-info-pre irc-msg-info-post))
  2655.          ((string-match "^ *\\([^: ]+\\) *: *\\([^: ]+\\) *: *\\(.*\\) *"
  2656.                 args)
  2657.           (let ((site (subfield args 1))
  2658.             (dir (subfield args 2))
  2659.             (files (subfield args 3)))
  2660.         (let ((x files)
  2661.               (y ""))
  2662.           (while (string-match "^ *\\([^ ]+\\)\\(.*\\)$" x)
  2663.             (let ((hd (subfield x 1))
  2664.               (tl (subfield x 2)))
  2665.               (setq y (format "%s, ftp://%s/%s" y dir hd)
  2666.                 x tl)))
  2667.           (setq y (substring y 1)) 
  2668.           (irc-insert "%sSource at%s%s"
  2669.                   irc-msg-info-pre
  2670.                   y                
  2671.                   irc-msg-info-post))
  2672.         ))
  2673.          (t (irc-insert "%%Received unknown CTCP %s reply from %s: %s"
  2674.                 keyw sndr args))))
  2675.       ((string= keyw "USERINFO")
  2676.        (if (or (string-match "^ *$" args)
  2677.            (string-match
  2678.             "^ *\\(HUH *\\?\\) *WHO +WANTS +TO +KNOW *\\? *$"
  2679.             (upcase args))
  2680.            (string= "<None Supplied>" args)
  2681.            (string= "And what you want to know?" args)
  2682.            (string= "No user info given." args)
  2683.            )
  2684.            (irc-insert (concat "%shasn't given any information"
  2685.                    " about him/herself%s")
  2686.                pre irc-msg-info-post)
  2687.            (progn
  2688.          (string-match "\\(\\.?\\)$" args)
  2689.          (let ((info (substring args 0 (match-beginning 0)))
  2690.                (dot (subfield args 2)))
  2691.            (irc-insert (concat "%shas given the information"
  2692.                        " \"%s\"%s about him/herself%s")
  2693.                    pre
  2694.                    (irc-clean-up-message info)
  2695.                    dot
  2696.                    irc-msg-info-post)))))
  2697.       ((or (string= keyw "VERSION")    ;CLIENT_VERSION
  2698.            (string= keyw "VRSN"))
  2699.        (if (string-match "^ *\\([^:]+\\) *: *\\([^:]+\\) *: *\\(.*\\) *$"
  2700.                  args)
  2701.            (let ((name (subfield args 1))
  2702.              (vrsn (subfield args 2))
  2703.              (env (subfield args 3)))
  2704.          (irc-insert (concat "%sUser \"%s\" claims to be using"
  2705.                      " client %s version %s (%s)%s")
  2706.                  irc-msg-info-pre
  2707.                  sndr name (irc-clean-up-message vrsn) env
  2708.                  irc-msg-info-post))
  2709.            (irc-insert "%sclaims to be using client %s%s"
  2710.                pre
  2711.                (irc-clean-up-message
  2712.                 (let ((c (cond
  2713.                        ((or (string-match
  2714.                          (concat
  2715.                           "^ *[Ii][Rr][Cc][Ii][Ii] +"
  2716.                           "\\([0-9]+\\.[0-9]+[^:]+\\) *:"
  2717.                           "[^0-9]*\\([0-9]\\.[0-9][^ \\.]+"
  2718.                           "*\\).*$")
  2719.                          args)
  2720.                         (string-match
  2721.                          (concat
  2722.                           "^ *[Ii][Rr][Cc][Ii][Ii] +"
  2723.                           "[^:]*: *\\(.*[0-9]\\."
  2724.                           "[0-9].*\\) *\\(\\)$")
  2725.                          args)
  2726.                         (string-match
  2727.                          (concat
  2728.                           "^ *[Ii][Rr][Cc][Ii][Ii] +"
  2729.                           "\\([^:]+\\) *:.*\\(\\)$")
  2730.                          args))
  2731.                     (concat "ircII "
  2732.                         (subfield args 1)
  2733.                         (subfield args 2)))
  2734.                        ((string-match
  2735.                      (concat "^[^:]*: *\\(.*[0-9]+\\."
  2736.                          "[0-9]+.*.*\\) *$")
  2737.                      args)
  2738.                     (subfield args 1))
  2739.                        ((string-match
  2740.                      "^[^:]*[0-9]+\\.[0-9]+[^:]*"
  2741.                      args)
  2742.                     (substring args 0 (match-end 0)))
  2743.                        (t args))))
  2744.                   (irc-nuke-whitespace
  2745.                    (progn
  2746.                  (while
  2747.                      (or (string-match
  2748.                       " The one true client\\." c)
  2749.                      (string-match (concat
  2750.                             " Who could ask for"
  2751.                             " anything more\\.")
  2752.                                c)
  2753.                      (string-match "SIAWPIO!" c))
  2754.                    (setq c (concat
  2755.                         (substring c 0 (match-beginning 0))
  2756.                         (substring c (match-end 0)))))
  2757.                  c))))
  2758.                irc-msg-info-post)))
  2759.       ((string= keyw "VRSN")
  2760.        (if (string-match "^ *\\([^:]+\\) *: *\\([^:]+\\) *: *\\(.*\\) *$"
  2761.                  args)
  2762.            (let ((name (subfield args 1))
  2763.              (vrsn (subfield args 2))
  2764.              (env (subfield args 3)))
  2765.          (irc-insert (concat "%sUser \"%s\" claims to be using"
  2766.                      " client %s version %s (%s)%s")
  2767.                  irc-msg-info-pre
  2768.                  sndr name vrsn env
  2769.                  irc-msg-info-post))
  2770.            (irc-insert "%%Received unknown (CTCP) %s reply from %s: %s"
  2771.                keyw sndr args)))
  2772.       (t (irc-insert (concat "%%Received unknown answer with keyword"
  2773.                  " \"%s\" from client of user \"%s\":"
  2774.                  " \"%s\".")
  2775.              keyw sndr args))))))
  2776.  
  2777.  
  2778. (defun irc-parse-CLIENT-query (sndr rcvr str)
  2779.   "Examine a client query message from another client.
  2780.  
  2781. Generally, incoming message will look like \"^A CLIENT keyword data
  2782. ... ^A\" where sndr is nick of client query is comming from, rcvr is
  2783. nick of receiver (either one self or a channel or a broadcast), and
  2784. keyword being a token in the set VERSION, USERINFO, ERRMSG etc. Arg1
  2785. to argN are optional." 
  2786.   (cond
  2787.     ((irc-recall sndr 'irc-ignored-ppl)
  2788.      ;; Ignored person.
  2789.      nil)
  2790.     ((not (string-match "^\001\\([^\001]*\\)\001$" str))
  2791.      (progn (irc-insert "%%Got non-CTCP query in irc-parse-CLIENT-query:")
  2792.         (irc-insert "%% \"%s\" (str)." str)
  2793.         (irc-insert "%% Please tell %s, probaly an internal error."
  2794.             irc-hacker)))
  2795.     (t (setq str (irc-ctcp-dequote
  2796.           (substring str (match-beginning 1) (match-end 1))))
  2797.        (if (not (string-match (concat " *\\([^\001 \t]+\\)" ;1 keyword
  2798.                       " *\\([^\001]*\\)" ;2 data
  2799.                       " *$")
  2800.                   str))
  2801.        (if (and debug-on-error
  2802.             (string< "" str))
  2803.            (progn
  2804.          (irc-insert "%%Received unknown CTCP request:")
  2805.          (irc-insert "%% \"%s\" (str)." (irc-clean-up-message str))
  2806.          (irc-insert "%% This is probaly not a bug.")))
  2807.        (let ((keyw (substring str (match-beginning 1) (match-end 1)))
  2808.          (args (substring str (match-beginning 2) (match-end 2)))
  2809.          (tell (memq 'ctcp irc-events)))
  2810.          (cond
  2811.            ((string= keyw "ACTION") ;CLIENT_ACTION
  2812.         (if (string= "" args)
  2813.             (irc-send (format "NOTICE %s :\001ERRMSG ACTION :%s\001"
  2814.                       sndr
  2815.                       "No argument supplied."))
  2816.             (irc-insert ">>> (To %s) User %s %s"
  2817.                 rcvr
  2818.                 sndr
  2819.                 (irc-clean-up-message args))))
  2820.            ((string= keyw "CLIENTINFO")
  2821.         (cond ((string-match "^ *$" args) ;No arguments
  2822.                (irc-send
  2823.             (concat "NOTICE " sndr " :\001"
  2824.                 (irc-ctcp-enquote
  2825.                  (concat
  2826.                   "CLIENTINFO :You can request help of the"
  2827.                   " commands ACTION CLIENTINFO ECHO ERRMSG"
  2828.                   " FINGER PING SOURCE USERINFO VERSION"
  2829.                   " by giving an argument to CLIENTINFO."))
  2830.                 "\001"))
  2831.                (if tell
  2832.                (irc-insert
  2833.                 "%sAnswered (CTCP) CLIENTINFO query to %s by %s%s"
  2834.                 irc-msg-info-pre rcvr sndr irc-msg-info-post)) )
  2835.               ((string-match "^ *\\([^: ]+\\) *$" args) ;1 arg
  2836.                (let* ((w (substring args
  2837.                         (match-beginning 1)
  2838.                         (match-end 1)))
  2839.                   (uw (upcase w))
  2840.                   (info (cond
  2841.                       ((string= uw "ACTION")
  2842.                        (concat
  2843.                     "ACTION takes one or more arguments,"
  2844.                     " and displayes them as a \"MUD like"
  2845.                     " feeling\" to this user. If nick"
  2846.                     " sojge sends \"falls down\", this"
  2847.                     " user gets a message looking more or"
  2848.                     " less like \"User sojge falls"
  2849.                     " down\"."))
  2850.                       ((string= uw "CLIENTINFO")
  2851.                        (concat
  2852.                     "CLIENTINFO with 0 arguments gives"
  2853.                     " a list of known client query"
  2854.                     " keywords. With 1 argument,"
  2855.                     " a description of the client query"
  2856.                     " keyword is returned."))
  2857.                       ((string= uw "ECHO")
  2858.                        (concat
  2859.                     "ECHO returns whatever argument is"
  2860.                     " given."))
  2861.                       ((string= uw "ERRMSG")
  2862.                        (concat
  2863.                     "ERRMSG is returned either when the"
  2864.                     " query keyword is ERRMSG (in which"
  2865.                     " case all arguments are echoed) or"
  2866.                     " when an error in a query is"
  2867.                     " detected or some other error"
  2868.                     " happens in connection to CTCP (in"
  2869.                     " which case the query is returned as"
  2870.                     " the replies arguments, with a short"
  2871.                     " error message added)."))
  2872.                       ((string= uw "FINGER")
  2873.                        (concat
  2874.                     "FINGER shows user's real name, login"
  2875.                     " name, client machine and idle"
  2876.                     " time."))
  2877.                       ((string= uw "PING")
  2878.                        (concat
  2879.                     "PING takes a integer number as its"
  2880.                     " argument and echoes it back to the"
  2881.                     " sender."))
  2882.                       ((string= uw "SOURCE")
  2883.                        (concat
  2884.                     "SOURCE takes 0 arguments and returns"
  2885.                     " a description of where to find the"
  2886.                     " source code of the client. The"
  2887.                     " description is made up out of zero"
  2888.                     " or more lines followed by an end"
  2889.                     " marker. Every line is a CTCP"
  2890.                     " reply with the SOURCE keyword,"
  2891.                     " a space, the name of a FTP-server, a"
  2892.                     " colon, a directory name, a colon,"
  2893.                     " and 0 or more file names."
  2894.                     " If no file names are given, all the"
  2895.                     " files in the named directory are"
  2896.                     " needed. The end marker contains just"
  2897.                     " the keyword."))
  2898.                       ((string= uw "VERSION")
  2899.                        (concat
  2900.                     "VERSION takes 0 arguments and"
  2901.                     " returns a list of words consisting"
  2902.                     " of clients name, any number of"
  2903.                     " versions (starting with the major"
  2904.                     " version), and ending with the"
  2905.                     " enviroment the client runs in. A"
  2906.                     " colon and a plain text descrpition"
  2907.                     " of the clients version is appended"
  2908.                     " after the list."))
  2909.                       ((string= uw "USERINFO")
  2910.                        (concat
  2911.                     "USERINFO takes no arguments and"
  2912.                     " returns a user settable"
  2913.                     " string."))
  2914.                       (t nil))))
  2915.              (cond ((stringp info)
  2916.                 (irc-send
  2917.                  (concat "NOTICE " sndr " :\001"
  2918.                      (irc-ctcp-enquote
  2919.                       (concat "CLIENTINFO :" info))
  2920.                      "\001"))
  2921.                 (if tell
  2922.                     (irc-insert
  2923.                      (concat "%sAnswered (CTCP)"
  2924.                          " CLIENTINFO %s to %s by %s%s")
  2925.                      irc-msg-info-pre
  2926.                      uw
  2927.                      rcvr
  2928.                      sndr
  2929.                      irc-msg-info-post)))
  2930.                    (t (irc-send
  2931.                    (concat
  2932.                     "NOTICE " sndr " :\001"
  2933.                     (irc-ctcp-enquote
  2934.                      (concat
  2935.                       "ERRMSG " keyw
  2936.                       (if args
  2937.                       (concat " " args)
  2938.                       "")
  2939.                       " :Unknown keyword in CLIENTINFO"
  2940.                       " client query. Send CLIENTINFO"
  2941.                       " CLIENTINFO for help."))
  2942.                     "\001"))))))
  2943.               (t (irc-send
  2944.               (concat "NOTICE " sndr " :\001"
  2945.                   (irc-ctcp-enquote
  2946.                    (concat "ERRMSG " keyw " " args " :"
  2947.                        "CLIENTINFO takes 0 or 1"
  2948.                        " argument. Send"
  2949.                        " CLIENTINFO CLIENTINFO"
  2950.                        " for help."))
  2951.                   "\001"))
  2952.              (if tell
  2953.                  (irc-insert (concat
  2954.                       "%sComplained about user %s's"
  2955.                       " corrupted CTCP CLIENTINFO query to"
  2956.                       " %s%s")
  2957.                      irc-msg-info-pre
  2958.                      sndr
  2959.                      rcvr
  2960.                      irc-msg-info-post)))))
  2961.            ((string= keyw "ECHO") 
  2962.         (irc-send (format "NOTICE %s :\001ECHO %s\001"
  2963.                   sndr
  2964.                   (irc-ctcp-enquote args)))
  2965.         (if tell
  2966.             (irc-insert (concat "%sAnswered to (CTCP) ECHO request"
  2967.                     " from %s to %s, echoed back \"%s\"%s")
  2968.                 irc-msg-info-pre rcvr sndr args
  2969.                 irc-msg-info-post)))
  2970.            ((string= keyw "ERRMSG")
  2971.         (irc-send (format "NOTICE %s :\001ERRMSG %s :No errors.\001"
  2972.                   sndr args))
  2973.         (cond ((not tell)
  2974.                )
  2975.               ((string-match "^ *PING +RELAY +[0-9]+ *$" args)
  2976.                (irc-insert (concat "%sAnswered to (CTCP) ERRMSG PING"
  2977.                        " RELAY request to %s from %s%s")
  2978.                    irc-msg-info-pre rcvr sndr
  2979.                    irc-msg-info-post))
  2980.               (t (irc-insert (concat "%sAnswered to (CTCP) ERRMSG"
  2981.                          " request to %s from %s, echoed"
  2982.                          " back \"%s\"%s")
  2983.                      irc-msg-info-pre
  2984.                      rcvr sndr (concat args " :No errors")
  2985.                      irc-msg-info-post))))
  2986.            ((string= keyw "FINGER")
  2987.         (let* ((idle (irc-idle-time))
  2988.                (verbose-idle (concat "(" (irc-sec-to-time idle) ") "))
  2989.                (plur (not (= 1 idle))))
  2990.           (irc-send (format (concat "NOTICE %s :\001FINGER :Please"
  2991.                         " check my USERINFO instead :%s"
  2992.                         " (%s@%s) %d second%s %sha%s"
  2993.                         " passed since %s gave a command"
  2994.                         " last.\001")
  2995.                     sndr
  2996.                     (user-full-name)
  2997.                     (user-real-login-name)
  2998.                     (system-name)
  2999.                     idle
  3000.                     (if plur "s" "")
  3001.                     (if (>= idle 60) verbose-idle "")
  3002.                     (if plur "ve" "s")
  3003.                     irc-nick-used)))
  3004.         (if tell
  3005.             (irc-insert "%sAnswered (CTCP) FINGER query to %s by %s%s"
  3006.                 irc-msg-info-pre rcvr sndr irc-msg-info-post)))
  3007.            ((string= keyw "PING")
  3008.         (cond ((string-match "^[0-9]+$" args)
  3009.                (irc-send (format "NOTICE %s :\001PING %s\001"
  3010.                      sndr
  3011.                      (irc-ctcp-enquote args)))
  3012.                (if tell
  3013.                (irc-insert
  3014.                 "%sAnswered to (CTCP) PING query to %s from %s%s"
  3015.                 irc-msg-info-pre rcvr sndr irc-msg-info-post)))
  3016.               (t (irc-send (format "NOTICE %s :\001%s %s :%s\001"
  3017.                        sndr
  3018.                        "ERRMSG PING"
  3019.                        (irc-ctcp-enquote args)
  3020.                        "Argument was not a number"))
  3021.              (cond
  3022.                (tell
  3023.                 (irc-insert (concat "%%Received unknown CTCP PING"
  3024.                         " query to %s from user"
  3025.                         " \"%s\":")
  3026.                     rcvr sndr)
  3027.                 (irc-insert "%% \"%s\" (args)." args)
  3028.                 (irc-insert "%% This is probaly NOT a bug."))))))
  3029.            ((string= keyw "SOURCE")
  3030.         (let ((s irc-ftp-source))
  3031.           (while (not (null s))
  3032.             (let* ((r (car s))
  3033.                (site (nth 0 r))
  3034.                (dir (nth 1 r))
  3035.                (files (nth 2 r)))
  3036.               (irc-send
  3037.                (concat "NOTICE " sndr " :\001"
  3038.                    (irc-ctcp-enquote
  3039.                 (format "SOURCE %s:%s:%s"
  3040.                     site
  3041.                     dir
  3042.                     (irc-listify files " " "")))
  3043.                    "\001"))
  3044.               (setq s (cdr s))))
  3045.           (irc-send (concat "NOTICE " sndr " :\001SOURCE\001"))
  3046.           (if tell
  3047.               (irc-insert
  3048.                "%sAnswered (CTCP) SOURCE query to %s by %s%s"
  3049.                irc-msg-info-pre
  3050.                rcvr sndr
  3051.                irc-msg-info-post))))
  3052.            ((string= keyw "USERINFO") ;CLIENT_USERINFO
  3053.         (irc-send (concat "NOTICE " sndr " :\001"
  3054.                   (irc-ctcp-enquote
  3055.                    (concat "USERINFO :"
  3056.                        (if (stringp irc-userinfo)
  3057.                            irc-userinfo
  3058.                            "")))
  3059.                   "\001"))
  3060.         (if tell
  3061.             (irc-insert
  3062.              "%sAnswered (CTCP) USERINFO query to %s by %s%s"
  3063.              irc-msg-info-pre rcvr sndr irc-msg-info-post)))
  3064.            ((string= keyw "VERSION")
  3065.         (cond ((string-match (concat
  3066.                       "^ *\\([^: ]+\\) +v?\\([0-9]+[^ ]+\\)"
  3067.                       " +\\(.*\\) *$")
  3068.                      irc-version)
  3069.                (irc-send
  3070.             (concat "NOTICE " sndr " :\001"
  3071.                 (irc-ctcp-enquote
  3072.                  (format "%s %s:%s:%s, %s, emacs %s"
  3073.                      keyw
  3074.                      (subfield irc-version 1)
  3075.                      (subfield irc-version 2)
  3076.                      (subfield irc-version 3)
  3077.                      (cond
  3078.                        (irc-emacs-knows-ISO8859-1
  3079.                         "8bit ISO 8859-1 characters")
  3080.                        (irc-translation-table-incoming
  3081.                         "8bit characters")
  3082.                        (t (concat "7bit ISO 646 characters"
  3083.                               " (ie ASCII with"
  3084.                               " friends)")))
  3085.                      emacs-version))
  3086.                 "\001"))
  3087.                (if tell
  3088.                (irc-insert
  3089.                 "%sAnswered (CTCP) %s query to %s by %s%s"
  3090.                 irc-msg-info-pre keyw rcvr sndr
  3091.                 irc-msg-info-post)))
  3092.               (t (irc-send (concat "NOTICE " sndr " :\001"
  3093.                        (irc-ctcp-enquote
  3094.                         (format "%s Kiwi::%s"
  3095.                             keyw
  3096.                             irc-version))
  3097.                        "\001"))
  3098.              (cond
  3099.                (tell
  3100.                 (irc-insert
  3101.                  "%sAnswered (CTCP) %s query to %s by %s%s"
  3102.                  irc-msg-info-pre keyw rcvr sndr irc-msg-info-post)
  3103.                 (irc-insert "%% Client doesn't know who it is!")
  3104.                 (irc-insert "%% Please tell %s." irc-hacker))))))
  3105.            (t (and nil
  3106.                (irc-send
  3107.            (concat "NOTICE " sndr " :\001"
  3108.                (irc-ctcp-enquote
  3109.                 (concat "ERRMSG "
  3110.                     keyw
  3111.                     (if args
  3112.                     (concat " " args)
  3113.                     "")
  3114.                     " :Query is unknown"))
  3115.                "\001"))
  3116.                )
  3117.           (cond
  3118.             (tell
  3119.              (irc-insert (concat "%%Received unknown CTCP \"%s\" to %s"
  3120.                      " from user \"%s\".")
  3121.                  str rcvr sndr))))))))))
  3122.  
  3123.  
  3124. (defun irc-parse-ERR (str)
  3125.   "Examine a numeric ERR_ message from the IRC server. Numeric
  3126. control messages are used by newer servers to aid in generalized
  3127. client design; while people are converting to the new servers the
  3128. older irc-parse-error, irc-parse-notice, et al, functions are
  3129. redundant with irc-parse-ERR and irc-parse-RPL.  Values used by this
  3130. function are found in the IRC source file numeric.h.
  3131.  
  3132. Note well that some things are still going to come out wrong because the
  3133. servers are currently still doing things inconsistently."
  3134.   (if (not (string-match (concat "^:\\(.*\\) +\\([4-5][0-9][0-9]\\) +"
  3135.                  "\\([^: ]*\\)? *:? *\\(.*\\) *$")
  3136.              str))
  3137.       (progn
  3138.     (irc-insert (concat "%%Received an ERR message with unknown format in"
  3139.                 " function irc-parse-ERR:"))
  3140.     (irc-insert "%% \"%s\"." str)
  3141.     (irc-insert "%%Please report this to %s." irc-hacker))
  3142.       (let*
  3143.       ;; we assume that the server and message are consistent for us; just
  3144.       ;; worry about the numeric value and the rest of the line
  3145.       ((srvr (subfield str 1))
  3146.        (code (subfield str 2))
  3147.        (txt (subfield str 4))
  3148.        (num (string-to-int code))
  3149.        (parorg (if (string= (upcase srvr) (upcase irc-server))
  3150.                ""
  3151.                (concat "(" srvr ") ")))
  3152.        (tmp1 nil))
  3153.     (if (not (string= "" srvr))
  3154.         (irc-remember srvr 'irc-servernames))
  3155.     (cond
  3156.       ((= num 401)        ; ERR_NOSUCHNICK
  3157.        (cond ((string-match (concat "^[^: ]+ +401 +[^: ]+ +"
  3158.                     ":Hunting +for +ghosts +?.*$")
  3159.                 str)
  3160.           nil)        ;Ignore "Hunting for ghosts ?" message.
  3161.          ((string-match (concat "^[^: ]+ +401 +[^: ]+ +"
  3162.                     ":Cannot +kick +user +off +"
  3163.                     "channel *$")
  3164.                 str)
  3165.           (irc-insert "%%%sCan't boot that user from that channel."
  3166.                   parorg))
  3167.          ((string-match "^@?[^:@ ]+" txt)
  3168.           (let* ((user (substring txt
  3169.                       (match-beginning 0)
  3170.                       (match-end 0)))
  3171.              (is-service (irc-recall user 'irc-services)))
  3172.             (if is-service
  3173.             (irc-insert (concat "%%Service %s isn't reachable at"
  3174.                         " the moment, please try again"
  3175.                         " later.")
  3176.                     is-service)
  3177.             (progn
  3178.               (if (irc-is-nickname user)
  3179.                   (irc-forget user 'irc-nicknames))
  3180.               (irc-insert (concat
  3181.                        "%%%sThere is no user called"
  3182.                        " \"%s\" on IRC at the moment.")
  3183.                       parorg
  3184.                       user)))
  3185.             (if (and (>= irc-major-version 2)
  3186.                  (>= irc-minor-version 6))
  3187.             (irc-send (concat "WHOWAS :" user))
  3188.             )))
  3189.          (t (irc-insert (concat "%%%sUnrecognized NO SUCH NICK"
  3190.                     " message follows; please tell %s:")
  3191.                 parorg
  3192.                 irc-hacker)
  3193.             (irc-insert "%% \"%s\"." str)
  3194.             (irc-insert "%%Function irc-parse-err, at 401."))))
  3195.       ((= num 402)        ; ERR_NOSUCHSERVER
  3196.        (cond ((or (string-match (concat "^ *\\(.+\\) *: *"
  3197.                         "\\(\\*\\*\\* * \\)?No +such +"
  3198.                         "server *.? *$")
  3199.                     txt)
  3200.               (string-match (concat "^:? *\\** *No +such"
  3201.                         " +server *( *"
  3202.                         "\\([^: ]+\\) *) *.?"
  3203.                         " *$")
  3204.                     txt))
  3205.           (irc-insert (concat "%%%sThere is no server \"%s\" on the"
  3206.                       " IRCnet at the moment.")
  3207.                   parorg
  3208.                   (irc-nuke-whitespace (subfield txt 1))))
  3209.          (t (irc-insert (concat "%%Unknown ERR 402 message received"
  3210.                     " in function irc-parse-ERR:"))
  3211.             (irc-insert "%% txt=\"%s\"." txt)
  3212.             (irc-insert "%% Please tell %s, it might be a bug."
  3213.                 irc-hacker))))
  3214.       ((= num 403)        ; ERR_NOSUCHCHANNEL
  3215.        (if (string= (upcase srvr) (upcase irc-server))
  3216.            (let ((chn (if (string-match "^\\([^: ]+\\) *:.*$" txt)
  3217.                   (subfield txt 1))))
  3218.          (if chn
  3219.              (irc-insert (concat "%%%sThere is no channel called"
  3220.                      " \"%s\" in use right now.")
  3221.                  parorg chn)
  3222.              (irc-insert "%%%sNo such channel in use." parorg)))))
  3223.       ((= num 404)        ; ERR_CANNOTSENDTOCHAN
  3224.        (if (string-match "^ *\\([^ :]+\\) *:" txt)
  3225.            (irc-insert "%%%sChannel %s rejected the message."
  3226.                parorg (subfield txt 1))
  3227.            (irc-insert "%%%sChannel rejected the message." parorg)))
  3228.       ((= num 405)
  3229.        (cond ((string-match (concat "^ *\\([^ ]+\\) *: *You +have +joined"
  3230.                     " +too +many +channels.? *$")
  3231.                 txt)
  3232.           (irc-insert (concat "%%Failed joining channel %s, as you're"
  3233.                       " already listening to too many"
  3234.                       " channels.")
  3235.                   (subfield txt 1)))
  3236.          (t (irc-insert "*** %s %s." parorg txt))))
  3237.       ((= num 406)
  3238.        (if (string-match "^ *\\([^: ]+\\) *: *\\(.*\\) *$"
  3239.                  txt)
  3240.            (let ((m (substring txt (match-beginning 2) (match-end 2)))
  3241.              (n (substring txt (match-beginning 1) (match-end 1))))
  3242.          (irc-insert
  3243.           "%%No trace left about \"%s\" in history of server %s."
  3244.           n srvr))
  3245.            (progn
  3246.          (irc-insert "%%Unknown type 406 error message from server:")
  3247.          (irc-insert "%% \"%s\" (str)." str)
  3248.          (irc-insert "%% Please tell %s, it migth be a bug."
  3249.                  irc-hacker))))
  3250.       ((= num 409)
  3251.        ;txt="No origin specified"
  3252.        (irc-insert "%%%s%s" parorg txt))
  3253.       ((= num 411)        ; ERR_NORECIPIENT
  3254.        (irc-insert "%%%sThe last message had no recipient." parorg))
  3255.       ((= num 412)        ; ERR_NOTEXTTOSEND
  3256.        (irc-insert "%%%sThe last message had no text to send." parorg))
  3257.       ((= num 413)
  3258.        (irc-insert "%%%sNo top level domain specified (no such receiver)."
  3259.                parorg))
  3260.       ((= num 421)        ; ERR_UNKNOWNCOMMAND
  3261.        (cond ((string-match "^CLIENT-SYNCH :?\\(.*\\) *:Unknown command$"
  3262.                 txt)
  3263.           (let* ((cmd (irc-nuke-whitespace (subfield txt 1)))
  3264.              (ucmd (upcase cmd)))
  3265.             (cond 
  3266.              ((or t (string-match "^QUOTE " ucmd))
  3267.               (irc-insert "%sEnd of quoted command%s"
  3268.                   irc-msg-info-pre irc-msg-info-post))
  3269.              (t (irc-insert (concat "%%Unknown internal"
  3270.                         " synchronisation in"
  3271.                         " irc-parse-ERR at 421:"))
  3272.             (irc-insert "%% \"%s\" (txt)." txt)
  3273.             (irc-insert "%% Please tell %s, this *is* a bug."
  3274.                     irc-hacker)))))
  3275.          ((string-match (concat "^\\(MODE\\|KICK\\|JOIN\\|PART\\)"
  3276.                     ".*Unknown :?command *$")
  3277.                 txt)
  3278.           nil)
  3279.          ((string-match "^CLIENT-START *: *Unknown *command *$" txt)
  3280.           (run-hooks 'irc-startup-hook))
  3281.          ((or (string-match "^\\(.*\\) :?Unknown :?command$" txt)
  3282.               (string-match "^:?Unknown command \\(.*[^ ].*\\) *$"
  3283.                     txt))
  3284.           (if (string= (upcase irc-server) (upcase srvr))
  3285.               (irc-insert "%%%sUnknown server command: %s."
  3286.                   parorg
  3287.                   (subfield txt 1))))
  3288.          (t (irc-insert (concat "%%%sUnkown server command,"
  3289.                     " reported in unknown format:")
  3290.                 parorg)
  3291.             (irc-insert "%% \"%s\" (txt)." txt)
  3292.             (irc-insert "%% Function irc-parse-err, at 421."))))
  3293.       ((or (= num 422)        ;ERR_NOMOTD
  3294.            (= num 423))        ;ERR_NOADMIN
  3295.        (irc-insert "%%%s%s" parorg txt))
  3296.       ((= num 431)        ; ERR_NONICKNAMEGIVEN
  3297.        (irc-insert "%%%sNo nickname give to change to." parorg))
  3298.       ((= num 432)        ; ERR_ERRONEUSNICKNAME
  3299.        (irc-insert (concat "%%%sBad format for nickname change. Your"
  3300.                    " nickname is \"%s\".")
  3301.                parorg irc-nick-used))
  3302.       ((= num 433)        ; ERR_NICKNAMEINUSE
  3303.        (if (or (string-match (concat "^:[^: \t]+ +433 +"
  3304.                      "\\([^: \t]+\\) +"
  3305.                      "\\([^: \t]+\\) +:")
  3306.                  str)
  3307.            (string-match (concat "^:[^: \t]+ +433 +\\(\\)"
  3308.                      "\\([^: \t]+\\) +:")
  3309.                  str))
  3310.            (let ((current (subfield str 1))
  3311.              (failed (subfield str 2)))
  3312.          (irc-insert (concat "%%%sNickname \"%s\" is already being"
  3313.                      " used, please choose another one.")
  3314.                  parorg
  3315.                  failed)
  3316.          (irc-insert "%sHmmm ... looks like you're still %s%s"
  3317.                  irc-msg-info-pre
  3318.                  (if (string= current "")
  3319.                  (concat "without a nickname, use \"/HELP"
  3320.                      " NICK\" to get help about how to"
  3321.                      " set one")
  3322.                  (concat "\"" current "\""))
  3323.                  irc-msg-info-post))
  3324.            (irc-insert "%%Unknown ERR 433 type message received:")
  3325.            (irc-insert "%% \"%s\" (str)." str)
  3326.            (irc-insert "%% Please tell %s." irc-hacker)))
  3327.       ((= num 436)
  3328.        (cond ((string-match "^\\([^ :]+\\) :Nickname collision KILL$" txt)
  3329.           (let ((nick (subfield txt 1)))
  3330.             (irc-insert "%sUser %s killed due to NAMECLASH at %s%s"
  3331.                 irc-msg-info-pre
  3332.                 nick
  3333.                 srvr
  3334.                 irc-msg-info-post)
  3335.             (irc-forget nick 'irc-nicknames)))
  3336.          (t (irc-insert "%%Unknown ERR 436 type message received:")
  3337.             (irc-insert "%% \"%s\" (txt)." txt)
  3338.             (irc-insert "%% Please tell %s." irc-hacker))))
  3339.       ((= num 437) 
  3340.        (if (string-match "^\\([^:]+\\) : *\\(.+\\)" txt)
  3341.            (irc-insert "%%%s: %s" (subfield txt 2) (subfield txt 1))
  3342.          (irc-insert "%%Unknown ERR 436 type message received:")
  3343.          (irc-insert "%% \"%s\" (txt)." txt)
  3344.          (irc-insert "%% Please tell %s." irc-hacker)))
  3345.       ((= num 441)        ; ERR_USERNOTINCHANNEL
  3346.        (if (string= (upcase irc-server) (upcase srvr))
  3347.            (irc-insert "%%%sYou're not on any channel." parorg)))
  3348.       ((= num 442)        ; ERR_NOTONCHANNEL
  3349.        (cond ((or (string-match (concat "^ *\\([^ :]+\\) +"
  3350.                         "\\([^ :]+\\) *: *"
  3351.                         "\\([^ :]+\\) +is +not"
  3352.                         " +here *.? *$")
  3353.                     txt)
  3354.               (string-match (concat "^ *\\([^: ]+\\) *\\(\\):\\"
  3355.                         "([^: ]+\\) +is +not +here *$")
  3356.                     str))
  3357.           (let* ((o1 (subfield txt 1))
  3358.              (c (subfield txt 2))
  3359.              (o2 (subfield txt 3))
  3360.              (chn (if (string= c "") irc-channel c))
  3361.              (name (if (string= o1 o2)
  3362.                    o1
  3363.                    (concat o2 " (" o1 ")"))))
  3364.             (irc-insert (concat "%%You can't change the channel"
  3365.                     " operator status of %s while s/he"
  3366.                     " isn't here on %s.")
  3367.                 name chn)))
  3368.          ((string-match (concat "^ *\\([^ :]+\\) +\\([^ :]+\\)"
  3369.                     " *: *\\(isn't +on +your"
  3370.                     " +channel\\|Cannot +kick"
  3371.                     " +user +off\\ +channel\\)")
  3372.                 txt)
  3373.           (let ((who (subfield txt 1))
  3374.             (chn (subfield txt 2))
  3375.             (msg (subfield txt 3)))
  3376.             (cond ((string-match "^isn't" msg)
  3377.                (irc-insert (concat "%%Can't /KICK %s while"
  3378.                            " s/he's not on your"
  3379.                            " channel %s.")
  3380.                        who chn))
  3381.               (t (irc-insert (concat "%%Failed to /KICK %s from"
  3382.                          " channel %s.")
  3383.                      who chn)))))
  3384.          ((string-match (concat "^: *[^: ]+ +442 +[^: ]+"
  3385.                     " +\\([^: ]+\\) *: *"
  3386.                     "isn't *on *your *"
  3387.                     "channel *!* *$")
  3388.                 str)
  3389.           (let ((u (subfield str 1)))
  3390.             (irc-insert (concat "%%Can't /kick user %s while s/he's"
  3391.                     " not on this channel.")
  3392.                 u)))
  3393.          ((or (string-match (concat ":[^: ]+ +442 +[^: ]+"
  3394.                         " +\\([^: ]+\\) +: *You're +not"
  3395.                         " +on *\\(that\\)? +channel *$")
  3396.                     str)
  3397.               (string-match
  3398.                (concat "^:[^: ]+ +442 +[^: ]+ +\\([^ ]+\\) *: *Not"
  3399.                    " *On *Channel$")
  3400.                str)
  3401.               (string-match (concat "^[^: ]+ +442 +[^: ]+"
  3402.                         " +\\([^ ]+\\): *You're +not +on"
  3403.                         " +channel +\\([^ ]+\\) *$")
  3404.                     str)
  3405.               (string-match (concat "^:[^: ]+ +442 +[^: ]+"
  3406.                         " *: *You're +not on"
  3407.                         " +channel +\\([^ ]+\\) *$")
  3408.                     str))
  3409.           (let ((c (subfield str 1)))
  3410.             (irc-insert "%%You're not on channel %s." c)))
  3411.          ((string-match "^\\([^ :]+\\) *:\\(.*\\)$" txt)
  3412.           (irc-insert "%%%s: %s" (subfield txt 2) (subfield txt 1)))
  3413.          ((string= (upcase irc-server) (upcase srvr))
  3414.           (irc-insert (concat "%%Unknown format on"
  3415.                       " ERR_NOTONCHANNEL message;"
  3416.                       " please tell %s, it might be"
  3417.                       " a bug:")
  3418.                   irc-hacker)
  3419.           (irc-insert "%% \"%s\" (str)." str)
  3420.           (irc-insert "%% Function irc-parse-ERR, at 442."))))
  3421.       ((= num 443)
  3422.        (if (string-match (concat "^\\([^: ]+\\) +\\([^: ]+\\) +"
  3423.                      ":is already on channel.?$")
  3424.                  txt)
  3425.            (let ((nick (subfield txt 1))
  3426.              (chan (subfield txt 2)))
  3427.          (irc-insert "%%User %s is already on channel %s." nick chan))
  3428.            (irc-insert "%%Unknown ERR433 message seen in irc-parse-ERR:")
  3429.            (irc-insert "%% \"%s\" (txt)." txt)
  3430.            (irc-insert "%% Please tell %s." irc-hacker)))
  3431.       ((= num 444)
  3432.        (if (string-match "^\\([^: ]+\\) +:\\(.*\\)$" txt)
  3433.            (let ((user (subfield txt 1))
  3434.              (mesg (subfield txt 2)))
  3435.          (irc-insert "%%%sNo such user as \"%s\" logged in."
  3436.                  parorg user))
  3437.            (irc-insert "%%%sNo such user logged in." parorg)))
  3438.       ((= num 445)
  3439.        (irc-insert "%%%s%s" parorg txt))
  3440.       ((= num 446)
  3441.        (irc-insert "%%%sCommand /%s" parorg txt))
  3442.       ((= num 451)        ; ERR_NOTREGISTERED
  3443.        (irc-insert "%%%sYou haven't checked in yet.  Choose a nickname."
  3444.                parorg))
  3445.       ((= num 461)        ; ERR_NEEDMOREPARAMS
  3446.        (if (or (string= "" srvr)
  3447.            (string= (upcase irc-server) (upcase srvr)))
  3448.            (irc-insert (concat "%%%sThere weren't enough arguments for"
  3449.                    " the last command.")
  3450.                parorg)))
  3451.       ((= num 462)        ; ERR_ALREADYREGISTRED
  3452.        (irc-insert "%%%sYou've already registered." parorg))
  3453.       ((= num 463)        ; ERR_NOPERMFORHOST
  3454.        (irc-insert "%%%sYour host isn't permitted." parorg))
  3455.       ((= num 464)        ; ERR_PASSWDMISMATCH
  3456.        (irc-insert "%%%sThat password is incorrect." parorg))
  3457.       ((= num 465)        ; ERR_YOUREBANNEDCREEP
  3458.        (irc-insert "%%%sYou've been banned from IRC." parorg))
  3459.       ((= num 466)        ; ERR_YOUWILLBEBANNED
  3460.        (irc-insert "%%%sYou will be banned from IRC (%s)." parorg str))
  3461.       ((= num 467)
  3462.        (if (string-match "^\\([^ :]+\\) :" txt)
  3463.            (irc-insert (concat "%%%sChannel %s already has a key, use"
  3464.                    " /MODE %s to see it.")
  3465.                parorg
  3466.                (subfield txt 1)
  3467.                (subfield txt 1))
  3468.            (irc-insert (concat "%%%sChannel already has a key, use /MODE"
  3469.                    " to see it.")
  3470.                parorg)))
  3471.       ((= num 471)        ; ERR_CHANNELISFULL
  3472.        (string-match "^[^: ]+" txt)
  3473.        (let ((s (substring txt (match-beginning 0) (match-end 0))))
  3474.          (irc-insert (concat "%%%sChannel %s is full. (Check limit with"
  3475.                  " /MODE %s)")
  3476.              parorg s s)))
  3477.       ((= num 472)        ; ERR_UNKNOWNMODE
  3478.        (if (not (string-match (concat "^: *\\([^: ]+\\) +472 +"
  3479.                       "\\([^: ]+\\) +\\(.*\\) +:?is +"
  3480.                       "unknown +mode +char +to +me *$")
  3481.                   str))
  3482.            (progn (irc-insert (concat "%%Unrecognized type 472 message;"
  3483.                       " please tell %s:")
  3484.                   irc-hacker)
  3485.               (irc-insert "%% \"%s\"." str)
  3486.               (irc-insert "%% Function irc-parse-ERR, at 472."))
  3487.            (let ((srv (substring str (match-beginning 1) (match-end 1)))
  3488.              (nick (substring str (match-beginning 2) (match-end 2)))
  3489.              (chr (substring str (match-beginning 3) (match-end 3))))
  3490.          (if (not (string= (upcase srvr) (upcase srv)))
  3491.              (irc-remember srv 'irc-servernames))
  3492.          (irc-remember nick 'irc-nicknames)
  3493.          (irc-insert "%%Character \"%s\" is not a MODE character."
  3494.                  chr))))
  3495.       ((= num 473)        ; ERR_INVITEONLYCHAN
  3496.        (if (not (string-match (concat "^:[^: ]+ +473 +[^: ]+ +"
  3497.                       "\\([^ ]+\\) +.*")
  3498.                   str))
  3499.            (progn (irc-insert (concat "%%%sUnknown format on"
  3500.                       " ERR_INVITEONLYCHAN; please tell"
  3501.                       " %s, it might be a bug:")
  3502.                   parorg
  3503.                   irc-hacker)
  3504.               (irc-insert "%% \"%s\" (str)." str)
  3505.               (irc-insert "%% Function irc-parse-ERR, at 473."))
  3506.            (let ((chn (substring str (match-beginning 1) (match-end 1))))
  3507.          (irc-insert (concat "%%%sYou need an invitation to join"
  3508.                      " invitation-only channel \"%s\".")
  3509.                  parorg
  3510.                  chn))))
  3511.       ((= num 474)
  3512.        (cond
  3513.          ((string-match "^\\([^ ]+\\) +:" txt)
  3514.           (let ((channel (subfield txt 1)))
  3515.         (irc-insert (concat "%%Can't join channel %s -- you're"
  3516.                     " banned from it.")
  3517.                 channel)))
  3518.          (t (irc-insert "%%Unknown ERR474 seen in irc-parse-ERR:")
  3519.         (irc-insert "%% \"%s\" (txt)" txt)
  3520.         (irc-insert "%% Please tell %s, it might be a bug."
  3521.                 irc-hacker))))
  3522.       ((= num 475)            ;ERR_CANT_JOIN
  3523.        (cond ((string-match "^\\([^ ]+\\) +:" txt)
  3524.           (let ((channel (subfield txt 1)))
  3525.             (irc-insert (concat "%%Can't join channel %s -- you"
  3526.                     " haven't supplied the right channel"
  3527.                     " key/password.") channel)))
  3528.          (t (irc-insert "%%Unknown ERR475 seen in irc-parse-ERR:")
  3529.             (irc-insert "%% \"%s\" (txt)" txt)
  3530.             (irc-insert "%% Please tell %s, it might be a bug."
  3531.                 irc-hacker))))
  3532.       ((= num 481)        ; ERR_NOPRIVILEGES
  3533.        (if (string= (upcase irc-server) (upcase srvr))
  3534.            (if (string-match "CHANNEL" str)
  3535.            (irc-insert
  3536.             (concat "%%%sYou must be a channel operator"
  3537.                 " to "
  3538.                 (cond
  3539.                   ((string-match (concat ":Cannot set topic, not"
  3540.                              " channel OPER$")
  3541.                          str)
  3542.                    "set the channels topic.")
  3543.                   (t "do that.")))
  3544.             parorg)
  3545.            (irc-insert (concat "%%%sYou must be an enabled IRC"
  3546.                        " Operator to do THAT!")
  3547.                    parorg))))
  3548.       ((= num 482)        ; ERR_NOOPERHOST
  3549.        (if (and (irc-server-has-channelname-in-msgs)
  3550.             (string-match "^\\([^ ]+\\) *:.*$" txt))
  3551.            (irc-insert "%%%sYou're not a channel operator for %s!"
  3552.                parorg
  3553.                (subfield txt 1))
  3554.            (irc-insert (concat "%%%sYou're not a channel operator on"
  3555.                    " that channel!")
  3556.                parorg)))
  3557.       ((= num 491)        ; ERR_NOOPERHOST
  3558.        (irc-insert (concat "%%Password check failed at server %s,"
  3559.                    " you're still a disabled luser.")
  3560.                (upcase srvr)))
  3561.       ((= num 501)        ; ERR_UMODEUNKNOWNFLAG
  3562.        (irc-insert "%%%s." txt))
  3563.       ((= num 502)        ; ERR_USERSDONTMATCH
  3564.        (irc-insert (concat "%%You can't change, not even look at, other"
  3565.                    " user's modes.")))
  3566.       ((= num 513)
  3567.        (if (string-match "^To connect, type /QUOTE PONG \\([1-9][0-9]*\\)$"
  3568.                  txt)
  3569.            (irc-send (format "PONG :%s" (subfield txt 1)))
  3570.          (irc-insert "%%Unknown MSG 513 \"%s\"" txt)))
  3571.       (t                                 ; default
  3572.        (irc-insert (concat "%%%sUnrecognized numeric ERR message"
  3573.                    " follows; please tell %s:")
  3574.                parorg
  3575.                irc-hacker)
  3576.        (irc-insert "%% \"%s\" (str)." str)
  3577.        (irc-insert "%%Function irc-parse-err, at catch all.")))))
  3578.   nil)
  3579.  
  3580.  
  3581. (defun irc-parse-error (str)
  3582.   "Examine an ERROR message from the IRC server.
  3583. ERROR is used when something bogus happens like an unparsable command
  3584. is issued to the server.  Usually this will not happen unless something
  3585. like /QUOTE is used.  This message is also used when a user attempts to
  3586. change to a name that already exists.
  3587.  
  3588. Returns nil; currently no signals are issued for an error."
  3589.   (string-match " +:" str)        ;Skip "^ERROR :"
  3590.   (setq str (substring str (match-end 0)))
  3591.   (cond
  3592.     ((string-match (concat "^ *Nickname +[^: ]* +\\(is \\)?"
  3593.                "\\(already\\|not +chan\\|in use\\) *$")
  3594.            str)
  3595.      (irc-insert "%%%s" str)
  3596.      ;; either we couldn't change the current nickname
  3597.      (setq irc-nick (or (and irc-nick (get 'irc-nick 'o-nick))
  3598.             ;; or we never even had one
  3599.             "NO NAME YET (/NICK to set one)"))
  3600.      (set-buffer-modified-p (buffer-modified-p))
  3601.      (irc-insert (if (get 'irc-nick 'o-nick)
  3602.              "%sHmmm ... looks like you're still \"%s\"%s" 
  3603.              "%s%s%s")
  3604.          irc-msg-info-pre
  3605.          irc-nick
  3606.          irc-msg-info-post))
  3607.     ((string-match " *No +option +specified. *Try +MAIL +HELP *$" str)
  3608.      (irc-insert "%%No option specified; try /HELP MAIL and /MAIL HELP."))
  3609.     ((or (string-match (concat "Closing +Link *: *\\([^[ :]+\\[[^]]+\\]\\)"
  3610.                    " *\\(\\)(\\(.*\\)) *$")
  3611.                str)
  3612.      (string-match (concat "Closing +Link *: *\\([^ :]+\\) +\\([^ :]+\\)"
  3613.                    " *\\(.\\|\n\\)+$")
  3614.                str))
  3615.      (let* ((id (subfield str 1))
  3616.         (srce (subfield str 2))
  3617.         (preason (subfield str 3))
  3618.         (reason (if (and (> (length preason) 0)
  3619.                  (= ?\050 (aref preason 0))
  3620.                  (= ?\051 (aref preason (1- (length preason)))))
  3621.             (substring preason 1 (1- (length preason)))
  3622.             preason))
  3623.         (matches (string-match "^\\([^[]+\\)\\[\\([^]]+\\)\\]$" id))
  3624.         (nick (if matches (subfield id 1) ""))
  3625.         (host (if matches (subfield id 2) "")))
  3626.        (irc-parse-quit (format ":%s QUIT %s :%s"
  3627.                    nick
  3628.                    nick
  3629.                    reason))))
  3630.     (t (irc-insert "%%%s" str)))
  3631.   nil)
  3632.  
  3633.  
  3634. (defun irc-parse-invite (str)
  3635.   "Examine an INVITE message from the IRC server.
  3636. INVITE is sent when one user invites another to a channel.
  3637. If the inviter is not being ignored a message is inserted in the buffer.
  3638.  
  3639. This function returns t if a bell should be issued for the \"invite\" event,
  3640. nil otherwise."
  3641.   (let ((user (substring str 1 (string-match " +INVITE " str)))
  3642.         (to (substring str (match-end 0)
  3643.                        (string-match " +:?" str (match-end 0))))
  3644.         (channel (substring str (match-end 0))))
  3645.     ;; glom a new name, if necessary
  3646.     (irc-remember user 'irc-nicknames)
  3647.     (if (irc-recall user 'irc-ignored-ppl)
  3648.         (irc-send (concat "NOTICE " user " :You are being ignored by \""
  3649.               irc-nick-used
  3650.               "\"."))
  3651.     (progn
  3652.       (irc-insert "%sUser %s invites %s to join channel %s%s"
  3653.               irc-msg-info-pre
  3654.               user
  3655.               (if (string= (downcase to) (downcase irc-nick-used))
  3656.               "you"
  3657.               to)
  3658.               (irc-clean-up-message channel)
  3659.               irc-msg-info-post)
  3660.       (irc-signal user 'invite)))))
  3661.  
  3662.  
  3663. (defun irc-parse-kick (str)
  3664.   "Examine and display a KICK message."
  3665.   (if (not
  3666.        (string-match "^: *\\([^: ]+\\) +KICK +\\([^: ]+\\) +\\([^: ]+\\) *"
  3667.              str))
  3668.       (progn (irc-insert (concat "%%Unknown format on KICK message; please"
  3669.                  " tell %s, it might be a bug:")
  3670.              irc-hacker)
  3671.          (irc-insert "%% \"%s\" (str)." str)
  3672.          (irc-insert "%% Function irc-parse-kick."))
  3673.       (let ((actor (substring str (match-beginning 1) (match-end 1)))
  3674.         (chan (substring str (match-beginning 2) (match-end 2)))
  3675.         (victim (substring str (match-beginning 3) (match-end 3))))
  3676.     (irc-remember actor 'irc-nicknames)
  3677.     (irc-remember victim 'irc-nicknames)
  3678.     (cond ((and (string= (upcase actor) (upcase victim))
  3679.             (string= (upcase actor) (upcase irc-nick-used)))
  3680.            (irc-insert "%sYou kicked yourself from channel %s%s"
  3681.                irc-msg-info-pre chan irc-msg-info-post))
  3682.           ((string= (upcase actor) (upcase victim))
  3683.            (irc-insert "%sUser %s kicked him/herself from channel %s%s"
  3684.                irc-msg-info-pre actor chan irc-msg-info-post))
  3685.           ((string= (upcase victim) (upcase irc-nick-used))
  3686.            (irc-insert (concat "%%You have been kicked out from"
  3687.                    " channel %s by user %s.")
  3688.                chan
  3689.                actor))
  3690.           ((string= (upcase actor) (upcase irc-nick-used))
  3691.            (irc-insert (concat "%sYou have kicked out user %s from"
  3692.                    " channel %s%s")
  3693.                irc-msg-info-pre
  3694.                victim
  3695.                chan
  3696.                irc-msg-info-post))
  3697.           (t (irc-insert (concat "%sUser %s kicked out user %s"
  3698.                      " from channel %s%s")
  3699.                  irc-msg-info-pre
  3700.                  actor
  3701.                  victim
  3702.                  chan
  3703.                  irc-msg-info-post)))
  3704.     (if (string= (upcase victim) (upcase irc-nick-used))
  3705.         ;; No need to irc-maintain the victim, -parse-chan does that.
  3706.         (progn (if (irc-server-has-multijoinable-channels)
  3707.                (irc-parse-channel (concat ":" victim " PART " chan))
  3708.                (irc-parse-channel (concat ":" victim " CHANNEL 0")))
  3709.            t)
  3710.         nil))))
  3711.  
  3712.  
  3713. (defun irc-parse-kill (str)
  3714.   "Examine a KILL message from the IRC server.
  3715. For a client this means its connexion will be closing momentarily.  This rather
  3716. drastic turn of events will always get a signal so this function returns t."
  3717.   (if (not (string-match "\\(:[^: ]+ +\\)?KILL +\\([^: ]+\\) +:" str))
  3718.       (progn
  3719.     (irc-insert "%%Spurios KILL message: \"%s\" (str) in irc-parse-kill."
  3720.             str)
  3721.     (irc-insert "%% Please tell %s, it might be a bug." irc-hacker))
  3722.       (let* ((s (subfield str 1))
  3723.          (v (subfield str 2))
  3724.          (i (substring str (match-end 0)))
  3725.          (server (irc-nuke-whitespace s))
  3726.          (victim (irc-nuke-whitespace v))
  3727.          (info (irc-nuke-whitespace i)))
  3728.     (cond ((string-match "\\([^!]+\\)!\\([^! ]+\\) +"
  3729.                  info)
  3730.            (let* ((s (subfield info 1))
  3731.               (o (subfield info 2))
  3732.               (m (substring info (match-end 0)))
  3733.               (c (if (and (= ?\050 (aref m 0))
  3734.                   (= ?\051 (aref m (1- (length m)))))
  3735.                  (substring m 1 (1- (length m)))
  3736.                  m)))
  3737.          (if (string= (upcase irc-nick-used) (upcase victim))
  3738.              (irc-insert (concat "%sYou have been /KILL'ed by operator"
  3739.                      " %s@%s (%s)%s")
  3740.                  irc-msg-info-pre
  3741.                  (irc-nuke-whitespace o)
  3742.                  (irc-nuke-whitespace s)
  3743.                  (irc-nuke-whitespace c)
  3744.                  irc-msg-info-post)
  3745.              (irc-insert "%sOperator %s@%s /KILL'ed user %s (%s)%s"
  3746.                  irc-msg-info-pre
  3747.                  (irc-nuke-whitespace o)
  3748.                  (irc-nuke-whitespace s)
  3749.                  victim
  3750.                  (irc-nuke-whitespace m)
  3751.                  irc-msg-info-post))))
  3752.           (t (irc-insert "%sUser %s KILL'ed by %s%s"
  3753.                  irc-msg-info-pre
  3754.                  victim
  3755.                  info
  3756.                  irc-msg-info-post)))))
  3757.   t)
  3758.  
  3759.  
  3760. (defun irc-parse-linreply (str)
  3761.   "Examine a LINREPLY message from the IRC server.
  3762. LINREPLY is used to answer a LINKS request to show all the servers on line.
  3763. \"Links\" is a bit of a misnomer since little information regarding the
  3764. actual structure of the IRCnet can be gained from these messages.
  3765.  
  3766. No signals are issued for lines from the LINREPLY."
  3767.   (if (not (string-match "^LINREPLY +\\([^: ]+\\) +" str))
  3768.       (progn (irc-insert (concat "%%Unkown LINREPLY format in "
  3769.                  "function irc-parse-linreply:"))
  3770.          (irc-insert "%% \"%s\"." str)
  3771.          (irc-insert "%% Please tell %s, it may be a bug." irc-hacker))
  3772.       (let ((old-mark irc-mark)
  3773.         (server-name (substring str (match-beginning 1) (match-end 1)))
  3774.         (server-info (irc-clean-up-message (substring str (match-end 0)))))
  3775.     (irc-remember server-name 'irc-servernames)
  3776.     (if (and (irc-terminal-is-slow)
  3777.          (or (irc-server-has-end-of-links) ;New server version ?
  3778.              (and (= irc-major-version 2) (= irc-minor-version 2))))
  3779.         (progn (irc-remember (format "Server %s: %s"
  3780.                      (upcase server-name)
  3781.                      server-info)
  3782.                  'irc-linksinfo)
  3783.            (if (and (not (irc-terminal-is-slow))
  3784.                 (string= (upcase server-name) (upcase irc-server)))
  3785.                (progn
  3786.              (irc-insert irc-links-header)
  3787.              (irc-insert irc-links-stroke)
  3788.              (set-buffer-modified-p (buffer-modified-p))
  3789.              (irc-recall-all-and-display 'irc-linksinfo
  3790.                              (progn
  3791.                                (string-match
  3792.                             "^[^: ]* ."
  3793.                             irc-links-header)
  3794.                                (match-end 0))
  3795.                              "servers"
  3796.                              "server")
  3797.              (irc-forget-all 'irc-linksinfo))))
  3798.     (progn (irc-insert "Server %s: %s"
  3799.                    (upcase server-name)
  3800.                    server-info)))))
  3801.   nil)
  3802.  
  3803.  
  3804. (defun irc-parse-mode-reply (str)
  3805.   "Examine a MODE reply message from the IRC server.
  3806. MODE replies are used in respnse to the MODE command to indicate the current,
  3807. ie new, status of a specified channel or user.
  3808.  
  3809. No signals are issued for MODE replies."
  3810.   (cond ((string-match (concat "^ *: *\\([^: ]+\\) +MODE +"
  3811.                    "\\([^: ]+\\) +:? *")
  3812.                str)
  3813.      (let ((orig (subfield str 1))
  3814.            (chan (subfield str 2))
  3815.            (mode (irc-nuke-whitespace (substring str (match-end 0)))) )
  3816.        (cond ((irc-is-hostname orig)
  3817.           (irc-remember orig 'irc-servernames))
  3818.          ((irc-is-nickname orig)
  3819.           (irc-remember orig 'irc-nicknames)))
  3820.        (cond ((irc-is-nickname chan)
  3821.           (let ((i (1- (length mode)))
  3822.             (um (upcase mode)))
  3823.             (while (and (>= i 0) (not (= ?O (aref um i))))
  3824.               (setq i (1- i)))
  3825.             (while (and (>= i 0)
  3826.                 (not (= ?- (aref um i)))
  3827.                 (not (= ?+ (aref um i))))
  3828.               (setq i (1- i)))
  3829.             (if (and (>= i 0) (= ?- (aref um i)))
  3830.             (setq irc-operator nil)
  3831.             (set-buffer-modified-p (buffer-modified-p))))
  3832.           (irc-insert "%sMode for user %s changed by %s: %s%s"
  3833.                   irc-msg-info-pre
  3834.                   chan
  3835.                   orig
  3836.                   (irc-explain-user-mode mode)
  3837.                   irc-msg-info-post))
  3838.          ((irc-is-nickname orig)
  3839.           (irc-insert "%sUser %s changed mode for channel %s: %s%s"
  3840.                   irc-msg-info-pre
  3841.                   orig
  3842.                   chan
  3843.                   (irc-explain-channel-mode mode)
  3844.                   irc-msg-info-post))
  3845.          ((irc-is-hostname orig)
  3846.           (irc-remember orig 'irc-servernames))
  3847.          (t (irc-insert "%%Unknown sender in irc-parse-mode-reply:")
  3848.             (irc-insert "%% \"%s\" (str), \"%s\" (orig)." str orig)
  3849.             (irc-insert "%% Please tell %s, this might be a bug."
  3850.                 irc-hacker)))))
  3851.     (t (irc-insert "%%Unkown format on MODE reply; please tell %s:"
  3852.                irc-hacker)
  3853.        (irc-insert "%% \"%s\"." str)
  3854.        (irc-insert "%% Function irc-parse-mode-reply.")))
  3855.   nil)
  3856.  
  3857.  
  3858. (defun irc-parse-namreply (str)
  3859.   "Examine a NAMREPLY message from the IRC server.
  3860. NAMREPLY is used in repsonse to NAMES to indicate what users are on what
  3861. channels.  All users on secret or private channels which the client is not
  3862. on are grouped together on one private channel.
  3863.  
  3864. No signals are issued for NAMREPLYs."
  3865.   (if (not (string-match "^NAMREPLY +[^ ]+ +\\([^ ]+\\) +" str))
  3866.       (progn (irc-insert (concat "%%Unknown format on NAMREPLY message,"
  3867.                  " in function IRC-PARSE-NAMREPLY:"))
  3868.          (irc-insert "%% \"%s\"." str))
  3869.       (let* ((channel (substring str (match-beginning 1) (match-end 1)))
  3870.          (users (substring str (match-end 0)))
  3871.          (count 0)
  3872.          (to-insert "")
  3873.          (nick nil)
  3874.          (format-string "%s  %3d   %s")
  3875.          (irc-msg-cont-used irc-names-cont-msg))
  3876.     ;; yet another source of information for irc-nicknames.
  3877.     (while (string-match "^\\([^ ]+\\)\\( \\|$\\)" users)
  3878.       (setq nick (substring users 0 (match-end 1))
  3879.         users (substring users (match-end 0))
  3880.         count (1+ count)
  3881.         to-insert (concat to-insert " " nick))
  3882.       (irc-remember nick 'irc-nicknames)) 
  3883.     (if (and (irc-terminal-is-slow) (irc-server-has-end-of-names))
  3884.         (let ((lin (format format-string
  3885.                 (irc-format-channel channel)
  3886.                    count
  3887.                    (irc-clean-up-message to-insert))))
  3888.           (setq irc-reply-count (1+ irc-reply-count))
  3889.           (let ((diff (irc-time-diff (irc-current-time)
  3890.                      irc-reply-count-time)))
  3891.         (cond ((or (> (nth 1 diff) 5) ;At least 5 seconds since last
  3892.                (> (nth 0 diff) 0)) ; display?
  3893.                (setq irc-reply-count-time (irc-current-time))
  3894.                (message (format " %d channel%s ..."
  3895.                     irc-reply-count
  3896.                     (if (= 1 irc-reply-count) "" "s"))))))
  3897.           (irc-remember lin 'irc-namtree))
  3898.         (irc-insert format-string
  3899.             (irc-format-channel channel)
  3900.             count
  3901.             (irc-clean-up-message to-insert)))))
  3902.   nil)
  3903.  
  3904.  
  3905. (defun irc-parse-nick (str)
  3906.   "Examine a NICK message from the IRC server.
  3907. NICK is sent when a user's nickname is changed, but it is only sent to the
  3908. people on the same channel as the user.  If the person changing names is
  3909. being ignored, this fact is tracked across the change.  If notification
  3910. is not enabled for \"nick\" then no message is inserted.
  3911.  
  3912. This function returns t if a signal should be issued for the \"nick\" event,
  3913. nil otherwise."
  3914.   (cond ((string-match "^: *\\([^ :]+\\) +NICK +:?\\([^ :]+\\) *$" str)
  3915.      (let* ((old (subfield str 1))
  3916.         (new (subfield str 2))
  3917.         (current irc-nick-used))
  3918.        (if (not (irc-recall old 'irc-services)) ;Always keep /services.
  3919.            (irc-forget old 'irc-nicknames))
  3920.        (irc-remember new 'irc-nicknames)
  3921.        (cond ((string= (upcase irc-nick-used) (upcase old))
  3922.           ;; Our own nick has changed.
  3923.           (setq irc-nick-used new)
  3924.           (set-buffer-modified-p (buffer-modified-p))))
  3925.        (cond ((irc-recall old 'irc-ignored-ppl)
  3926.           (irc-forget old 'irc-ignored-ppl)
  3927.           (irc-remember new 'irc-ignored-ppl)
  3928.           nil)            ;Don't signal this.
  3929.          ((and (memq 'nick irc-events)
  3930.                (not (string= (upcase new) (upcase current))))
  3931.           (irc-insert "%s%s is now known as %s%s"
  3932.                   irc-msg-info-pre old new irc-msg-info-post)
  3933.           (irc-signal old 'user))
  3934.          (t nil))))
  3935.     (t (irc-insert "%%Unknown NICK seen in irc-parse-nick:")
  3936.        (irc-insert "%% \"%s\" (str)." str)
  3937.        (irc-insert "%% Please tell %s, this might be a bug." irc-hacker))))
  3938.  
  3939.  
  3940. ;irc-remember
  3941. (defun irc-parse-notice (str)
  3942.   "Examine a NOTICE message from the IRC server.
  3943. NOTICE is the catch-all for IRC messages; if it can't be classified as
  3944. one of the other currently existing messages then the information is
  3945. sent as NOTICE.  This message is overused, even when it another could be
  3946. used instead.  For example, if an attempt is made to send to a nickname
  3947. which is not on IRC the error reply is sent via NOTICE.
  3948.  
  3949. No signal is issued for NOTICE because it is way too random with what it
  3950. means."
  3951.   (let* ((lst (if (string-match (concat "^ *:? *\\([^: ]*\\)? *NOTICE *"
  3952.                     "\\([^: ]*\\)? *:")
  3953.                 str)
  3954.           (list (substring str (match-beginning 1) (match-end 1)) ;srvr
  3955.             (substring str (match-beginning 2) (match-end 2)) ;rcvr
  3956.             (substring str (match-end 0))) ;msg
  3957.           (list "" "" str)))
  3958.      (srvnam (if (string= (car lst) "") irc-server (car lst)))
  3959.      (srvr (if (string= (upcase srvnam) (upcase irc-server)) "" srvnam))
  3960.      (parorg (if (string= "" srvr) "" (concat "(" srvr ") ")))
  3961.      (rcvr (car (cdr lst)))
  3962.      (msg (car (cdr (cdr lst))))
  3963.      (cmsg (irc-clean-up-message msg))
  3964.      (retval nil))            ;Kludge!
  3965.     (if (not (stringp irc-server))
  3966.     (setq irc-server (if (stringp (default-value 'irc-server))
  3967.                  (default-value 'irc-server)
  3968.                  "")))
  3969.     (if (and rcvr (irc-is-nickname rcvr))
  3970.     (setq irc-nick-used rcvr))
  3971.     (irc-remember srvr 'irc-servernames)
  3972.     (cond
  3973.       ((and (string= "POXAV" (upcase srvr))
  3974.         (string-match "weenie" msg))
  3975.        )
  3976.       ((irc-recall srvr 'irc-services)
  3977.        (irc-remember srvr 'irc-services) ;Update spelling.
  3978.        (irc-remember srvr 'irc-nicknames)
  3979.        (irc-insert "%s%s%s %s"
  3980.            irc-msg-info-pre srvr irc-msg-info-post cmsg))
  3981.       ((string-match (concat "^\\*\\*\\* *Notice *-- *Access *denied *"
  3982.                  "(\\(.*\\)) *\\(.*\\) *$")
  3983.              msg)
  3984.        (let ((reason (subfield msg 1))
  3985.          (refused-server (subfield msg 2)))
  3986.      (irc-insert "%%Refused server-link connection from server %s: %s."
  3987.              (upcase refused-server)
  3988.              reason)))
  3989.       ((string-match (concat "^\\*\\*\\* *Notice *-- *Rehashing *Server"
  3990.                  " *config *file *(\\(.*\\)) *$")
  3991.              msg)
  3992.        (let ((file (subfield msg 1)))
  3993.      (irc-insert "%sServer %s has reloaded it's configuration file %s%s"
  3994.              irc-msg-info-pre
  3995.              (upcase srvnam)
  3996.              file
  3997.              irc-msg-info-post)))
  3998.       ((string-match (concat "^\\*\\*\\* *Notice *-- *\\(Hack\\|Fake\\) *:"
  3999.                  " *\\([^ ]+\\) +MODE +\\([^ ]+\\)"
  4000.                  " *\\([^ ]*\\).*$")
  4001.              msg)
  4002.        ;;Ignore this information. It's just a way for enabled operators on 2.7
  4003.        ;; server to see people on 2.6 server as they join channels with initial
  4004.        ;; modes, such as secret or private. Hopefulle this will go away when
  4005.        ;; 2.6 servers go way.
  4006.        (let ((user (subfield msg 2))
  4007.          (channel (subfield msg 3))
  4008.          (mode (irc-nuke-whitespace (subfield msg 4))))
  4009.      (cond ((string-match "\\+[^-]*[sp]" mode)
  4010.         (irc-insert (concat "%sWarning a user about seeing her/his"
  4011.                     " secret channel join%s")
  4012.                 irc-msg-info-pre irc-msg-info-post)
  4013.         (irc-send (concat "NOTICE " user " :<Automatic warning> My"
  4014.                   " client (but not I myself -- I don't even"
  4015.                   " know who you are unless you'll tell me or"
  4016.                   " you happen to be marked as being AWAY)"
  4017.                   " saw you join channel "
  4018.                   channel
  4019.                   " ("
  4020.                   mode
  4021.                   "). The fact was broadcasted to everyone"
  4022.                   " seeing WALLOPS messages on 2.7 (and later)"
  4023.                   " servers. Your channel is probably"
  4024.                   " without any special mode on other servers."
  4025.                   " (But still look \"valid\" at yous site)."
  4026.                   " If you have any questions, then don't send"
  4027.                   " them to "
  4028.                   irc-nick
  4029.                   " but to the channel #Twilight_Zone."
  4030.                   ))
  4031.         (irc-send (concat "NOTICE " user " :<Automatic warning> If"
  4032.                   " you don't care about getting warned, but"
  4033.                   " want to think you're invisible while being"
  4034.                   " visible, and you happen to use a Kiwi"
  4035.                   " client, you can do M-x set-variable RET"
  4036.                   " irc-ignore-automatic-warnings RET t"
  4037.                   " RET. If you're using ircII, instead do"
  4038.                   " /on ^notice \"" irc-nick " <Automatic"
  4039.                   " warning>*\: /^comment"))
  4040.         ))))
  4041.       ((string-match (concat "^\\*\\*\\* Message-of-today is missing"
  4042.                  " on host \\([^: ]+\\)? *$")
  4043.              msg)
  4044.        (let ((host (irc-clean-up-message (subfield msg 1))))
  4045.      (if (not (string= (upcase srvr) (upcase host)))
  4046.          (irc-remember host 'irc-servernames))
  4047.      (irc-insert "%%%sNo message of the day at server %s."
  4048.              (if (or (string= srvr irc-server)
  4049.                  (string= srvr ""))
  4050.              ""
  4051.              (concat "(" srvr ") "))
  4052.              (upcase host))))
  4053.       ((string-match "^MOTD *- ?*\\([^: ]+\\)? *message +of +the +day *-? *$"
  4054.              msg)
  4055.        (let ((server (irc-clean-up-message (substring msg
  4056.                               (match-beginning 1)
  4057.                               (match-end 1)))))
  4058.      (if (not (string= (upcase srvr) (upcase server)))
  4059.          (irc-remember server 'irc-servernames))
  4060.      (irc-insert "")
  4061.      (irc-insert ">>> Message of the day at server %s:" server)
  4062.      (set-buffer-modified-p (buffer-modified-p))))
  4063.       ((string-match "^MOTD *- ?" msg)
  4064.        (setq irc-motd-lines (append irc-motd-lines
  4065.                     (list (irc-clean-up-message
  4066.                        (substring msg (match-end 0)))))))
  4067.       ((string-match "^\\* *end +of +/?motd +command. *$" msg)
  4068.        (while irc-motd-lines
  4069.      (irc-insert ">>> %s" (car irc-motd-lines))
  4070.      (setq irc-motd-lines (cdr irc-motd-lines))))
  4071.       ((string-match (concat "^\\*\\*\\* *Error *: *No +mere +mortals +"
  4072.                  "may +trace +the +nets +of +the +universe *$")
  4073.              msg)
  4074.        (irc-insert (concat "%%%sYou must be an enabled IRC operator to trace"
  4075.                " the IRCnet, use /OPER to enable yourself. An"
  4076.                " alternative is to use /STATS L, do /HELP STATS.")
  4077.            parorg))
  4078.       ((string-match "^Good afternoon, gentleman\\. I am a HAL 9000" msg)
  4079.        (if (string= srvr "")
  4080.        (irc-insert "%sOperator status for %s ENABLED%s"
  4081.                irc-msg-info-pre
  4082.                irc-nick-used
  4083.                irc-msg-info-post)
  4084.        (irc-insert "%sOperator status at %s for %s ENABLED%s"
  4085.                irc-msg-info-pre
  4086.                srvr
  4087.                irc-nick-used
  4088.                irc-msg-info-post))
  4089.        ;; we've been granted operator privileges.  the string is for mode-line
  4090.        (setq irc-operator " IOPR")
  4091.        (set-buffer-modified-p (buffer-modified-p)))
  4092.       ((string-match (concat "^\\*\\*\\* *notice *-- *Received"
  4093.                  " +unauthorized +connection +from +")
  4094.              msg)
  4095.        (irc-insert (concat "%%Something at internet host %s tried to"
  4096.                " establish a connection with us. Refused"
  4097.                " as it isn't enabled in the confiugation file.")
  4098.            (irc-nuke-whitespace (substring msg (match-end 0)))))
  4099.       ((string-match (concat "^\\*\\*\\* *Notice *\\(:\\|--\\) *Link"
  4100.                  " +with +\\([^ ]+\\) +established"
  4101.                  " *.? *$")
  4102.              msg)
  4103.        ;; In a few seconds, we ought to issue a LINKS command to the server,
  4104.        ;; but without displaying the answer, only storing it. Sigh.
  4105.        (let* ((h (irc-extract-hostname
  4106.           (irc-clean-up-message
  4107.            (subfield msg 2))))
  4108.           (host (if (stringp h) h "")))
  4109.      (if (not (string= (upcase srvr) (upcase host)))
  4110.          (irc-remember host 'irc-servernames))
  4111.      (irc-insert "%s%sLink with %s established%s"
  4112.              irc-msg-info-pre
  4113.              (if (string= srvr "") "" (concat "(" srvr ")"))
  4114.              (upcase host)
  4115.              irc-msg-info-post))
  4116.        (irc-later-execute-lusers))
  4117.       ((or (string-match (concat "^\\*\\*\\* *\\([^ ]+\\) +\\([^:]+\\) *"
  4118.                  "==> *\\(.+\\) *$")
  4119.              cmsg)
  4120.        ;; 2.6 following
  4121.        (string-match (concat "^\\*\\*\\* +\\(Connection\\) +\\([^ ]+\\) +"
  4122.                  "==> +\\([^ ]+\\) +\\[\\([^ ]+\\)\\] *$")
  4123.              cmsg)
  4124.        (string-match (concat "^\\*\\*\\* +\\(Connection\\) +\\([^ ]+\\) +"
  4125.                  "==> +\\([^ ]+\\) *$")
  4126.              cmsg)
  4127.        (string-match (concat "^\\*\\*\\* +\\(Link\\) +\\([^ ]+\\) +"
  4128.                  "==> +\\([^ ]+\\) *$")
  4129.              cmsg)
  4130.        (string-match (concat "^\\*\\*\\* +\\(<newtype>\\) +\\([^ ]+\\) +"
  4131.                  "==> +\\([^ ]+\\) *$")
  4132.              cmsg))
  4133.        (let* ((type (substring cmsg (match-beginning 1) (match-end 1)))
  4134.           (lcl (substring cmsg (match-beginning 2) (match-end 2)))
  4135.           (remote (substring cmsg (match-beginning 3) (match-end 3)))
  4136.           (address (if (match-beginning 4)
  4137.                (substring cmsg (match-beginning 4) (match-end 4))
  4138.                remote))
  4139.           (extra (cond
  4140.                ((not (string= (upcase remote) (upcase address)))
  4141.             (concat "(" address ")"))
  4142.                ((string-match
  4143.              "^\\([^ ]+\\) +\\([0-9]+\\)S +\\([0-9]+\\)C$"
  4144.              remote)
  4145.             (let ((x (subfield remote 1))
  4146.                   (s (string-to-int (subfield remote 2)))
  4147.                   (c (string-to-int (subfield remote 3))))
  4148.               (setq remote x)
  4149.               (format " (%d server%s, %d client%s)"
  4150.                   s
  4151.                   (if (= 1 s) "" "s")
  4152.                   c
  4153.                   (if (= 1 c) "" "s"))))
  4154.                (t "")))
  4155.           (p (cond
  4156.            ((string-match "^ *CLASS\\[\\([0-9]+\\)\\] +\\([^: ]+\\) *$"
  4157.                   lcl)
  4158.             (cons (subfield lcl 2) (subfield lcl 1)))
  4159.            ((string-match "^ *CLASS\\[\\([0-9]+\\)\\] *$" lcl)
  4160.             (cons srvr (subfield lcl 1)))
  4161.            (t (cons lcl nil))))
  4162.           (local (irc-nuke-whitespace (car p)))
  4163.           (class (cdr p))
  4164.           (lserv (irc-extract-hostname local))
  4165.           (rserv (irc-extract-hostname remote)))
  4166.      (if (and lserv (not (string= (upcase srvr) (upcase lserv))))
  4167.          (irc-remember lserv 'irc-servernames))
  4168.      (if (and rserv (not (string= (upcase srvr) (upcase rserv))))
  4169.          (irc-remember remote 'irc-servernames))
  4170.      (cond
  4171.        ((string= (upcase type) "LINK")
  4172.         (irc-insert "%s%s to %s%s goes through %s%s"
  4173.             irc-msg-info-pre
  4174.             type
  4175.             (upcase remote)
  4176.             extra
  4177.             (upcase local)
  4178.             irc-msg-info-post))
  4179.        ((and (string-match "\\(CHANOP\\|OPER\\|USER\\)" (upcase type))
  4180.          (numberp (string-match "^\\([^[]*\\)\\[\\([^: ]+\\)\\]$"
  4181.                     remote)))
  4182.         (let ((user (subfield remote 1))
  4183.           (cm (subfield remote 2)))
  4184.           (irc-remember user 'irc-nicknames)
  4185.           (if (stringp class)
  4186.           (irc-insert
  4187.            "%s%s of class %3s at server %s: \"%s\" (client on %s)%s"
  4188.            irc-msg-info-pre
  4189.            type
  4190.            class
  4191.            (upcase local)
  4192.            user
  4193.            (upcase cm)
  4194.            irc-msg-info-post)
  4195.           (irc-insert "%s%s at server %s: \"%s\" (client on %s)%s"
  4196.                   irc-msg-info-pre
  4197.                   type
  4198.                   (upcase local)
  4199.                   user
  4200.                   (upcase cm)
  4201.                   irc-msg-info-post))))
  4202.        ((and (string-match "\\(UNKNOWN\\)" (upcase type))
  4203.          (numberp (string-match "^\\([^[]*\\)\\[\\([^: ]+\\)\\]$"
  4204.                     remote)))
  4205.         (let ((cm (substring remote
  4206.                  (match-beginning 2)
  4207.                  (match-end 2))))
  4208.           (irc-insert (concat "%s%s at server %s from internet"
  4209.                   " host %s%s")
  4210.               irc-msg-info-pre
  4211.               (cond ((string= "UNKNOWN" (upcase type))
  4212.                  "Half open connection")
  4213.                 (t (concat "<Unknown type (%s) in function"
  4214.                        " irc-parse-notice, please"
  4215.                        " tell "
  4216.                        irc-hacker
  4217.                        ">")))
  4218.               (upcase local)
  4219.               (upcase cm)
  4220.               irc-msg-info-post)))
  4221.        (t (irc-insert "%s%s at server %s to%s server %s%s%s"
  4222.               irc-msg-info-pre
  4223.               (cond ((string= (upcase type) "CONNECTION")
  4224.                  "Serverlink")
  4225.                 ((string= (upcase type) "CONNECTING")
  4226.                  "Server-search")
  4227.                 (t type))
  4228.               (upcase local)
  4229.               (if (stringp class)
  4230.                   (format " class %3s" class)
  4231.                   "")
  4232.               (upcase remote)
  4233.               (downcase extra)
  4234.               irc-msg-info-post)))))
  4235.       ((string-match (concat "^\\*\\*\\* *Notice *\\(:\\|--\\)"
  4236.                  " *No +response +from +"
  4237.                  "\\([^ ]+\\) *, *closing +link *$")
  4238.              cmsg)
  4239.        (irc-insert "%%Closed serverlink to %s due to lack of respone."
  4240.            (substring cmsg (match-beginning 2) (match-end 2)))
  4241.        (irc-later-execute-lusers))
  4242.       ((string-match (concat "^\\*\\*\\* *Class +\\([0-9]+\\) *"
  4243.                  "Entries *linked *: *\\([0-9]+\\) *$")
  4244.              cmsg)
  4245.        (let ((class (string-to-int (subfield cmsg 1)))
  4246.          (count (string-to-int (subfield cmsg 2))))
  4247.      (irc-insert "%s%s%d service%s linked for class %3d%s"
  4248.              irc-msg-info-pre
  4249.              parorg
  4250.              count
  4251.              (if (= 1 count) "" "s")
  4252.              class
  4253.              irc-msg-info-post)))
  4254.       ((string-match (concat "^\\([A-Za-z]+\\) +has +been +used +"
  4255.                  "\\([0-9]+\\) +times? +after +"
  4256.                  "startup *$")
  4257.              cmsg)
  4258.        (let ((cmd (substring cmsg (match-beginning 1) (match-end 1)))
  4259.          (cnt (substring cmsg (match-beginning 2) (match-end 2))))
  4260.      (irc-insert "%sServer %s has seen %s%s command%s of type %s%s"
  4261.              irc-msg-info-pre
  4262.              (upcase (if (string= srvr "") irc-server srvr))
  4263.              (make-string (max 0 (- 5 (length cnt))) ? )
  4264.              cnt
  4265.              (if (string= cnt "1") " " "s")
  4266.              cmd
  4267.              irc-msg-info-post)))
  4268.       ((string-match "^\\*\\*\\* *No +such +server *" cmsg)
  4269.        (let ((unknown (substring cmsg (match-end 0))))
  4270.      (irc-forget unknown 'irc-servernames)
  4271.      (irc-insert "%%%sNo such server: \"%s\"."
  4272.              (if (string= "" srvr)
  4273.              ""
  4274.              (concat "(" srvr ")"))
  4275.              unknown)))
  4276.       ((string-match (concat "^\\*\\*\\* *unknown \\([^: ]+\\) *==> *"
  4277.                  "\\([^: ]+\\) *$")
  4278.              cmsg)
  4279.        (irc-insert "%sUnknown connection at server %s to host %s%s"
  4280.            irc-msg-info-pre
  4281.            (upcase (substring cmsg (match-beginning 1) (match-end 1)))
  4282.            (upcase (substring cmsg (match-beginning 2) (match-end 2)))
  4283.            irc-msg-info-post))
  4284.       ((string-match (concat "^\\*\\*\\* *\\(User\\)?\\(ChanOp\\)?"
  4285.                  "\\(Oper\\)? +\\([^: ]+\\) *==> *"
  4286.                  "\\([^: ]*\\) *\\[\\(.\\|\n\\)*\\] *$")
  4287.              cmsg)
  4288.        (let* ((first (substring cmsg
  4289.                 (or (match-beginning 1) 0)
  4290.                 (or (match-end 1) 0)))
  4291.           (second (substring cmsg
  4292.                  (or (match-beginning 2) 0)
  4293.                  (or (match-end 2) 0)))
  4294.           (third (substring cmsg
  4295.                 (or (match-beginning 3) 0)
  4296.                 (or (match-end 3) 0)))
  4297.           (srvr (substring cmsg (match-beginning 4) (match-end 4)))
  4298.           (nick (substring cmsg (match-beginning 5) (match-end 5)))
  4299.           (client (substring cmsg (match-beginning 6) (match-end 6)))
  4300.           (type (cond ((not (string= "" first)) "User")
  4301.               ((not (string= "" second)) "Channel operator")
  4302.               ((not (string= "" third)) "IRC operator")
  4303.               (t "?UNKNOWN?"))))
  4304.      (irc-remember nick 'irc-nicknames)
  4305.      (irc-insert "%s%s at server %s: \"%s\" (client on %s)%s"
  4306.              irc-msg-info-pre
  4307.              type
  4308.              (upcase srvr)
  4309.              nick
  4310.              (upcase client)
  4311.              irc-msg-info-post)))
  4312.       ((string-match (concat "^\\(\\*\\*\\*\\)? *\\([0-9]+\\) +users* +"
  4313.                  "\\(have\\|has\\) +connection +to +the +"
  4314.                  "twilight +zone *$")
  4315.              cmsg)
  4316.        (let ((n (string-to-int (subfield cmsg 2))))
  4317.      (irc-insert "*** There %s %d enabled operator%s online."
  4318.              (if (= 1 n) "is" "are")
  4319.              n
  4320.              (if (= 1 n) "" "s"))))
  4321.        ((string-match (concat "^\\(\\*\\*\\*\\)? *There \\(is\\|are\\) +"
  4322.                   "+\\([0-9]+\\) +channels*. *$")
  4323.               cmsg)
  4324.         (let ((n (string-to-int (subfield cmsg 3))))
  4325.       (irc-insert "*** There %s %d channel%s."
  4326.               (if (= 1 n) "is" "are")
  4327.               n
  4328.               (if (= 1 n) "" "s"))))
  4329.        ((string-match (concat "^\\(\\*\\*\\*\\)? *There \\(is\\|are\\) +"
  4330.                   "+\\([0-9]+\\) +clients* +connected +"
  4331.                   "to +\\([^ ,]+\\).*$")
  4332.               cmsg)
  4333.         (let ((n (string-to-int (subfield cmsg 3)))
  4334.           (s (subfield cmsg 4)))
  4335.       (irc-insert "*** There %s %d client%s on %s."
  4336.               (if (= 1 n) "is" "are")
  4337.               n
  4338.               (if (= 1 n) "" "s")
  4339.               s)))
  4340.       ((string-match "^###" cmsg)
  4341.        (let ((m (substring cmsg (match-end 0))))
  4342.      (irc-insert "###%s%s"
  4343.              (if (or (string= "" srvr)
  4344.                  (string= (upcase srvr) (upcase irc-server)))
  4345.              ""
  4346.              (concat "(" srvr ")"))
  4347.              m)))
  4348.       ((string-match (concat "^\\*\\*\\* *welcome +to +the +internet +"
  4349.                  "relay +network *, *\\([^: ]+\\) *$")
  4350.              cmsg)        ;v2.4 welcome message
  4351.        (let ((user (subfield cmsg 1)))
  4352.      (irc-remember user 'irc-nicknames)))
  4353.       ((string-match (concat "^\\*\\*\\* *Your +host +is +"
  4354.                  "\\([^ ,]+\\) *, *running +version +"
  4355.                  "\\([^: ]+\\) *$")
  4356.              cmsg)
  4357.        (let* ((s (subfield cmsg 1))
  4358.           (vrsn (subfield cmsg 2))
  4359.           (s (downcase (irc-extract-hostname s))) ;REAL GENERIC servername
  4360.           (cur-bufname (buffer-name (current-buffer)))
  4361.           (new-bufname (irc-host+port-to-buffer-name s irc-port))
  4362.           (pre-kludge nil))
  4363.      (setq-default irc-server s)
  4364.      (setq irc-server s)
  4365.      (if (string< cur-bufname new-bufname)
  4366.          (rename-buffer new-bufname))
  4367.      (if (not (string= (upcase srvr) (upcase s)))
  4368.          (irc-remember s 'irc-servernames))
  4369.      (if (or (string-match (concat "^\\([Ii][Rr][Cc][Dd]?\\)?\\([u0-9]+\\)"
  4370.                        "[^0-9]+\\([0-9]+\\)\\([^0-9]+\\)"
  4371.                        "\\([0-9]+\\)")
  4372.                    vrsn)
  4373.          (string-match (concat "^\\([Ii][Rr][Cc][Dd]?\\)?\\([u0-9]+\\)"
  4374.                        "[^0-9]+\\([0-9]+\\)\\(\\)")
  4375.                    vrsn)
  4376.          (string-match (concat "^\\([Ii][Rr][Cc][Dd]?\\)?\\([u0-9]+\\)"
  4377.                        "\\(\\)\\(\\)")
  4378.                    vrsn))
  4379.          (let* ((type nil)
  4380.             (major (subfield vrsn 2))
  4381.             (minor (subfield vrsn 3))
  4382.             (kludge (subfield vrsn 4))
  4383.             (edit (subfield vrsn 5))
  4384.             (minor (if (string= "" minor) 0 (string-to-int minor)))
  4385.             (edit (if (string= "" edit) 0 (string-to-int edit))))
  4386.            (if (string-match "^u" major)
  4387.            (setq type (format "%c" (aref major 0))
  4388.              major (substring major 1)))
  4389.            (setq irc-type-version type
  4390.              irc-major-version (string-to-int major)
  4391.              irc-minor-version minor
  4392.              pre-kludge kludge
  4393.              irc-edit-version edit)
  4394.            )
  4395.          (irc-insert "%%Failed parsing vrsn \"%s\" in irc-parse-notice."
  4396.              vrsn))
  4397.      (if (and (= irc-major-version 2)
  4398.           (= irc-minor-version 6)
  4399.           (not (string= (upcase pre-kludge) "PRE")))
  4400.          (setq irc-edit-version (+ 10000 irc-edit-version)))
  4401.      (irc-insert "")
  4402.      (irc-insert "*** Welcome to the IRC server at %s!" s)
  4403.      (irc-insert "*** The server's version is %s," vrsn)))
  4404.       ((string-match "^\\*\\*\\* *This +server +was +created +"
  4405.              cmsg)
  4406.        (irc-insert "*** and it was created %s."
  4407.            (substring cmsg (match-end 0))))
  4408.       ;; Hello message from a 2.2 server.
  4409.       ((string-match (concat "^\\*\\*\\* *Welcome +to +Internet +Relay +"
  4410.                  "Server *")
  4411.              cmsg)
  4412.        (let ((vrsn (irc-nuke-whitespace (substring cmsg (match-end 0)))))
  4413.      (if (string-match (concat "^[^0-9]*\\([0-9]+\\)\\.\\([0-9]+\\)"
  4414.                    "[^0-9]+\\([0-9]+\\)?.*$")
  4415.                vrsn)
  4416.          (let ((maj (substring vrsn (match-beginning 1) (match-end 1)))
  4417.            (min (substring vrsn (match-beginning 2) (match-end 2)))
  4418.            (edt (substring vrsn (match-beginning 3) (match-end 3))))
  4419.            (setq irc-major-version (string-to-int maj)
  4420.              irc-minor-version (string-to-int min)
  4421.              irc-edit-version (string-to-int edt))))
  4422.      (irc-send "MOTD")
  4423.      (irc-insert (concat "*** Welcome to the Internet Relay Chat server "
  4424.                  "version %s at %s!")
  4425.              vrsn
  4426.              irc-server)
  4427.      (set-buffer-modified-p (buffer-modified-p))))
  4428.        ((string-match (concat "^\\(\\*\\*\\*\\)? *There +are +\\([0-9]+\\) +"
  4429.                  "users +\\(and +\\|(\\)?"
  4430.                  "\\([^0-9]*[0-9]+ invisible\\)?\\()\\)? *"
  4431.                  "on +\\([0-9]+\\) +servers *$")
  4432.              cmsg)
  4433.        (let* ((ucount (subfield cmsg 2))
  4434.           (sdelim (subfield cmsg 3))
  4435.           (invstr (subfield cmsg 4))
  4436.           (edelim (subfield cmsg 5))
  4437.           (scount (subfield cmsg 6))
  4438.           (inv (if (string= "" invstr)
  4439.                ""
  4440.                (concat " "  sdelim invstr edelim)))
  4441.           (n (string-to-int ucount)))
  4442.      (irc-insert "*** There %s %s user%s%s on %s server%s."
  4443.              (if (= n 1) "is" "are")
  4444.              ucount
  4445.              (if (= n 1) "" "s")
  4446.              inv
  4447.              scount
  4448.              (if (= (string-to-int scount) 1) "" "s"))))
  4449.       ((string-match (concat "^\\(\\*\\*\\*\\)? *There +are \\([0-9]+\\) +"
  4450.                  "yet +unknown +connections *$")
  4451.              cmsg)
  4452.        (let ((count (substring cmsg (match-beginning 2) (match-end 2))))
  4453.      (irc-insert "*** There %s yet %s unknown connection%s."
  4454.              (if (string= count "1") "is" "are")
  4455.              count
  4456.              (if (string= count "1") "" "s"))))
  4457.       ((string-match (concat "^\\(\\*\\*\\*\\)? *I +have +\\([0-9]+\\)"
  4458.                  " +clients +and \\([0-9]+\\) +servers *$")
  4459.              cmsg)
  4460.        (let* ((c (subfield cmsg 2))
  4461.           (s (subfield cmsg 3))
  4462.           (cn (string-to-int c))
  4463.           (sn (string-to-int s))
  4464.           (isare (if (= 1 cn) "is" "are"))
  4465.           (cstr (if (= 1 cn) "client" "clients"))
  4466.           (sstr (if (= 1 sn) "server" "servers")))
  4467.      (irc-insert "*** There %s %d %s and %d %s on this server."
  4468.              isare cn cstr sn sstr)))
  4469.       ((string-match (concat "^\\*\\*\\* +Notice *:?-?-? +Received +KILL"
  4470.                  " +message +for +\\([^ ]+\\).\\( +From [^ ]+\\)?"
  4471.                  " +Path: *")
  4472.              cmsg)
  4473.        (let* ((sender (substring cmsg (match-beginning 1) (match-end 1)))
  4474.           (f (subfield cmsg 2))
  4475.           (path (substring cmsg (match-end 0)))
  4476.           (from (cond ((string-match "^From " f)
  4477.                (substring cmsg (match-end 0)))
  4478.               ((irc-is-hostname f) f)
  4479.               (t ""))))
  4480.      (cond ((string-match "\\([^!]+\\)!?(\\([^ ]*\\) *<- *\\([^ ]*\\)) *$"
  4481.                   path)
  4482.         (let* ((at (subfield path 1))
  4483.                (old (subfield path 2))
  4484.                (new (subfield path 3))
  4485.                (local (irc-is-nickname old))
  4486.                (irc-msg-cont-used (make-string
  4487.                        (length (concat irc-msg-info-pre
  4488.                                "User "))
  4489.                        ? )))
  4490.           (irc-insert
  4491.            (concat "%s%s COLLIDED at %s, "
  4492.                (if local
  4493.                    "local user %s seen on link from %s%s"
  4494.                    "was on %s, now from %s%s"))
  4495.            irc-msg-info-pre
  4496.            sender
  4497.            (upcase (irc-nuke-whitespace at))
  4498.            (upcase (irc-nuke-whitespace old))
  4499.            (upcase (irc-nuke-whitespace new))
  4500.            irc-msg-info-post)))
  4501.            ((or (string-match "\\([^!]+\\)!\\([^=][^! ]*\\) +(\\(.*\\))$"
  4502.                   path)
  4503.             (string-match "\\([^!]+\\)!\\([^=][^! ]*\\) *\\(\\)$"
  4504.                   path))
  4505.         (let* ((s (subfield path 1))
  4506.                (o (subfield path 2))
  4507.                (m (subfield path 3))
  4508.                (site (irc-nuke-whitespace s))
  4509.                (oper (irc-nuke-whitespace o))
  4510.                (type (if (string-match "\\." oper)
  4511.                  "Server"
  4512.                  "Operator"))
  4513.                (m2 (irc-nuke-whitespace m))
  4514.                (mesg (if (string= "" m2) "" (concat " (" m2 ")"))))
  4515.           (if (string-match "\\." oper)
  4516.               (irc-remember oper 'irc-servernames)
  4517.               (irc-remember oper 'irc-nicknames))
  4518.           (irc-insert "%sOperator %s (@%s) /KILL'ed user %s%s%s"
  4519.                   irc-msg-info-pre
  4520.                   oper
  4521.                   site
  4522.                   sender
  4523.                   mesg
  4524.                   irc-msg-info-post))
  4525.         (irc-send (concat "WHOWAS :" sender)))
  4526.            (t (irc-insert "%sUser %s KILL'ed, path: %s%s"
  4527.                   irc-msg-info-pre
  4528.                   sender
  4529.                   path
  4530.                   irc-msg-info-post)))))
  4531.       ((or (string-match "^ *You +have +been +marked +as +being +away *$" cmsg)
  4532.        (string-match "^ *You +have +marked +as +being +away *$" cmsg))
  4533.        (if (string= srvr "")
  4534.        (irc-insert (concat "%sYou have been marked as being away,"
  4535.                    " use /HERE to revert the effect%s")
  4536.                irc-msg-info-pre
  4537.                irc-msg-info-post)))
  4538.       ((string-match "^ *You +are +no +longer +marked +as +being +away *$"
  4539.              cmsg)
  4540.        (if (string= srvr "")        ;Only display if from local server.
  4541.        (irc-insert "%sYou are no longer marked as being away%s"
  4542.                irc-msg-info-pre
  4543.                irc-msg-info-post)))
  4544.       ((string-match (concat "^ *\\([^: *]*\\) *"
  4545.                  "\\(tty[^: ]+"
  4546.                  "\\|pty/tty[^: ]+"
  4547.                  "\\|vt[0-9]+"
  4548.                  "\\|pt[^: ]+"
  4549.                  "\\|display"
  4550.                  "\\|console\\) *"
  4551.                  "\\([ -~]+\\)?.*$")
  4552.              cmsg)
  4553.        (let ((user (substring cmsg (match-beginning 1) (match-end 1)))
  4554.          (tty (substring cmsg (match-beginning 2) (match-end 2)))
  4555.          (remote (substring cmsg (match-beginning 3) (match-end 3))))
  4556.      (irc-insert "%s%s %s%s %s"
  4557.              user
  4558.              (make-string (max 0 (- 39 (length user))) ? )
  4559.              tty
  4560.              (make-string (max 0 (- 14 (length tty))) ? )
  4561.              remote)))
  4562.       ((string-match " *Nobody +logged +in +on +\\([^: ]+\\) *$" cmsg)
  4563.        (let* ((s (subfield cmsg 1))
  4564.           (server (irc-extract-hostname s)))
  4565.      (if (and (stringp server)
  4566.           (not (string= (upcase srvr) (upcase server))))
  4567.          (irc-remember server 'irc-servernames))
  4568.      (irc-insert (concat "%%No users logged in on the Internet node"
  4569.                  " which runs the IRC server %s at the moment.")
  4570.              server)))
  4571.       ((string-match "^ *\\(UserId +Terminal +Host\\) *$" cmsg)
  4572.        (let ((m (substring cmsg (match-beginning 1) (match-end 1))))
  4573.      (irc-insert (concat "Login name                              "
  4574.                  "TTY            Logged in from"))
  4575.      (irc-insert (concat "--------------------------------------- "
  4576.                  "-------------- --------------"))))
  4577.       ((string-match (concat "^\\*\\*\\* *\\(Notice\\)? *\\(:\\|--\\)?"
  4578.                  " *Connecti\\(ng\\|on\\) *to"
  4579.                  " +\\(.+\\) +activated.? *$")
  4580.              cmsg)
  4581.        (irc-insert "%s%sTrying to establish a serverlink to %s%s"
  4582.            irc-msg-info-pre
  4583.            parorg
  4584.            (upcase (substring cmsg (match-beginning 4) (match-end 4)))
  4585.            irc-msg-info-post))
  4586.       ((string-match (concat "^\\*\\*\\* *Notice *\\(:\\|--\\)"
  4587.                  " *Failed *in *connecting *to"
  4588.                  " *\\([^: ]+\\) *: *Socket *is"
  4589.                  " *not *connected *.? *$")
  4590.              cmsg)
  4591.        (irc-insert (concat "%%%sFailed to establish a serverlink to %s;"
  4592.                " no active server at other end.")
  4593.            parorg
  4594.            (upcase
  4595.             (substring cmsg (match-beginning 2) (match-end 2)))))
  4596.       ((string-match (concat "^\\*\\*\\* *Notice *: *Connect +"
  4597.                  "to +host +\\(.\\|\n\\)* +failed *:")
  4598.              cmsg)
  4599.        (let* ((host (substring cmsg (match-beginning 1) (match-end 1)))
  4600.           (reason (substring cmsg (match-end 0)))
  4601.           (server (upcase (irc-extract-hostname host))))
  4602.      (irc-forget server 'irc-servernames) ;Just in case.
  4603.      (irc-insert "%%Failed to establish a serverlink to %s; %s."
  4604.              (upcase server)
  4605.              reason)))
  4606.       ((string-match (concat "^\\*\\*\\* Notice: Access denied (no such server"
  4607.                  " enabled) \\([^ ]+\\) *\\(\\[[^ ]+\\]\\)? *$")
  4608.              cmsg)
  4609.        (let ((claimed (substring cmsg (match-beginning 1) (match-end 1)))
  4610.          (truename (substring cmsg
  4611.                   (1+ (or (match-beginning 2) -1))
  4612.                   (1- (or (match-end 2) 1)))))
  4613.      (irc-insert (concat "%%Rejected attemp by internethost \"%s\"%s to"
  4614.                  " establish a serverlink; that host isn't enabled"
  4615.                  " in the configuration file.")
  4616.              (if (string= "" truename) claimed truename)
  4617.              (if (or (string= "" truename)
  4618.                  (string= (upcase claimed) (upcase truename)))
  4619.              ""
  4620.              (concat " (claiming to be \"" claimed "\")")))))
  4621.       ((string-match (concat "^ *\\*\\*\\* +Notice *: +No +"
  4622.                  "response +from +\\([^: ]+\\) +, +"
  4623.                  "closing +link *$")
  4624.              cmsg)
  4625.        (let ((removed-server (substring cmsg
  4626.                     (match-beginning 1)
  4627.                     (match-end 1))))
  4628.      (irc-forget removed-server 'irc-servernames)
  4629.      (irc-insert (concat "%%Failed to get any response whatsoever from"
  4630.                  " server %s, removing the serverlink to it.")
  4631.              removed-server))
  4632.        (irc-later-execute-lusers))
  4633.       ((or (string-match (concat "^ *\\*\\*\\* *Notice *\\(:\\|--\\)"
  4634.                  " *Max +buffering +limit +exceed"
  4635.                  " +for +\\([^ ]+\\)")
  4636.              cmsg)
  4637.        (string-match (concat "^ *\\*\\*\\* *Notice\\ *\\(:\\|--\\)"
  4638.                  " *SendQueued +called +for +a"
  4639.                  " +DEADSOCKET +\\([^: ]*\\) *"
  4640.                  "\\(:-(\\)? *$")
  4641.              cmsg))
  4642.        (let ((host (irc-extract-hostname (substring cmsg
  4643.                             (match-beginning 2)
  4644.                             (match-end 2)))))
  4645.      (irc-forget host 'irc-servernames)
  4646.      (irc-insert (concat "%%Closed serverlink to %s, max buffering limit"
  4647.                  " got exceeded.")
  4648.              (upcase host)))
  4649.        (irc-later-execute-lusers))
  4650.       ((string-match (concat "^ *\\*\\*\\* *Host +\\(.*\\) +is"
  4651.                  " +unknown *\\.* *$")
  4652.              cmsg)
  4653.        (irc-insert "%%Host \"%s\" is unknown."
  4654.            (upcase
  4655.             (substring cmsg (match-beginning 1) (match-end 1)))))
  4656.       ((string-match (concat "^ *\\*\\*\\* *Notice *-- *Connect +to +host"
  4657.                  " +\\(.+\\) +failed *: *\\(.+\\) *$")
  4658.              cmsg)
  4659.        (let ((h (subfield cmsg 1))
  4660.          (reason (subfield cmsg 2)))
  4661.      (irc-insert "%%Connect to host %s failed: %s" (upcase h) reason)))
  4662.       ((string-match (concat "^ *\\*\\*\\* *Notice *-- *ERROR +"
  4663.                  "from +\\(.*\\) *: *SUMMON +No +"
  4664.                  "such +host *( *\\(.\\|\n\\)* *) *found"
  4665.                  " *$")
  4666.              cmsg)
  4667.        (let* ((fld1 (subfield cmsg 1))
  4668.           (fld2 (subfield cmsg 2))
  4669.           (at-server (irc-extract-hostname fld1))
  4670.           (unknown-host (irc-extract-hostname fld2)))
  4671.      (if (and (string< "" at-server)
  4672.           (not (string= (upcase srvr) (upcase at-server))))
  4673.          (irc-remember at-server 'irc-servernames))
  4674.      (irc-insert (concat "%%Summon command failed as server %s doesn't"
  4675.                  " know of any Internet host called \"%s\".")
  4676.              (upcase fld1)
  4677.              fld2)))
  4678.       ((string-match (concat "^ *\\*\\*\\* *Notice *-- *ERROR"
  4679.                  " +from\\ +\\(.*\\) *: *Access +"
  4680.                  "denied *( *no +such +server +"
  4681.                  "enabled *) *")
  4682.              cmsg)
  4683.        (let ((complainer (subfield cmsg 1))
  4684.          (disabled (substring cmsg (match-end 0))))
  4685.      (if (and (irc-is-hostname complainer)
  4686.           (not (string= (upcase srvr) (upcase complainer))))
  4687.          (irc-remember complainer 'irc-servernames))
  4688.      (irc-insert (concat "%%Server %s refuses to accept serverlink from"
  4689.                  " host %s as that host isn't enabled in the"
  4690.                  " configuration. Use \"/STATS C %s\" to check"
  4691.                  " which hosts ARE enabled.")
  4692.              complainer
  4693.              disabled)))
  4694.       ((string-match (concat "^ *\\([^: ]+\\) +seems +to +have +"
  4695.                  "disabled +summoning")
  4696.              cmsg)
  4697.        (irc-insert "%%User %s@%s has disabled summoning."
  4698.            (substring cmsg (match-beginning 1) (match-end 1))
  4699.            srvnam))
  4700.       ((string-match (concat "^ *Summoning +user *\\([^: ]*\\) +"
  4701.                  "to +irc *$")
  4702.              cmsg)
  4703.        (irc-insert "%sSummoning user %s@%s to IRC%s"
  4704.            irc-msg-info-pre
  4705.            (substring cmsg (match-beginning 1) (match-end 1))
  4706.            srvnam
  4707.            irc-msg-info-post))
  4708.       ((string-match (concat "^ *\\*\\*\\* *Notice *\\(:\\|--\\)"
  4709.                  " *Link +\\(.*\\) +cancelled *,"
  4710.                  " *server +\\(.*\\) +already"
  4711.                  " +exists *$")
  4712.              cmsg)
  4713.        (let ((rhost (substring cmsg (match-beginning 2) (match-end 2)))
  4714.          (rsrvr (substring cmsg (match-beginning 3) (match-end 3))))
  4715.      (irc-insert (concat "%%Server %s %s tried to establish a serverlink"
  4716.                  " to us (%s). Refused as we already are linked.")
  4717.              rsrvr rhost irc-server)))
  4718.       ((string-match (concat "^ *Connect *: *Server +\\([^ ]+\\) +already"
  4719.                  " +exists +from +\\([^ ]+\\) *$")
  4720.              cmsg)
  4721.        (let ((other-side (subfield cmsg 1))
  4722.          (trying-side (subfield cmsg 2)))
  4723.      (irc-remember other-side 'irc-servernames)
  4724.      (irc-remember trying-side 'irc-servernames)
  4725.      (irc-insert "%%Server %s is already connected to %s"
  4726.              (upcase other-side)
  4727.              (upcase trying-side))))
  4728.       ((string-match (concat "^ *\\*\\*\\* *Notice *\\(:\\|--\\)"
  4729.                  " *ERROR +from +\\(.*\\) *:"
  4730.                  " *Server +\\(.*\\) +already +exists"
  4731.                  " *\\.?\\.?\\.? *$")
  4732.              cmsg)
  4733.        (let ((remote (substring cmsg (match-beginning 2) (match-end 2)))
  4734.          (local (substring cmsg (match-beginning 3) (match-end 3))))
  4735.      (if (not (string= (upcase srvr) (upcase remote)))
  4736.          (irc-remember remote 'irc-servernames))
  4737.      (irc-insert (concat "%%Server %s refused to accept a serverlink from"
  4738.                  " %s, the servers are already connected.")
  4739.              (upcase remote)
  4740.              (if (string= (upcase local) (upcase irc-server))
  4741.              (concat "this server (" local ")")
  4742.              (concat "other server " local))))) 
  4743.       ((string-match (concat "^ *\\*\\*\\* *Notice *\\(:\\|--\\)"
  4744.                  " *Server +\\([^: ]+\\) +closed +the"
  4745.                  " +connection *.? *$")
  4746.              cmsg)
  4747.        (let ((remote (substring cmsg (match-beginning 2) (match-end 2))))
  4748.      (irc-forget remote 'irc-servernames)
  4749.      (irc-insert "%%%sServerlink from %s closed by remote side."
  4750.              parorg
  4751.              (upcase remote))))
  4752.       ((string-match (concat "^ *\\*\\*\\* *Notice *\\(:\\|--\\)"
  4753.                  " *Access +denied *( *no +such"
  4754.                  " +server +enabled *) *")
  4755.              cmsg)
  4756.        (let* ((remote (substring cmsg (match-end 0)))
  4757.           (s (irc-extract-hostname remote))
  4758.           (server (if (stringp s) s ""))
  4759.           (rest (substring remote (length server)))
  4760.           (h (irc-nuke-whitespace rest))
  4761.           (host (upcase (if (string= "" h) server h))))
  4762.      (irc-insert (concat "%%Server %s (on host %s) tried to set up a"
  4763.                  " server-link to us (%s) but we refused as there"
  4764.                  " is no N line accepting that host/server"
  4765.                  " combination.")
  4766.              server host irc-server)))
  4767.       ((string-match (concat "^ *\\*\\*\\* *Notice *\\(:\\|--\\)"
  4768.                  " *Lost +server +connection +to"
  4769.                  " +\\(.*\\) *:")
  4770.              cmsg)
  4771.        (let ((remote (substring cmsg (match-beginning 2) (match-end 2)))
  4772.          (reason (substring cmsg (match-end 0))))
  4773.      (irc-forget remote 'irc-servernames)
  4774.      (irc-insert "%%Lost serverlink to %s (%s)." (upcase remote) reason)
  4775.      (irc-later-execute-lusers)))
  4776.       ((string-match (concat "^ *Connect *: *Host +\\(.\\|\n\\)*"
  4777.                  " +not +listed +in +ircd?.conf *$")
  4778.              cmsg)
  4779.        (let ((host (substring cmsg (match-beginning 1) (match-end 1))))
  4780.      (irc-insert (concat "%%There is no host matching the description"
  4781.                  " \"%s\" in the servers (%s) configuration"
  4782.                  " file.")
  4783.              host irc-server)))
  4784.       ((string-match "^ *\\(.\\|\n\\)* *: *Privileged +command *$"
  4785.              cmsg)
  4786.        (irc-insert (concat "%%You must be an ENABLED IRC operator to use"
  4787.                " command \"%s\". Use /OPER to enable yourself.")
  4788.            (upcase (subfield cmsg 1))))
  4789.       ((string-match (concat "^ *\\*\\*\\* *Notice *-- *ERROR +"
  4790.                  "from +\\(.*\\) *: *SUMMON +No +"
  4791.                  "such +host *( *\\(.*\\) *) *found"
  4792.                  " *$")
  4793.              cmsg)
  4794.        (let ((complainer (subfield cmsg 1))
  4795.          (nonfound (subfield cmsg 2)))
  4796.      (if (not (string= (upcase srvr) (upcase complainer)))
  4797.          (irc-remember complainer 'irc-servernames))
  4798.      (irc-insert (concat "%%Command /SUMMON found as server \"%s\" doesn't"
  4799.                  " know about any server \"%s\".")
  4800.              complainer nonfound)))
  4801.       ((and (irc-is-hostname srvr)
  4802.         (string-match (concat "^ *User +\\(.\\|\n\\)* +not +logged"
  4803.                   " +in *$")
  4804.               cmsg))
  4805.        (irc-insert (concat "%%Command /SUMMON failed as no user called \"%s\""
  4806.                " is logged in at %s at the moment.")
  4807.            (subfield cmsg 1) (upcase srvr)))
  4808.       ((or (string-match "^\\*\\*\\* *Notice *:?-* *\\([^ ]*\\) *$" cmsg)
  4809.        (string-match "^\\*\\*\\* *\\([^ ]*\\) *$" cmsg)
  4810.        (string-match "^ *Notice *:?-* *\\([^ ]+\\) *$" cmsg)
  4811.        (string-match "^ *\\([CNIYQK] *:.*\\) *$" cmsg) ;/STATS C
  4812.        (string-match "^ *\\*\\*\\* *\\(.*\\) *$" cmsg))
  4813.        (let* ((b (or (match-beginning 1) 0))
  4814.           (e (or (match-end 1) b))
  4815.           (m (substring cmsg b e)))
  4816.      (irc-insert "%s%s%s%s%s%s"
  4817.              irc-msg-info-pre
  4818.              (if (or (string= rcvr "")
  4819.                  (string= (upcase rcvr) (upcase irc-nick-used)))
  4820.              ""
  4821.              (concat
  4822.               "To "
  4823.               (cond ((irc-is-nickname rcvr) "user ")
  4824.                 ((irc-is-channelname rcvr) "channel ")
  4825.                 ((irc-is-broadcastname rcvr) "server "))
  4826.               rcvr
  4827.               " "))
  4828.              (cond ((string= srvr "") "")
  4829.                ((or (string-match "^C:" m) (string-match "^N:" m))
  4830.                 parorg)
  4831.                (t (concat "from "
  4832.                       (if (irc-is-hostname srvr)
  4833.                       "server (user?)"
  4834.                       "user (server?)")
  4835.                       " "
  4836.                       srvr)))
  4837.              (if (and (string= srvr "")
  4838.                   (or (string= rcvr "")
  4839.                   (string= (upcase rcvr)
  4840.                        (upcase irc-nick-used))))
  4841.              ""
  4842.              ": ")
  4843.              m
  4844.              irc-msg-info-post)))
  4845.       ((or (string-match (concat "^[^: ]+ +[0-9]+ *[0-9]+ *[0-9]+ *"
  4846.                  "[0-9]+ *[0-9]+ +\\("
  4847.                  "Mon\\|Tue\\|Wed\\|Thu\\|Fri\\|Sat\\|Sun"
  4848.                  "\\) +")
  4849.              cmsg)
  4850.        (string-match (concat "^ *Link +SendQ +SendM +SendBytes"
  4851.                  " +RcveM +RcveBytes +Open +since"
  4852.                  " *$")
  4853.              cmsg))
  4854.        (irc-insert cmsg))
  4855. ;;;      ((string-match "^ *: *\\([^: ]+\\) +NOTICE +\\([^: ]+\\) *:" str)
  4856. ;;;       (let ((from (substring str (match-beginning 1) (match-end 1)))
  4857. ;;;         (to (substring str (match-beginning 2) (match-end 2)))
  4858. ;;;         (msg (substring str (match-end 0))))
  4859. ;;;     (setq retval (irc-parse-priv (concat ":" from " PRIVMSG " to
  4860. ;;;                          " :" msg)))))
  4861.       ((string-match "^\\(.*\\) +ToolZ V[0-9]+\\.[0-9]+[a-zA-Z]* *$" cmsg)
  4862.        (let ((m (subfield cmsg 1)))
  4863.      (if (string-match "^[ :;\\.?]*" m)
  4864.          (setq m (substring m (match-end 0))))
  4865.      (if (string-match "[ :;\\.?]*$" m)
  4866.          (setq m (substring m 0 (match-beginning 0))))
  4867.      (irc-insert "%sToolZ-notice from %s: %s%s"
  4868.              irc-msg-info-pre
  4869.              srvnam
  4870.              m
  4871.              irc-msg-info-post)))
  4872.       ((and (string= (upcase rcvr) (upcase irc-last-NOTICE-rcv))
  4873.         (string= (upcase srvr) (upcase irc-last-NOTICE-src)))
  4874.        (setq irc-last-NOTICE-rcv rcvr
  4875.          irc-last-NOTICE-src srvr)
  4876.        (let ((irc-msg-cont-used "    "))
  4877.      (irc-insert "*** %s" cmsg)))
  4878.       (t (setq irc-last-NOTICE-rcv rcvr
  4879.            irc-last-NOTICE-src srvr)
  4880.      (cond ((irc-is-nickname srvr)
  4881.         (irc-remember srvr 'irc-nicknames))
  4882.            ((irc-is-hostname srvr)
  4883.         (irc-remember srvr 'irc-servernames)))
  4884.      (irc-insert "")
  4885.      (let ((irc-msg-cont-used "       "))
  4886.        (irc-insert "****** %s %s says to %s:"
  4887.                (cond ((string= "" srvr) "Your")
  4888.                  ((irc-is-nickname srvr)
  4889.                   "User (or possible server)")
  4890.                  (t "Server (or possible user)"))
  4891.                (cond ((string= "" srvr) "server")
  4892.                  (t (concat "\"" srvr "\"")))
  4893.                (if (string= (upcase rcvr) (upcase irc-nick))
  4894.                "you"
  4895.                rcvr))
  4896.        (let ((irc-msg-cont-used "   "))
  4897.          (irc-insert "*** %s" cmsg)))))
  4898.     retval))
  4899.  
  4900.  
  4901. (defun irc-parse-pong (str)
  4902.   "Examine a PONG message from the IRC server.
  4903. Normaly the server should never send such a message, but when it does,
  4904. chances are there's a server name  given."
  4905.   (if (string-match "^PONG *\\([^: ]*\\)? *" str)
  4906.       (let* ((s (subfield str 1))
  4907.          (data (irc-nuke-whitespace (substring str (match-end 0))))
  4908.          (server (irc-extract-hostname s)))
  4909.     (if (irc-is-hostname server)
  4910.         (irc-remember server 'irc-servernames))
  4911.     (if data
  4912.         (irc-insert "%sServer %s says PONG, with message \"%s\"%s"
  4913.             irc-msg-info-pre
  4914.             server
  4915.             data
  4916.             irc-msg-info-post)
  4917.         (irc-insert "%sServer %s says PONG%s"
  4918.             irc-msg-info-pre
  4919.             server
  4920.             irc-msg-info-post)))))
  4921.  
  4922.  
  4923. (defun irc-parse-priv (str)
  4924.   "Examine a PRIVMSG message from the IRC server.
  4925. PRIVMSG is intended to be used for private message sent between users.
  4926. This is not always the case at the moment; servers will use it like either
  4927. NOTICE or MSG on occasion.
  4928.  
  4929. If it really is a private message, this function returns t if a signal should
  4930. be issued for the \"private\" event, nil otherwise."
  4931.   ;; This is really gross because it kludges in the fact that PRIVMSG can
  4932.   ;; be used to send notification of a change of channel topic.
  4933.  
  4934.   (if (not (string-match (concat "^ *: *\\([^: ]*\\) *PRIVMSG"
  4935.                  " *\\([^ ]*\\) +:")
  4936.              str))
  4937.       (progn
  4938.     (irc-insert "%%Unknown PRIVMSG seen in irc-parse-priv:")
  4939.     (irc-insert "%% \"%s\" (str)." str)
  4940.     (irc-insert "%% Please tell %s, it might be a bug." irc-hacker))
  4941.       (let* ((from (substring str (match-beginning 1) (match-end 1))) 
  4942.          (to (substring str (match-beginning 2) (match-end 2)))
  4943.          (msg (substring str (match-end 0)))
  4944.          (time (if (and irc-message-stamp
  4945.                 (not (eq 'public irc-message-stamp)))
  4946.                (concat " (" (irc-get-time) ") ")
  4947.                ""))
  4948.          (hdr (format (format irc-msg-priv (+ 7 (length irc-channel)))
  4949.               time
  4950.               from
  4951.               "")))
  4952.     (cond ((and (irc-is-nickname from)
  4953.             (not (irc-recall to 'irc-subscribed-channels)))
  4954.            (irc-remember from 'irc-nicknames))
  4955.           ((irc-is-hostname from)
  4956.            (irc-remember from 'irc-servernames)))
  4957.     (cond
  4958.       ((and irc-ignore-automatic-warnings
  4959.         (string-match "^<Automatic +warning> +" msg))
  4960.        nil)
  4961.       ((irc-recall to 'irc-subscribed-channels)
  4962.        (irc-parse-public (concat ":" from " MSG :" msg) to))
  4963.       ((irc-recall from 'irc-ignored-ppl)
  4964.        (if (and (boundp 'irc-abusive-ignore)
  4965.             irc-abusive-ignore)
  4966.            (irc-send (concat "NOTICE "
  4967.                  from
  4968.                  " :You are being ignored by "
  4969.                  irc-nick-used))))
  4970.       ((string= (upcase to) (upcase irc-nick-used))
  4971.        (setq irc-last-private (concat from ":"))
  4972.        (let ((irc-msg-cont-used (make-string
  4973.                      (min (length hdr)
  4974.                       (/ (window-width
  4975.                           (get-buffer-window
  4976.                            (current-buffer)))
  4977.                          2))
  4978.                      ? )))
  4979.          (if (and (boundp 'irc-private-insert)
  4980.               irc-private-insert)
  4981.          (funcall irc-private-insert from to msg)
  4982.          (irc-insert (concat hdr (irc-clean-up-message msg))))
  4983.          (irc-signal from 'private)))
  4984.       ((irc-is-broadcastname to)
  4985.        (let ((irc-msg-cont-used (make-string
  4986.                      (min (length hdr)
  4987.                       (/ (window-width
  4988.                           (get-buffer-window
  4989.                            (current-buffer)))
  4990.                          2))
  4991.                      ? )))
  4992.          (irc-insert (concat hdr
  4993.                  "[BROADCAST to all users on IRC "
  4994.                  (if (= ?$ (aref to 0))
  4995.                      "server(s) "
  4996.                      "clients(s) on Internet host(s) ")
  4997.                  (upcase (substring to 1))
  4998.                  "] "
  4999.                  (irc-clean-up-message msg)))
  5000.          (irc-signal from 'wall)))
  5001.       (t (setq irc-last-private (concat from ":"))
  5002.          (let ((irc-msg-cont-used (make-string
  5003.                        (min (length hdr)
  5004.                         (/ (window-width
  5005.                         (get-buffer-window
  5006.                          (current-buffer)))
  5007.                            2))
  5008.                        ? )))
  5009.            (irc-insert "*** Private message to \"%s\" follows:" to)
  5010.            (if (and (boundp 'irc-private-insert)
  5011.             irc-private-insert)
  5012.            (funcall irc-private-insert from to msg)
  5013.            (irc-insert (concat hdr (irc-clean-up-message msg))))
  5014.            (irc-signal from 'private)))))))
  5015.  
  5016.  
  5017. (defun irc-parse-public (str &optional priv-chan)
  5018.   "Examine a MSG message from the IRC server.
  5019. MSG is sent when someone has sent a message to a channel.  In reality,
  5020. sometimes PRIVMSG is used but irc-parse-private should hand those off to
  5021. here.
  5022.  
  5023. This function returns t if a bell should be issued for the \"public\" or
  5024. \"backtalk\" events, nil otherwise."
  5025.   (let* ((user (substring str 1 (string-match " MSG :" str)))
  5026.      (rcvr (if priv-chan
  5027.            priv-chan
  5028.            (let ((clst (irc-recall-all 'irc-subscribed-channels)))
  5029.              ;; Find out which of the channel's is "MSG:able".
  5030.              (while (and clst (listp clst))
  5031.                (if (irc-is-multijoinable-channel (car clst))
  5032.                (setq clst (cdr clst))
  5033.                (setq clst (car clst))))
  5034.              ;; As THIS function was activated, we are listening to one
  5035.              ;; of the old type channels (42, +glbf) if priv-chan=nil.
  5036.              (if (not clst)
  5037.              "???"
  5038.              clst))))
  5039.      (msg (substring str (match-end 0)))
  5040.      (about-self (numberp (string-match
  5041.                    (concat "\\<"
  5042.                        (regexp-quote irc-nick-used)
  5043.                        "\\>")
  5044.                    msg)))
  5045.      (ismem (irc-recall user 'irc-ignored-ppl))
  5046.      (hdr (if ismem ""
  5047.           (format irc-msg-public
  5048.               (if (and irc-message-stamp
  5049.                    (not (eq 'private irc-message-stamp)))
  5050.                   (concat " (" (irc-get-time) ")")
  5051.                   "")
  5052.               user
  5053.               rcvr)))
  5054.      (irc-msg-cont-used (make-string
  5055.                  (min (length hdr)
  5056.                   (/ (window-width
  5057.                       (get-buffer-window (current-buffer)))
  5058.                      2))
  5059.                  ? )))
  5060.     ;; even here we can't guarantee that the sender has already been noted
  5061.     ;; someplace else like join or nick -- the sender might be someplace
  5062.     ;; else and sending to this channel with PRIVMSG.
  5063.     (irc-remember user 'irc-nicknames)
  5064.     (cond ((not ismem)            ;Not ignored?
  5065.        (progn (if (and (boundp 'irc-public-insert)
  5066.                irc-public-insert)
  5067.               (funcall irc-public-insert user rcvr msg)
  5068.               (irc-insert (concat hdr (irc-clean-up-message msg))))
  5069.           (or (irc-signal user 'public)
  5070.               (and about-self (irc-signal user 'backtalk))))))))
  5071.  
  5072.  
  5073. (defun irc-parse-quit (str)
  5074.   "Examine a QUIT message from the IRC server.
  5075. QUIT is used to tell of a user's departure from IRC.  It is currently sent
  5076. by the servers to those clients which are on the same channel as the
  5077. departing user.
  5078.  
  5079. This function returns t if a signal should be issued for the \"join\" event,
  5080. since it also signals someone leaving the channel.  It returns nil if no
  5081. bell should be issued."
  5082.   (if (not (or (string-match "^:? *\\([^ :]+\\)? +QUIT +\\([^ :]+\\) *: *" str)
  5083.            (string-match "^:? *\\([^ :]+\\)? +QUIT *\\(\\): *" str)))
  5084.       (progn (irc-insert "%%Unknown QUIT message in irc-parse-quit:")
  5085.          (irc-insert "%% \"%s\" (str)." str)
  5086.          (irc-insert "%% Please tell %s, it might be a bug." irc-hacker))
  5087.       (let* ((u (subfield str 1))
  5088.          (user2 (subfield str 2))
  5089.          (c (irc-clean-up-message (irc-nuke-whitespace
  5090.                        (substring str (match-end 0)))))
  5091.          (user (if (string= "" u) irc-nick-used u))
  5092.          (myself (string= (upcase user) (upcase irc-nick-used)))
  5093.          (uc (upcase c))
  5094.          (comment (cond ((or (string= "" c)
  5095.                  (string= (upcase user) uc))
  5096.                  ": user quit")
  5097.                 ((string= "LEAVING" uc)
  5098.                  ": user quit, one ircII user less on IRC")
  5099.                 ((string= "BAD LINK?" uc)
  5100.                  ": link closed from client's side")
  5101.                 ((string-match "^\\([^.!]+\\)![A-Za-z][^ !]+$" c)
  5102.                  (format ": user quit past %s" (subfield c 1)))
  5103.                 ((string= "KILLED" uc)
  5104.                  ": killed")
  5105.                 ((string= "PING TIMEOUT" uc)
  5106.                  ": killed off due to inactivity")
  5107.                 ((string= "DEAD SOCKET" uc)
  5108.                  ": dead socket")
  5109.                 ((string= "WRITE ERROR" uc)
  5110.                  ": write error")
  5111.                 ((string-match
  5112.                   (concat "^\\([^ ]+\\.[^ .][^ ]*\\)"
  5113.                       " +\\([^ ]+\\.[^ .][^ ]*\\)$")
  5114.                   c)
  5115.                  (format ": netsplit past %s (lost %s)"
  5116.                      (subfield c 1)
  5117.                      (subfield c 2)))
  5118.                 ((string-match "^[^ ]+\\.[^ .][^ ]$" c)
  5119.                  (irc-remember c 'irc-servernames)
  5120.                  (concat ": netsplit just past " c))
  5121.                 (t (concat " (" c ")")))))
  5122.     (if (and (string< "" user2)
  5123.          (not (string= (upcase user) (upcase user2)))
  5124.          (boundp 'debug-on-error)
  5125.          debug-on-error)
  5126.         (irc-insert (concat "%sirc-parse-quit: secondary user to QUIT"
  5127.                 " differed, user=\"%s\", user2=\"%s\"%s")
  5128.             irc-msg-info-pre user user2 irc-msg-info-post))
  5129.     (irc-forget user 'irc-nicknames)
  5130.     (if (and (not (irc-recall user 'irc-ignored-ppl))
  5131.          (memq 'quit irc-events))
  5132.         (progn (irc-insert "%s%s left IRC%s%s"
  5133.                irc-msg-info-pre
  5134.                (if myself "You" user)
  5135.                comment
  5136.                irc-msg-info-post)
  5137.            ;; currently just the join event; some modification will
  5138.            ;; need to be made here when/if Jarkko has QUIT sent to
  5139.            ;; everyone,not just the channel 
  5140.            (irc-signal user 'join))))))
  5141.  
  5142.  
  5143. (defun irc-parse-RPL (str)
  5144.   "Examine a numeric RPL_ message from the IRC server.
  5145. Numeric control messages are used by newer servers to aid in generalized
  5146. client design; while people are converting to the new servers the older
  5147. irc-parse-error, irc-parse-notice, et al, functions are redundant with
  5148. irc-parse-ERR and irc-parse-RPL.  Values used by this function are found
  5149. in the IRC source file numeric.h.
  5150.  
  5151. Note well that some things are still going to come out wrong because the
  5152. servers are currently still doing things inconsistently."
  5153.   (if (string-match "^:?[^: ]+ +\\([023]\\)[0-9][0-9] +" str)
  5154.       (let ((n (string-to-int (subfield str 1))))
  5155.     (cond ((= n 3) (irc-parse-RPL-3xx str))
  5156.           ((= n 2) (irc-parse-RPL-2xx str))
  5157.           (t (irc-parse-RPL-0xx str))))
  5158.       (progn 
  5159.     (irc-insert "%%Function irc-parse-RPL called with non-RPL:")
  5160.     (irc-insert "%% \"%s\" (str)" str)
  5161.     (irc-insert "%% Please tell %s." irc-hacker))))
  5162.  
  5163.  
  5164. (defun irc-parse-RPL-0xx (str)
  5165.   "Examine a numeric RPL_ message from the IRC server.
  5166. Numeric control messages are used by newer servers to aid in generalized
  5167. client design; while people are converting to the new servers the older
  5168. irc-parse-error, irc-parse-notice, et al, functions are redundant with
  5169. irc-parse-ERR and irc-parse-RPL.  Values used by this function are found
  5170. in the IRC source file numeric.h.
  5171.  
  5172. Note well that some things are still going to come out wrong because the
  5173. servers are currently still doing things inconsistently."
  5174.   (if (string-match (concat "^:?\\([^: ]+\\) *\\([023][0-9][0-9]\\) +"
  5175.                 "\\([^: ]+\\)? +:?")
  5176.             str)
  5177.       ;; we assume that the server and message are consistent for us; just
  5178.       ;; worry about the numeric value and the rest of the line
  5179.       (let* ((origin (subfield str 1))
  5180.          (num (string-to-int (subfield str 2)))
  5181.          (user (subfield str 3))
  5182.          (txt (substring str (match-end 0)))
  5183.          (parorg (if (string= (upcase origin) (upcase irc-server))
  5184.              ""
  5185.              (concat "(" origin ") ")))
  5186.          tmp1 tmp2 tmp3 tmp4)
  5187.     (irc-remember origin 'irc-servernames)
  5188.     (cond
  5189.       ((= num 001)
  5190.        )
  5191.       ((= num 002)
  5192.        (irc-parse-notice (format "NOTICE %s :*** %s" user txt)))
  5193.       ((= num 003)
  5194.        (irc-parse-notice (format "NOTICE %s :*** %s" user txt)))
  5195.       ((= num 004)
  5196.        (irc-insert "*** FEATURES: %s" txt))
  5197.       (t                                 ; default
  5198.        (irc-insert (concat "%%Unrecognized numeric RPL 0xx message; "
  5199.                    "please tell %s:")
  5200.                irc-hacker)
  5201.        (irc-insert "%% str=\"%s\"." str)
  5202.        (irc-insert "%% Function irc-parse-RPL-0xx."))))
  5203.       ;; else
  5204.       (irc-insert (concat "%%Unrecognized nonnumeric RPL 0xx message follows; "
  5205.               "please tell %s:")
  5206.           irc-hacker)
  5207.       (irc-insert "%% \"%s\"." str)
  5208.       (irc-insert "%% Function irc-parse-RPL-0xx."))
  5209.   nil)
  5210.  
  5211.  
  5212. (defun irc-parse-RPL-2xx (str)
  5213.   "Examine a numeric RPL_ message from the IRC server.
  5214. Numeric control messages are used by newer servers to aid in generalized
  5215. client design; while people are converting to the new servers the older
  5216. irc-parse-error, irc-parse-notice, et al, functions are redundant with
  5217. irc-parse-ERR and irc-parse-RPL.  Values used by this function are found
  5218. in the IRC source file numeric.h.
  5219.  
  5220. Note well that some things are still going to come out wrong because the
  5221. servers are currently still doing things inconsistently."
  5222.   (if (string-match (concat "^:?\\([^: ]+\\) *\\([023][0-9][0-9]\\) +"
  5223.                 "\\([^: ]+\\)? +:?")
  5224.             str)
  5225.       ;; we assume that the server and message are consistent for us; just
  5226.       ;; worry about the numeric value and the rest of the line
  5227.       (let* ((origin (subfield str 1))
  5228.          (num (string-to-int (subfield str 2)))
  5229.          (user (subfield str 3))
  5230.          (txt (substring str (match-end 0)))
  5231.          (parorg (if (string= (upcase origin) (upcase irc-server))
  5232.              ""
  5233.              (concat "(" origin ") ")))
  5234.          tmp1 tmp2 tmp3 tmp4)
  5235.     (irc-remember origin 'irc-servernames)
  5236.     (cond
  5237.       ((= num 200)
  5238.        (cond ((string-match
  5239.            "^ *Link +\\([^ ]+\\) *:?\\([^ ]+\\) *:?\\([^ ]+\\)? *$"
  5240.            txt)
  5241.           (let ((vrsn (subfield txt 1))
  5242.             (goal (subfield txt 2))
  5243.             (next (subfield txt 3)))
  5244.             (irc-insert "%sLink to %s passes %s<%s>%s%s"
  5245.                 irc-msg-info-pre
  5246.                 (upcase goal)
  5247.                 (upcase origin)
  5248.                 (upcase vrsn)
  5249.                 (if (string= "" next)
  5250.                     ""
  5251.                     (concat "; next:" next))
  5252.                 irc-msg-info-post)))
  5253.          (t (irc-insert "%%Unknown RPL200 received in irc-parse-RPL-2xx:")
  5254.             (irc-insert "%% \"%s\" (txt)." txt)
  5255.             (irc-insert "%% Please tell %s, this might be a bug."
  5256.                 irc-hacker))))
  5257.       ((or (= num 201)        ; RPL_TRACECONNECTING "Try."
  5258.            (= num 202))        ; RPL_TRACEHANDSHAKE
  5259.        (cond ((string-match "^\\([^ ]+\\) +\\([0-9]+\\) +:?\\([^ ]+\\)"
  5260.                 txt)
  5261.           (let* ((type (subfield txt 1))
  5262.              (class (subfield txt 2))
  5263.              (host (subfield txt 3))
  5264.              (utype (upcase type))
  5265.              (state (cond ((string= "TRY." utype)
  5266.                        "trying to connect to it")
  5267.                       ((string= "H.S." utype)
  5268.                        "registering us as server at it")
  5269.                       (t type))))
  5270.             (irc-insert "%s%sClass %3s half: %s (%s)%s"
  5271.                 irc-msg-info-pre
  5272.                 parorg class (upcase host) state
  5273.                 irc-msg-info-post)))
  5274.          (t (irc-insert "%%Received unknown RPL%d in irc-parse-RPL-2xx:"
  5275.                 num)
  5276.             (irc-insert "%% \"%s\" (txt)." txt)
  5277.             (irc-insert "%% Please tell %s, it might be a bug."
  5278.                 irc-hacker))))
  5279.       ((or (= num 203)        ; RPL_TRACEUNKNOWN
  5280.            (= num 204)        ; RPL_TRACEOPERATOR "Oper"
  5281.            (= num 205))        ; RPL_TRACEUSER "User"
  5282.        (cond ((string-match (concat "^\\([^ ]+\\) +\\(-?[0-9]+\\) *:?"
  5283.                     "*\\([^ ]*\\)\\[\\(.+\\)\\] *"
  5284.                     ":?[0-9]*")
  5285.                 txt)
  5286.           (let* ((type (subfield txt 1))
  5287.              (class (subfield txt 2))
  5288.              (u (subfield txt 3))
  5289.              (cm (subfield txt 4))
  5290.              (user (irc-nuke-whitespace u)))
  5291.             (if (string< "" user)
  5292.             (irc-remember user 'irc-nicknames))
  5293.             (irc-insert "%s%sClass %3s %s: \"%s\" (client on %s)%s"
  5294.                 irc-msg-info-pre
  5295.                 parorg
  5296.                 class
  5297.                 (downcase type)
  5298.                 user
  5299.                 (upcase cm)
  5300.                 irc-msg-info-post)))
  5301.          (t (irc-insert
  5302.              "%%Unknown RPL203:205 seen, in irc-parse-RPL-2xx:")
  5303.             (irc-insert "%% \"%s\" (str); \"%s\" (txt)." str txt)
  5304.             (irc-insert "%% Please tell %s, it might be a bug."
  5305.                 irc-hacker))))
  5306.       ((= num 206)            ; RPL_TRACESERVER "Serv"
  5307.        (if (or (string-match (concat "^\\([^ ]+\\) +\\([0-9]+\\) +\\(\\)"
  5308.                      "\\([0-9]+\\)S +\\([0-9]+\\)C +:? *"
  5309.                      "\\([^ ]+\\) *$")
  5310.                  txt)
  5311.            (string-match (concat "^\\([^ ]+\\) +\\([0-9]+\\) +"
  5312.                      "\\([^ ]+\\) +\\([0-9]+\\)S *:?"
  5313.                      " *\\([0-9]+\\)C *$")
  5314.                  txt)
  5315.            (string-match (concat "^\\([^ ]+\\) +\\([0-9]+\\) *"
  5316.                      ":? *\\(.+\\) *\\(\\)\\(\\)$")
  5317.                  txt))
  5318.            (let* ((type (subfield txt 1))
  5319.               (class (subfield txt 2))
  5320.               (r (subfield txt 3))
  5321.               (ns (string-to-int (subfield txt 4)))
  5322.               (nc (string-to-int (subfield txt 5)))
  5323.               (remote (if (string= "" r) (subfield txt 6) r)))
  5324.          (irc-remember remote 'irc-servernames)
  5325.          (irc-insert "%s%sClass %3s %s: %s%s%s"
  5326.                  irc-msg-info-pre
  5327.                  parorg
  5328.                  class
  5329.                  (downcase type)
  5330.                  (upcase remote)
  5331.                  (if (and (= ns 0) (= nc 0))
  5332.                  ""
  5333.                  (format " (%d server%s, %d client%s)%s"
  5334.                      ns
  5335.                      (if (= 1 ns) "" "s")
  5336.                      nc
  5337.                      (if (= 1 nc) "" "s")))
  5338.                  irc-msg-info-post))
  5339.            (progn
  5340.          (irc-insert "%%Unknown RPL206 received in irc-parse-RPL-2xx:")
  5341.          (irc-insert "%% \"%s\" (txt)." txt)
  5342.          (irc-insert "%% Please tell %s, it might be a bug."
  5343.                  irc-hacker))))
  5344.       ;; Missing 207 RPL_TRACESERVICE
  5345.       ;; Missing 208 RPL_TRACENEWTYPE
  5346.       ((= num 209)            ; RPL_TRACECLASS
  5347.        (cond ((string-match (concat "^Class +\\([0-9]+\\) *"
  5348.                     ":? *\\([0-9]+\\) *$")
  5349.                 txt)
  5350.           (let ((class (string-to-int (subfield txt 1)))
  5351.             (count (string-to-int (subfield txt 2))))
  5352.             (irc-insert
  5353.              "%s%s%d service%s linked for class %3d%s"
  5354.              irc-msg-info-pre
  5355.              parorg
  5356.              count
  5357.              (if (= 1 count) "" "s")
  5358.              class
  5359.              irc-msg-info-post)))
  5360.          (t (irc-insert "%%Unknown RPL209 message in irc-parse-RPL-2xx:")
  5361.             (irc-insert "%% \"%s\" (txt)" txt)
  5362.             (irc-insert "%% Please tell %s, it might be a bug."
  5363.                 irc-hacker))))
  5364.       ((= num 211)            ;L-lines
  5365.        (cond ((string-match (concat "^\\([^: ]+\\) +\\([0-9]+\\) +"
  5366.                     "\\([0-9]+\\) +\\([0-9]+\\) +"
  5367.                     "\\([0-9]+\\) +\\([0-9]+\\) +"
  5368.                     ": *\\(.*\\) *$")
  5369.                 txt)
  5370.           (let* ((link (subfield txt 1))
  5371.              (sendq (subfield txt 2))
  5372.              (sendm (subfield txt 3))
  5373.              (sendbytes (subfield txt 4))
  5374.              (rcvem (subfield txt 5))
  5375.              (rcvebytes (subfield txt 6))
  5376.              (rest (subfield txt 7))
  5377.              (irc-msg-cont-used
  5378.               "                                                 "))
  5379.             (irc-insert "%8s %8s %10s %8s %10s %s"
  5380.                 sendq sendm sendbytes rcvem rcvebytes rest)
  5381.             (irc-insert "%s(to %s)" irc-msg-cont-used (upcase link))))
  5382.          ((string-match (concat "^ *\\(Link +\\)?SendQ +SendM"
  5383.                     " +SendBytes +RcveM +RcveBytes"
  5384.                     " +:Open since *$")
  5385.                 txt)
  5386.           (irc-insert (concat
  5387.                    " SendQue   S-Msgs    S-Bytes   R-Msgs"
  5388.                    "    R-Bytes Date (to link)"))
  5389.           (irc-insert (concat
  5390.                    "-------- -------- ---------- --------"
  5391.                    " ---------- --------------")))
  5392.          (t (irc-insert "%%Unknown RPL211, in irc-parse-RPL-2xx:")
  5393.             (irc-insert "%% \"%s\" (txt)." txt)
  5394.             (irc-insert "%% Please tell %s, it might be a bug."
  5395.                 irc-hacker))))
  5396.       ((= num 212)            ;RPL_STATSCOMMANDS (ie non CIKLQY)
  5397.        (cond ((string-match "^\\([^ ]+\\) +:?\\([0-9]+\\) *\\([0-9]+\\)?$"
  5398.                 txt)
  5399.           (let* ((type (subfield txt 1))
  5400.              (count (subfield txt 2))
  5401.              (rcount (subfield txt 3))
  5402.              (n (string-to-int count))
  5403.              (rn (string-to-int rcount))
  5404.              (c (concat (make-string (max 0 (- 5 (length count)))
  5405.                          ? )
  5406.                     count))
  5407.              (cmds (if (= n 1) "command " "commands")))
  5408.             (irc-insert "%sServer %s has seen %s %s of type %s%s%s"
  5409.                 irc-msg-info-pre
  5410.                 (upcase origin)
  5411.                 c
  5412.                 cmds
  5413.                 (upcase type)
  5414.                 (if (string= "" rcount)
  5415.                     ""
  5416.                     (format " %s(%d remote?)"
  5417.                         (make-string (- 7 (length type))
  5418.                              ? )
  5419.                         rn))
  5420.                 irc-msg-info-post)))
  5421.          (t (irc-insert
  5422.              "%%Unknown RPL212 message received in irc-parse-RPL-2xx:")
  5423.             (irc-insert "%% \"%s\" (txt)." txt)
  5424.             (irc-insert "%% Please tell %s, it might be a bug."
  5425.                 irc-hacker))))
  5426.       ((or (= num 213)        ;C-lines
  5427.            (= num 214)        ;N-lines
  5428.            (= num 215)        ;I-lines
  5429.            (= num 216)        ;K-lines
  5430.            (= num 217)        ;Q-lines
  5431.            (= num 241)        ;L-lines
  5432.            (= num 242)        ;Uptime
  5433.            (= num 243)        ;O-lines
  5434.            (= num 244)        ;H-lines
  5435.            (= num 249)        ;other such lines
  5436.            )
  5437.        (cond ((string= (upcase origin) (upcase irc-server))
  5438.           (irc-insert "*** %s" txt))
  5439.          (t (irc-insert "*** (%s): %s" origin txt))))
  5440.       ((= num 218)            ;Y-lines
  5441.        (cond ((string-match
  5442.            (concat "^ *Y +\\([0-9]+\\) +\\([0-9]+\\) +\\([0-9]+\\) +:?"
  5443.                " *\\([0-9]+\\) +:?\\([0-9]+\\)")
  5444.            txt)
  5445.           (let* ((class (subfield txt 1))
  5446.              (ping-freq (subfield txt 2))
  5447.              (conn-freq (subfield txt 3))
  5448.              (max-links (subfield txt 4))
  5449.              (plur (if (= 1 (string-to-int max-links)) "" "s"))
  5450.              (sendq (subfield txt 5))
  5451.              (pre (format (concat "*** %sClass: %s, conn. freq."
  5452.                           " %ss, ping freq. %ss, ")
  5453.                       parorg class conn-freq ping-freq))
  5454.              (irc-msg-cont-used (make-string (length pre) ? )))
  5455.             (irc-insert "%smax# %s link%s, SendQ %s."
  5456.                 pre
  5457.                 max-links
  5458.                 plur
  5459.                 sendq)))
  5460.          (t (irc-insert "%%Unknown RPL218 in irc-parse-RPL-2xx:")
  5461.             (irc-insert "%% \"%s\" (txt)." txt)
  5462.             (irc-insert "%% Please tell %s, it might be a bug."
  5463.                 irc-hacker))))
  5464.       ((= num 219)
  5465.        (irc-insert "%sSTATS listing for server %s done%s"
  5466.                irc-msg-info-pre
  5467.                (upcase origin)
  5468.                irc-msg-info-post)
  5469.        (irc-insert ""))
  5470.       ((= num 221)
  5471.        (let ((i (1- (length txt)))
  5472.          (ut (upcase txt)))
  5473.          (while (and (>= i 0) (not (= ?O (aref ut i))))
  5474.            (setq i (1- i)))
  5475.          (while (and (>= i 0)
  5476.              (not (= ?- (aref ut i)))
  5477.              (not (= ?+ (aref ut i))))
  5478.            (setq i (1- i)))
  5479.          (setq irc-operator (if (and (>= i 0) (= ?+ (aref ut i)))
  5480.                      " IOPR"
  5481.                      nil)))
  5482.        (irc-insert "%sUser %s'%s mode%s: %s%s"
  5483.                irc-msg-info-pre
  5484.                user
  5485.                (if (= ?S (aref (upcase user) (1- (length user))))
  5486.                ""
  5487.                "s")
  5488.                (if (= 2 (length txt)) " is" "s are")
  5489.                (irc-explain-user-mode txt 'no-direction)
  5490.                irc-msg-info-post))
  5491. ;;;      ((= num 232)
  5492. ;;;       (irc-insert "DEBUG: RPL232 txt=\"%s\"." txt))
  5493. ;;;      ((= num 241) SEE RPL213-217
  5494. ;;;       )
  5495. ;;;      ((= num 242) SEE RPL213-217
  5496. ;;;       )
  5497. ;;;      ((= num 243) SEE RPL213-217
  5498. ;;;       )
  5499. ;;;      ((= num 244) SEE RPL213-217
  5500. ;;;       )
  5501. ;;;      ((= num 249) SEE RPL213-217
  5502. ;;;       )
  5503.       ((= num 250)
  5504.        (irc-insert "*** %s" txt))
  5505.       ((= num 251)
  5506.        (irc-insert "*** %s" txt))
  5507.       ((= num 252)
  5508.        (cond ((string-match "^\\([0-9]+\\) +:operator.*online$" txt)
  5509.           (irc-parse-notice (format (concat
  5510.                          "NOTICE %s :*** %s users have"
  5511.                          " connection to the twilight"
  5512.                          " zone")
  5513.                         user (subfield txt 1))))
  5514.          ((string-match "^\\([^ :]+\\) *: *\\(.*\\)$" txt)
  5515.           (irc-insert "*** %s %s" (subfield txt 1) (subfield txt 2)))
  5516.          (t (irc-insert "*** %s" txt))))
  5517.       ((= num 253)
  5518.        (if (string-match "^\\([0-9]+\\) *:unknown connection(?s?)?" txt)
  5519.            (let ((n (string-to-int (subfield txt 1))))
  5520.          (irc-insert "*** There %s %d %s of (yet) unknown %s."
  5521.                  (if (= 1 n) "is" "are")
  5522.                  n
  5523.                  (if (= 1 n) "connection" "connections")
  5524.                  (if (= 1 n) "type" "types")))
  5525.            (progn (irc-insert "%%Unrecognized RPL 253 message seen:")
  5526.               (irc-insert "%% \"%s\" (txt)" txt)
  5527.               (irc-insert "%% Please tell %s" irc-hacker))))
  5528.       ((= num 254)
  5529.        (if (string-match "^\\([0-9]+\\) :channel" txt)
  5530.            (irc-parse-notice (format (concat "NOTICE %s :*** There are %s"
  5531.                          " channels.")
  5532.                      user (subfield txt 1)))
  5533.            (irc-insert "*** %s" txt)))
  5534.       ((= num 255)            ;"I have 77 clients, 0 services and 1 servers"
  5535.        (let ((text (if (string-match "^I have \\(.*\\)" txt)
  5536.                (format "%s has %s"
  5537.                    (upcase origin)
  5538.                    (subfield txt 1))
  5539.              txt)))
  5540.          (irc-insert "*** %s" text)))
  5541.       ((= num 256)            ;RPL admin, first line
  5542.        (irc-insert "### %s" txt))
  5543.       ((= num 257)            ;RPL admin, second line
  5544.        (irc-insert "### %s" txt))
  5545.       ((= num 258)            ;RPL admin, third line
  5546.        (irc-insert "### %s" txt))
  5547.       ((= num 259)            ;RPL admin, fourth and last line
  5548.        (irc-insert "### %s" txt)
  5549.        (irc-insert "%sEnd of ADMIN for %s%s"
  5550.                irc-msg-info-pre origin irc-msg-info-post)
  5551.        (irc-insert ""))
  5552.       ((= num 261)            ;RPL log file
  5553.        (if (string-match "^File +\\(.+\\) +:\\([0-9]+\\)$"
  5554.                  txt)
  5555.            (let ((file (subfield txt 1))
  5556.              (dbglvl (subfield txt 2)))
  5557.          (irc-insert
  5558.           "%s%sThe servers log file for debug level %s is %s%s"
  5559.           irc-msg-info-pre
  5560.           parorg
  5561.           dbglvl
  5562.           file
  5563.           irc-msg-info-post))
  5564.            (progn (irc-insert "%%Unknown RPL 261 seen:")
  5565.               (irc-insert "%% \"%s\" (txt)" txt)
  5566.               (irc-insert "%% Please tell %s" irc-hacker))))
  5567.       ((= num 262)
  5568.        (if (string-match "\\([^ ]+\\) +\\([^ ]+\\)\\.? *: *\\(.*\\)" txt)
  5569.            (irc-insert "%%%s for %s who's using a server of version %s"
  5570.                (subfield txt 3)
  5571.                (subfield txt 1)
  5572.                (subfield txt 2))
  5573.          (irc-insert "%%%s" txt)))
  5574.       ((= num 265)
  5575.        (irc-insert "*** %s" txt))
  5576.       ((= num 266)
  5577.        (irc-insert "*** %s" txt))
  5578.       (t                                 ; default
  5579.        (irc-insert (concat "%%Unrecognized numeric RPL 2xx message; "
  5580.                    "please tell %s:")
  5581.                irc-hacker)
  5582.        (irc-insert "%% str=\"%s\"." str)
  5583.        (irc-insert "%% Function irc-parse-RPL-2xx."))))
  5584.       ;; else
  5585.       (irc-insert (concat "%%Unrecognized nonnumeric RPL 2xx message follows; "
  5586.               "please tell %s:")
  5587.           irc-hacker)
  5588.       (irc-insert "%% \"%s\"." str)
  5589.       (irc-insert "%% Function irc-parse-RPL-2xx."))
  5590.   nil)
  5591.  
  5592.  
  5593. (defun irc-parse-RPL-3xx (str)
  5594.   "Examine a numeric RPL_ message from the IRC server.
  5595. Numeric control messages are used by newer servers to aid in generalized
  5596. client design; while people are converting to the new servers the older
  5597. irc-parse-error, irc-parse-notice, et al, functions are redundant with
  5598. irc-parse-ERR and irc-parse-RPL.  Values used by this function are found
  5599. in the IRC source file numeric.h.
  5600.  
  5601. Note well that some things are still going to come out wrong because the
  5602. servers are currently still doing things inconsistently."
  5603.   (if (string-match (concat "^:?\\([^: ]+\\) *\\([023][0-9][0-9]\\) +"
  5604.                 "\\([^: ]+\\)? +:?")
  5605.             str)
  5606.       ;; we assume that the server and message are consistent for us; just
  5607.       ;; worry about the numeric value and the rest of the line
  5608.       (let* ((origin (subfield str 1))
  5609.          (num (string-to-int (subfield str 2)))
  5610.          (user (subfield str 3))
  5611.          (txt (substring str (match-end 0)))
  5612.          (parorg (if (string= (upcase origin) (upcase irc-server))
  5613.              ""
  5614.              (concat "(" origin ") ")))
  5615.          tmp1 tmp2 tmp3 tmp4)
  5616.     (irc-remember origin 'irc-servernames)
  5617.     (cond
  5618.      ((= num 301)                       ; RPL_AWAY
  5619.       (cond ((string-match "^\\([^: ]+\\) :" txt)
  5620.          (let ((nick (subfield txt 1))
  5621.                (msg (substring txt (match-end 0))))
  5622.            (irc-remember nick 'irc-nicknames)
  5623.            (irc-insert "%%User %s is away (%s)."
  5624.                    nick
  5625.                    (irc-clean-up-message msg))))
  5626.         (t (irc-insert (concat "%%One of the last persons you sent to"
  5627.                        " is away, delivered your"
  5628.                        " message anyway.")))))
  5629.      ((= num 302)                 ; RPL_USERHOST
  5630.       (let ((s txt))
  5631.         (while (string-match
  5632.             (concat "^\\([^ =*]+\\)\\(\\*?\\)=\\([+-]\\)"
  5633.                 "\\([^@]+\\)@\\([^ ]+\\) *")
  5634.             s)
  5635.           (let* ((nick (subfield s 1))
  5636.              (oper (subfield s 2))
  5637.              (away (subfield s 3))
  5638.              (user (subfield s 4))
  5639.              (host (subfield s 5))
  5640.              (rest (substring s (match-end 0))))
  5641.         (irc-remember nick 'irc-nicknames)
  5642.         (irc-remember host 'irc-servernames)
  5643.         (irc-insert "%s%s \"%s\" is %s@%s%s%s"
  5644.                 irc-msg-info-pre
  5645.                 (if (string= "*" oper) "Operator" "User")
  5646.                 nick
  5647.                 user
  5648.                 host
  5649.                 (if (string= "-" away) " (AWAY)" "")
  5650.                 irc-msg-info-post)
  5651.         (setq s rest)))))
  5652.      ((= num 303)                 ; RPL_ISON
  5653.       (let ((data (if (and (> (length txt) 0) (= ?: (aref txt 0)))
  5654.               (substring txt 1) txt))
  5655.         (ignored 0)
  5656.         (list ())
  5657.         (found ()))
  5658.         (while (string-match "^ *\\([^ ]+\\)" data)
  5659.           (setq found (cons (subfield data 1) found)
  5660.             data (substring data (match-end 0))))
  5661.         (while (not (null found))
  5662.           (if (irc-recall (car found) 'irc-ignored-ppl)
  5663.           (setq ignored (1+ ignored))
  5664.         (setq list (cons (car found) list)))
  5665.           (setq found (cdr found)))
  5666.         (setq list (reverse list))    ;Keep list sorted.
  5667.         (let ((l list)
  5668.           (arrivers ()))
  5669.           (while (not (null l))
  5670.         (if (not (irc-recall (car l) 'irc-notify-detected))
  5671.             (progn (setq arrivers (cons (car l) arrivers))
  5672.                (irc-send (format "WHOIS %s %s" (car l) (car l)))
  5673.                (irc-remember (car l) 'irc-notify-detected)
  5674.                (irc-remember (car l) 'irc-nicknames)
  5675.                ))
  5676.         (setq l (cdr l)))
  5677.           (let ((l (irc-recall-all 'irc-notify-detected))
  5678.             (gonners ()))
  5679.         (while (not (null l))
  5680.           (if (not (irc-list-recall (car l) list))
  5681.               (progn (setq gonners (cons (car l) gonners))
  5682.                  (irc-forget (car l) 'irc-notify-detected)))
  5683.           (setq l (cdr l)))
  5684.         (if (not (null arrivers))
  5685.             (let ((a arrivers)
  5686.               (as (irc-listify arrivers ", " "and")))
  5687.               (irc-insert "%sDETECTED %s%s on IRC%s"
  5688.                   irc-msg-info-pre
  5689.                   as
  5690.                   (if (> ignored 0)
  5691.                       (format " (also %d ignored person%s)"
  5692.                           ignored
  5693.                           (if (= 1 ignored) "" "s"))
  5694.                     "")
  5695.                   irc-msg-info-post)
  5696.               (if (irc-signal (car a) 'detect)
  5697.               (progn
  5698.                 (message (format "Kiwi: Detected %s on IRC" as))
  5699.                 (ding t)))))
  5700.         (if (not (null gonners))
  5701.             (let ((g gonners)
  5702.               (gs (irc-listify gonners ", " "and")))
  5703.               (irc-insert "%sLOST SIGHT of %s from IRC%s"
  5704.                   irc-msg-info-pre
  5705.                   gs
  5706.                   irc-msg-info-post)
  5707.               (while g
  5708.             (if (irc-signal (car g) 'detect)
  5709.                 (progn
  5710.                   (message (format
  5711.                     "Kiwi: lost sight of %s from IRC"
  5712.                     gs))
  5713.                   (ding t)))
  5714.             (setq g (cdr g)))))))))
  5715.      ((= num 304)                 ; RPL_TEXT
  5716.       (irc-insert "Text: %s" txt))
  5717.      ((= num 305)
  5718.       (irc-insert "%sYou are no longer marked as being away%s"
  5719.               irc-msg-info-pre irc-msg-info-post))
  5720.      ((= num 306)
  5721.       (irc-insert (concat "%sYou have been marked as being away, use"
  5722.                   " /HERE to revert the effect%s")
  5723.               irc-msg-info-pre irc-msg-info-post))
  5724.      ((= num 311)                       ; RPL_WHOISUSER
  5725.       (string-match (concat "^\\([^: ]+\\) +\\([^: ]+\\) +\\([^: ]+\\)"
  5726.                 " \\([^: ]+\\) :")
  5727.             txt)
  5728.       (let* ((nick (subfield txt 1))
  5729.          (rn (substring txt (match-end 0)))
  5730.          (user-name (subfield txt 2))
  5731.          (client (subfield txt 3))
  5732.          (c (subfield txt 4))
  5733.          (channel (if (string= c "*")
  5734.                   ""
  5735.                 (concat " on channel " c)))
  5736.          (cntrl1 (format "%s \"%s\" "
  5737.                  (if (irc-recall nick 'irc-ignored-ppl)
  5738.                      "IGNORED user"
  5739.                    "User")
  5740.                  nick))
  5741.          (real-name (irc-nuke-whitespace rn)))
  5742.         (setq irc-msg-cont-used (make-string (length cntrl1) ? ))
  5743.         (irc-remember nick 'irc-nicknames)
  5744.         (irc-insert (concat cntrl1 "is %s <%s@%s>%s,")
  5745.             (irc-clean-up-message real-name)
  5746.             (irc-clean-up-message user-name)
  5747.             client
  5748.             channel)))
  5749.      ((= num 312)            ; RPL_WHOISSERVER
  5750.       (let ((info-hop-count nil)
  5751.         (info-nick nil)
  5752.         (info-real-server-or-relay-name nil)
  5753.         (info-server-name nil)
  5754.         (info-server-descr nil)
  5755.         (found-info nil))
  5756.         (cond
  5757.          ((string-match "^ *\\([^ :]+\\) +\\([^ :]+\\) *: *" txt)
  5758.           (setq info-nick (subfield txt 1)
  5759.             info-server-name (subfield txt 2))
  5760.           (let ((rst (substring txt (match-end 0))))
  5761.         (cond ((string-match (concat "^... ... +[0-9]+ [0-9]+:"
  5762.                          "[0-9]+:[0-9]+ [0-9]+$")
  5763.                      rst)
  5764.                (setq info-server-descr (format "gone since %s" rst)
  5765.                  found-info t))
  5766.               ((string-match (concat "^\\([0-9]+\\) *: *\\["
  5767.                          "\\([^]]+\\)\\] *\\(.*\\) *$")
  5768.                      rst)
  5769.                (setq info-hop-count (subfield rst 1)
  5770.                  info-real-server-or-relay-name (subfield rst 2)
  5771.                  info-server-descr (subfield rst 3)
  5772.                  found-info t))
  5773.               ((string-match "^\\([0-9]+\\) +:? *\\(.*\\) *$" rst)
  5774.                (setq info-hop-count (subfield rst 1)
  5775.                  info-server-descr (subfield rst 2)
  5776.                  found-info t))
  5777.               ((string-match "^\\[\\([^]]+\\)\\] *\\(.*\\) *$"
  5778.                      rst)
  5779.                (setq info-real-server-or-relay-name (subfield rst 1)
  5780.                  info-server-descr (subfield rst 2)
  5781.                  found-info t))
  5782.               (t (setq info-server-descr rst
  5783.                    found-info t)))))
  5784.          ((string-match (concat "^\\([^ :]+\\) *: *\\([0-9]+\\) *: *"
  5785.                     "\\([^ ].*[^ ]\\) *$")
  5786.                 txt)
  5787.           (setq info-server-name (subfield txt 1)
  5788.             info-hop-count (subfield txt 2)
  5789.             info-server-descr (subfield txt 3)
  5790.             found-info t))
  5791.          ((string-match "^\\([^ :]+\\) *: *\\([^ ].*[^ ]\\) *$" txt)
  5792.           (setq info-server-name (subfield txt 1)
  5793.             info-server-descr (subfield txt 2)
  5794.             found-info t)))
  5795.         (if (not found-info)
  5796.         (progn
  5797.           (irc-insert "%%Found unknown RPL312 in irc-parse-RPL-3xx:")
  5798.           (irc-insert "%% \"%s\" (txt)." txt)
  5799.           (irc-insert "%% Please tell %s, it might be a bug."
  5800.                   irc-hacker))
  5801.           (irc-remember info-server-name 'irc-servernames)
  5802.           (let ((s (format "%s%son %s (%s)%s."
  5803.                    irc-msg-cont-used
  5804.                    (if info-real-server-or-relay-name
  5805.                    (concat "(according to "
  5806.                        info-real-server-or-relay-name
  5807.                        ") ")
  5808.                  "")
  5809.                    info-server-name
  5810.                    (irc-clean-up-message
  5811.                 (irc-nuke-whitespace info-server-descr))
  5812.                    (if info-hop-count
  5813.                    (concat " at least "
  5814.                        info-hop-count
  5815.                        " hops away")
  5816.                  ""))))
  5817.         (irc-insert "%s" s)))))
  5818.      ((= num 313)            ; RPL_WHOISOPERATOR
  5819.       (string-match "^[^: ]+" txt)
  5820.       (irc-insert "%s\"%s\" is an ENABLED operator on IRC."
  5821.               irc-msg-cont-used
  5822.               (substring txt (match-beginning 0) (match-end 0))))
  5823.      ((= num 314)                 ; RPL_WHOWASUSER
  5824.       (if (string-match (concat "^\\([^: ]+\\) \\([^: ]+\\) \\([^: ]+\\)"
  5825.                     " \\([^: ]+\\) *:")
  5826.                 txt)
  5827.           (let* ((nick (subfield txt 1))
  5828.              (rn (substring txt (match-end 0)))
  5829.              (user-name (subfield txt 2))
  5830.              (client (subfield txt 3))
  5831.              (c (subfield txt 4))
  5832.              (channel (if (string= c "*")
  5833.                   ""
  5834.                 (concat " on channel " c)))
  5835.              (real-name (irc-nuke-whitespace rn))
  5836.              (cntrl1 (format "%%User \"%s\" " nick)))
  5837.         (setq irc-msg-cont-used (make-string (length cntrl1) ? ))
  5838.         (if (not (irc-recall nick 'irc-services))
  5839.             (irc-forget nick 'irc-nicknames))
  5840.         (irc-insert (concat "%" cntrl1 "isn't on IRC anymore,"
  5841.                     " was %s <%s@%s>%s,")
  5842.                 (irc-clean-up-message real-name)
  5843.                 (irc-clean-up-message user-name)
  5844.                 client
  5845.                 channel))))
  5846.      ((= num 315)                 ; RPL_WHOEND
  5847.       (if (= 0 irc-reply-count)
  5848.           (irc-insert "%%No users listed")
  5849.         (irc-insert "%s%d user%s listed%s"
  5850.             irc-msg-info-pre
  5851.             irc-reply-count
  5852.             (if (= 1 irc-reply-count) "" "s")
  5853.             irc-msg-info-post))
  5854.       (setq irc-reply-count 0)
  5855.       (if t ()
  5856.         (message "")
  5857.         (if (irc-nothing-remembered-p 'irc-whotree)
  5858.         (let ((c (if (string-match (concat "^ *: *[^ ]+ +315"
  5859.                            " +[^ ]+ +\\([^:]+\\)"
  5860.                            " +:")
  5861.                        str)
  5862.                  (subfield str 1))))
  5863.           (irc-insert (if c "%%No users on \"%s\"." "%%No users.")
  5864.                   c))
  5865.           (irc-recall-all-and-display 'irc-whotree
  5866.                     ;(string-match "-* *$"
  5867.                     ;irc-who-stroke)
  5868.                       31
  5869.                       "users"
  5870.                       "user")
  5871.           (irc-forget-all 'irc-whotree)))
  5872.       )
  5873.      ((= num 316)                 ; RPL_WHOISCHANOP
  5874.       (if (not
  5875.            (string-match (concat "^:\\([^: ]+\\)? +316 +\\([^: ]+\\) +"
  5876.                      "\\([^: ]+\\) +: *has +been +"
  5877.                      "touched +by +magic +forces *$")
  5878.                  str))
  5879.           (progn (irc-insert (concat "%%Unrecognized type 316 reply; "
  5880.                      "please tell %s:")
  5881.                  irc-hacker)
  5882.              (irc-insert "%% \"%s\"." str)
  5883.              (irc-insert " Function irc-parse-RPL-3xx, at 316."))
  5884.         (let ((server (substring str (match-beginning 1) (match-end 1)))
  5885.           (own (substring str (match-beginning 2) (match-end 2)))
  5886.           (other (substring str (match-beginning 3) (match-end 3))))
  5887.           (irc-remember own 'irc-nicknames)
  5888.           (irc-remember other 'irc-nicknames)
  5889.           (irc-insert "%s\"%s\" is a channel operator."
  5890.               irc-msg-cont-used
  5891.               other))))
  5892.      ((= num 317)            ;RPL_IDLETIME
  5893.       (cond ((or (string-match (concat "^ *: *[^ ]+ +317 +[^ ]+"
  5894.                        " +\\([^ ]+\\)"
  5895.                        " +\\([0-9]+\\)"
  5896.                        " +\\([0-9]+\\)"
  5897.                        " *:")
  5898.                    str)
  5899.              (string-match (concat "^ *: *[^ ]+ +317 +[^ ]+"
  5900.                        " +\\([^ ]+\\)"
  5901.                        " +\\([0-9]+\\)"
  5902.                        "\\(\\) *:")
  5903.                    str)
  5904.              (string-match (concat "^ *: *[^ ]+ +317 +[^ ]+\\(\\)\\(\)"
  5905.                        " +\\([0-9]+\\)"
  5906.                        " *:")
  5907.                    str))
  5908.          (let* ((user (subfield str 1))
  5909.             (time (string-to-int (subfield str 2)))
  5910.             (logintime (string-to-int (subfield str 3))))
  5911.            (if (zerop time)
  5912.                (irc-insert "%s\"%s\" is actively typing."
  5913.                    irc-msg-cont-used
  5914.                    user)
  5915.              (irc-insert "%sIdle time for user %s is %d second%s%s."
  5916.                  irc-msg-cont-used
  5917.                  user
  5918.                  time
  5919.                  (if (= 1 time) "" "s")
  5920.                  (if (> 60 time)
  5921.                      ""
  5922.                    (concat " ("
  5923.                        (irc-sec-to-time time)
  5924.                        ")"))))))
  5925.         (t (irc-insert (concat "%%Unknown 317 type reply message in"
  5926.                        " function irc-parse-RPL-3xx."))
  5927.            (irc-insert "%% \"%s\" (str)." str)
  5928.            (irc-insert "%% Please tell %s, it might be a bug."
  5929.                    irc-hacker))))
  5930.      ((= num 318)                 ; RPL_ENDOFWHOIS
  5931.       )
  5932.      ((= num 319)
  5933.       (cond ((string-match "^\\([^:]*:\\)?" txt)
  5934.          (let ((list (irc-listify
  5935.                   (irc-burst-comma
  5936.                    (irc-nuke-whitespace
  5937.                 (substring txt (match-end 0))))
  5938.                   ", " "and")))
  5939.            (irc-insert "%sis listening to channel%s %s,"
  5940.                    irc-msg-cont-used
  5941.                    (if (string-match " [^ ]" list) "s" "")
  5942.                    list)))
  5943.         (t (irc-insert (concat "%%Unknown 319 type reply message in"
  5944.                        " function irc-parse-RPL-3xx."))
  5945.            (irc-insert "%% \"%s\" (txt)." txt)
  5946.            (irc-insert "%% Please tell %s, it might be a bug."
  5947.                    irc-hacker))))
  5948.      ((= num 321)                       ; RPL_LISTSTART
  5949.       (irc-insert irc-list-header)
  5950.       (irc-insert irc-list-stroke)
  5951.       (setq irc-list-stats '(0 0))
  5952.       (set-buffer-modified-p (buffer-modified-p)))
  5953.      ((= num 322)                       ; RPL_LIST
  5954.       (if (not (string-match "^\\([^ ]+\\) \\([^ ]+\\) :" txt))
  5955.           (progn (irc-insert (concat "%%Unknown format on RPL_LIST"
  5956.                      " message; please tell %s.")
  5957.                  irc-hacker)
  5958.              (irc-insert "%% \"%s\" (txt)." txt)
  5959.              (irc-insert "%% Function irc-parse-RPL-3xx, at 322."))
  5960.         (let* ((chan (substring txt (match-beginning 1) (match-end 1)))
  5961.            (count (substring txt (match-beginning 2) (match-end 2)))
  5962.            (topic (irc-nuke-whitespace
  5963.                (substring txt (match-end 0))))
  5964.            (tmpline (format "%s   %2s   "
  5965.                     (irc-format-channel chan)
  5966.                     count))
  5967.            (top (irc-clean-up-message topic))
  5968.            (line (concat tmpline top))
  5969.            (irc-msg-cont-used (make-string (length tmpline) ? )))
  5970.           (if (or t (> (string-to-int count) 10))
  5971.           (let ((irc-msg-cont-used (make-string
  5972.                         (string-match "-* *$"
  5973.                               irc-list-stroke)
  5974.                         ? )))
  5975.             (setq irc-list-stats (list (1+ (car irc-list-stats))
  5976.                            (+ (nth 1 irc-list-stats)
  5977.                           (string-to-int count))))
  5978.             (irc-insert (irc-clean-up-message line)))))))
  5979.      ((= num 323)                       ; RPL_LISTEND
  5980.       (let ((ch (car irc-list-stats))
  5981.         (us (nth 1 irc-list-stats)))
  5982.         (if (and (zerop us) (zerop ch))
  5983.         (irc-insert "%%No visible channels.")
  5984.           (irc-insert (concat "%s%s user%s on the %s channel%s"
  5985.                   " which happen to be visible%s")
  5986.               irc-msg-info-pre
  5987.               (if (zerop us) "No" (int-to-string us))
  5988.               (if (= 1 us) "" "s")
  5989.               (if (zerop ch) "No" (int-to-string ch))
  5990.               (if (= 1 ch) "" "s")
  5991.               irc-msg-info-post)))
  5992.       (setq irc-list-stats '(0 0)))
  5993.      ((= num 324)                 ; RPL_CHANNELMODEIS
  5994.       (let* ((lst (if (irc-server-has-channelname-in-msgs)
  5995.               (if (string-match
  5996.                    (concat "^ *: *\\([^ ]+\\) +324" ;origin
  5997.                        " +\\([^ ]+\\)"    ;nick
  5998.                        " +\\([^ ]+\\)"    ;channel
  5999.                        " +\\(\\+[^ ]*\\)" ;mode
  6000.                        "\\( [-+]?[^ ]+\\)? *$") ;extra
  6001.                    str)
  6002.                   (list (subfield str 1) ;origin
  6003.                     (subfield str 2) ;nick
  6004.                     (subfield str 3) ;channel
  6005.                     (subfield str 4) ;mode (at least a "+")
  6006.                     (subfield str 5)))    ;limit (optional)
  6007.             (if (string-match
  6008.                  (concat "^ *: *\\([^ ]+\\) +324 +"
  6009.                      "\\([^ ]+\\) +\\(+[^ ]*\\)"
  6010.                      "\\( +[0-9]+\\)? *$")
  6011.                  str)
  6012.                 (list (subfield str 1) ;origin
  6013.                   (subfield str 2) ;nick
  6014.                   nil ;channel not given
  6015.                   (subfield str 3) ;mode (at least "+")
  6016.                   (subfield str 4))))) ;limit (optional)
  6017.          (orig (nth 0 lst))
  6018.          (nick (nth 1 lst))
  6019.          (channel (nth 2 lst))
  6020.          (mode (if lst (irc-nuke-whitespace (concat (nth 3 lst)
  6021.                                 (nth 4 lst)))))
  6022.          (expl (if lst (irc-explain-channel-mode mode 'skip-dir)))
  6023.          (chntxt (concat (if channel "The channel " "The channels")
  6024.                  (if channel
  6025.                      (concat
  6026.                       channel
  6027.                       "'"
  6028.                       (if (not (= ?s (aref channel
  6029.                                (1- (length
  6030.                                 channel)))))
  6031.                       "s"))
  6032.                    "")
  6033.                  " "))
  6034.          (irc-msg-cont-used (make-string (+ (length chntxt)
  6035.                             (length irc-msg-info-pre))
  6036.                          ? )))
  6037.         (if (not lst)
  6038.         (progn
  6039.           (irc-insert (concat "%%Received RPL_CHANNELMODEIS reply"
  6040.                       " in unknown format:"))
  6041.           (irc-insert "%% \"%s\" (str)." str)
  6042.           (irc-insert "%% In irc-parse-RPL-3xx at 324. Please tell %s."
  6043.                   irc-hacker))
  6044.           (progn
  6045.         (if (irc-is-nickname orig)
  6046.             (irc-remember orig 'irc-nicknames))
  6047.         (if (and (irc-is-hostname orig)
  6048.              (not (string= (upcase origin) (upcase orig))))
  6049.             (irc-remember orig 'irc-servernames))
  6050.         (irc-remember nick 'irc-nicknames)
  6051.         (if (or t (string= (upcase orig) (upcase irc-server)))
  6052.             (irc-insert "%s%smode%s %s %s%s"
  6053.                 irc-msg-info-pre
  6054.                 chntxt 
  6055.                 (if (string-match " and " expl) "s" "")
  6056.                 (if (string-match " and " expl) "are" "is")
  6057.                 expl
  6058.                 irc-msg-info-post)
  6059.           ;; Ignore MODE replies from remote servers.
  6060.           )))))
  6061.      ((= num 325)
  6062.       (irc-insert "%s%s%s" irc-msg-info-pre txt irc-msg-info-post))
  6063.      ((= num 329)            ;undernet: time of channe; creation
  6064.       (cond ((string-match "\\([^ ]+\\) +\\([^ ]+\\)$" txt) ;Undernet
  6065.          ;;(let ((chan (subfield txt 1))
  6066.          ;;    (time (subfield txt 2)))
  6067.          ;;(irc-insert "%sNYI: channel %s was created at <%s>%s"
  6068.          ;;        irc-msg-info-pre
  6069.          ;;        chan
  6070.          ;;        time
  6071.          ;;        irc-msg-info-post))
  6072.          )
  6073.         (t (irc-insert "%% Bad 329 message, txt=\"%s\"." txt))))
  6074.      ((= num 331)                       ; RPL_NOTOPIC
  6075.       (if (string= parorg "")    ;Not when message from remote (old)
  6076.           (if (string-match (concat "^\\([^ ]+\\) +: *No +topic"
  6077.                     " +is +set *.? *$")
  6078.                 txt)
  6079.           (irc-insert "%sNo topic is set for channel %s%s"
  6080.                   irc-msg-info-pre
  6081.                   (subfield txt 1)
  6082.                   irc-msg-info-post)
  6083.         (irc-insert "%sNo topic is set%s"
  6084.                 irc-msg-info-pre
  6085.                 irc-msg-info-post))))
  6086.      ((= num 332)                       ; RPL_TOPIC
  6087.       (cond ((and (irc-server-has-end-of-whois)
  6088.               (string-match "^\\([^ ]+\\) *:" txt))
  6089.          (irc-insert "%sThe topic for channel %s is \"%s\"%s"
  6090.                  irc-msg-info-pre
  6091.                  (irc-clean-up-message (subfield txt 1))
  6092.                  (irc-clean-up-message
  6093.                   (irc-nuke-whitespace
  6094.                    (substring txt (match-end 0))))
  6095.                  irc-msg-info-post))
  6096.         ((string-match ":?" txt)
  6097.          (irc-insert "%sThe topic is \"%s\"%s"
  6098.                  irc-msg-info-pre
  6099.                  (irc-clean-up-message (substring txt
  6100.                                   (match-end 0)))
  6101.                  irc-msg-info-post))
  6102.         (t (irc-insert "%sThe topic is \"%s\"%s"
  6103.                    irc-msg-info-pre
  6104.                    (irc-clean-up-message txt)
  6105.                    irc-msg-info-post))))
  6106.      ((= num 333)
  6107.       (cond ((string-match "^\\([^ ]+\\) +\\([^ ]+\\) +\\([0-9]+\\)$" txt)
  6108.          (irc-insert "%sChannel %s created by %s%s"
  6109.                  irc-msg-info-pre
  6110.                  (subfield txt 1)
  6111.                  (subfield txt 2)
  6112.                  irc-msg-info-post))
  6113.         (t (irc-insert "%% Bad 333 message, txt=\"%s\"." txt))))
  6114.      ((= num 338)
  6115.       (irc-insert "%s%s%s" irc-msg-info-pre txt irc-msg-info-post))
  6116.      ((= num 339)
  6117.       (irc-insert "%s%s%s" irc-msg-info-pre txt irc-msg-info-post))
  6118.      ((= num 341)                       ; RPL_INVITING
  6119.       (string-match (concat "^:\\([^: ]+\\) +341 +[^: ]+ +\\([^: ]+\\) +"
  6120.                 "\\([^ ]+\\)")
  6121.             str)
  6122.       (let ((nick (subfield str 2))
  6123.         (channel (subfield str 3)))
  6124.         (irc-remember nick 'irc-nicknames)
  6125.         (irc-insert "%sYou are inviting user \"%s\" to channel %s%s"
  6126.             irc-msg-info-pre
  6127.             nick
  6128.             (irc-clean-up-message channel)
  6129.             irc-msg-info-post)))
  6130.      ((= num 351)                       ; RPL_VERSION | RPL_WHOREPLY
  6131.       (if (string-match "^\\([^: ]+\\) :?\\([^: ]+\\)" txt)
  6132.           (let ((s (substring txt (match-beginning 2) (match-end 2)))
  6133.             (v (substring txt (match-beginning 1) (match-end 1))))
  6134.         (if (not (string= (upcase origin) (upcase s)))
  6135.             (irc-remember s 'irc-servernames))
  6136.         (irc-insert (concat "%sIRC server %s is running version %s,"
  6137.                     " and the client you are using is %s%s")
  6138.                 irc-msg-info-pre
  6139.                 (upcase s)
  6140.                 v
  6141.                 irc-version
  6142.                 irc-msg-info-post))))
  6143.      ((= num 352)
  6144.       ;;(irc-parse-whoreply (format "WHOREPLY %s" txt))
  6145.       (cond ((= 0 irc-reply-count)
  6146.          (irc-insert irc-who-header)
  6147.          (irc-insert irc-who-stroke) 
  6148.          (setq irc-msg-cont-used (make-string
  6149.                       (string-match "-* *$"
  6150.                             irc-who-stroke)
  6151.                       ? ))))
  6152.       (setq irc-reply-count (1+ irc-reply-count))
  6153.       (if (string-match (concat "^\\([^ ]+\\) \\([^ ]+\\) \\([^ ]+\\\)"
  6154.                     " \\([^ ]+\\) \\([^ ]+\\) \\([^ ]+\\\)"
  6155.                     " :\\([0-9]+\\) \\(.+\\)$")
  6156.                 txt)
  6157.           (let* ((chan (subfield txt 1))
  6158.              (login (subfield txt 2))
  6159.              (client (subfield txt 3))
  6160.              (server (subfield txt 4))
  6161.              (nick (subfield txt 5))
  6162.              (mode (subfield txt 6))
  6163.              (unkn (subfield txt 7))
  6164.              (realname (subfield txt 8))
  6165.              (vsts (cond ((irc-recall nick 'irc-ignored-ppl) "IGNR")
  6166.                  ((string= "H"   mode) "    ") ;Norm
  6167.                  ((string= "G"   mode) "Away") ;Away
  6168.                  ((string= "H*"  mode) "Iopr") ;Iopr
  6169.                  ((string= "G*"  mode) "IoAw") ;IoAw
  6170.                  ((string= "H@"  mode) "Copr") ;Copr
  6171.                  ((string= "G@"  mode) "CoAw") ;CoAw
  6172.                  ((string= "H*@" mode) "ICop") ;ICop
  6173.                  ((string= "G*@" mode) "ICAw") ;ICAw
  6174.                  ((string= "S"   mode) "    ") ;Norm
  6175.                  (t mode))))
  6176.         (irc-insert "%-9s %-4s %-15s %s@%s \"%s\""
  6177.                 nick
  6178.                 vsts
  6179.                 chan
  6180.                 login
  6181.                 client
  6182.                 realname))))
  6183.      ((= num 353)                       ; RPL_NAMREPLY
  6184.       (if (or (string-match "^@ +\\([#&][^ ]+\\) +:?" txt)
  6185.           (string-match "^ *[=*] +\\([^ ]+\\) *:" txt))
  6186.           (let ((c (subfield txt 1))
  6187.             (n (substring txt (match-end 0))))
  6188.         (irc-parse-namreply
  6189.          (format "NAMREPLY placeholder %s %s" c n)))
  6190.         (irc-parse-namreply (format "NAMREPLY %s" txt))))
  6191.      ((= num 354)                       ; RPL_ENDOFNAMES
  6192.       (irc-insert "Names 354: %s" txt))
  6193.      ((= num 361)                       ; RPL_KILLDONE
  6194.       (string-match "^[^: ]+" txt)
  6195.       (irc-insert "%sYou have removed \"%s\" from IRC (/killed)%s"
  6196.               irc-msg-info-pre
  6197.               (substring txt (match-beginning 0) (match-end 0))
  6198.               irc-msg-info-post))
  6199.      ((= num 364)                 ; RPL_LINKS
  6200.       (if (not (or (string-match "^\\([^ ]*\\) \\([^ ]*\\) *:" txt)
  6201.                (string-match "^\\([^ ]*\\) *:" txt)))
  6202.           (progn
  6203.         (irc-insert "%%Error in parsing RPL 364, please tell %s:"
  6204.                 irc-hacker)
  6205.         (irc-insert "%% \"%s\" (txt)." txt)
  6206.         (irc-insert "%% In function irc-parse-RPL-3xx, at 364."))
  6207.         (let ((s (upcase (subfield txt 1)))
  6208.           (f2 (subfield txt 2))
  6209.           (info (irc-nuke-whitespace
  6210.              (irc-clean-up-message
  6211.               (substring txt (match-end 0))))))
  6212.           (setq irc-reply-count (1+ irc-reply-count))
  6213.           (let ((diff (irc-time-diff (irc-current-time)
  6214.                      irc-reply-count-time)))
  6215.         (cond ((or (> (nth 1 diff) 5) ;At least 5 seconds since last
  6216.                (> (nth 0 diff) 0)) ; display?
  6217.                (setq irc-reply-count-time (irc-current-time))
  6218.                (message (format " %d server%s ..."
  6219.                     irc-reply-count
  6220.                     (if (= 1 irc-reply-count)
  6221.                         ""
  6222.                       "s"))))))
  6223.           (irc-remember (format "Server %s%s: %s"
  6224.                     s
  6225.                     (if (string= "" f2)
  6226.                     ""
  6227.                       (format " (to %s)" (upcase f2)))
  6228.                     info) 
  6229.                 'irc-linksinfo)
  6230.           (if (not (string= (upcase origin) (upcase s)))
  6231.           (irc-remember s 'irc-servernames)))))
  6232.      ((= num 365)                 ; RPL_ENDOFLINKS
  6233.       (setq irc-reply-count 0)
  6234.       (message "")
  6235.       (irc-insert irc-links-header)
  6236.       (irc-insert irc-links-stroke)
  6237.       (set-buffer-modified-p (buffer-modified-p))
  6238.       (irc-recall-all-and-display 'irc-linksinfo
  6239.                       (progn (string-match "^[^: ]* ."
  6240.                                irc-links-header)
  6241.                          (match-end 0))
  6242.                       "servers"
  6243.                       "server") 
  6244.       (irc-forget-all 'irc-linksinfo))
  6245.      ((= num 366)                 ; RPL_NAMES_END
  6246.       (setq irc-reply-count 0)
  6247.       (message "")
  6248.       (if (irc-terminal-is-slow)
  6249.           (let ((lincnt 0)
  6250.             (usrcnt 0)
  6251.             (adjust 0)
  6252.             (w (irc-recall-all 'irc-namtree))
  6253.             (irc-msg-cont-used irc-names-cont-msg))
  6254.         (irc-insert "Name of channel  Users  Nicknames")
  6255.         (irc-insert "---------------  -----  ---------")
  6256.         (set-buffer-modified-p (buffer-modified-p))
  6257.         (while w
  6258.           (irc-insert "%s" (car w))
  6259.           (let* ((pair (if (string-match (concat "^ *\\([^ ]+\\) +"
  6260.                              "\\([0-9]+\\)")
  6261.                          (car w))
  6262.                    (cons (subfield (car w) 1)
  6263.                      (subfield (car w) 2))
  6264.                  (cons "" "0")))
  6265.              (ldiff (if (string= "PRIVATE" (upcase (car pair)))
  6266.                     1
  6267.                   0))
  6268.              (udiff (string-to-int (cdr pair))))
  6269.             (setq usrcnt (+ usrcnt udiff)
  6270.               lincnt (1+ lincnt)
  6271.               adjust (+ adjust ldiff)
  6272.               w (cdr w))))
  6273.         (let ((adjusted (- lincnt adjust)))
  6274.           (irc-insert (concat "%s%d visible user%s on %d visible"
  6275.                       " channel%s or on some private"
  6276.                       " channel%s")
  6277.                   irc-msg-info-pre
  6278.                   usrcnt
  6279.                   (if (= usrcnt 1) "" "s")
  6280.                   adjusted
  6281.                   (if (= adjusted 1) "" "s")
  6282.                   irc-msg-info-post)
  6283.           (irc-insert ""))
  6284.         (irc-forget-all 'irc-namtree))
  6285.         ;; Else fast terminal.
  6286.         (irc-insert "%sEnd of NAMES list%s"
  6287.             irc-msg-info-pre
  6288.             irc-msg-info-post)))
  6289.      ((= num 367)                       ; RPL_BANLIST
  6290.       (cond
  6291.        ((string-match "^\\([^ ]+\\) +\\([^ ]+\\) +\\([^ ]+\\) +\\(.+\\)$"
  6292.               txt)
  6293.         (let ((chan (subfield txt 1))
  6294.           (banned (subfield txt 2))
  6295.           (banner (subfield txt 3))
  6296.           (time (subfield txt 4)))
  6297.           (irc-insert "%sUser(s) \"%s\" are banned from %s by %s at %s%s"
  6298.               irc-msg-info-pre
  6299.               banned
  6300.               chan
  6301.               banner
  6302.               time
  6303.               irc-msg-info-post)))
  6304.        ((string-match "^\\([^ ]+\\) +\\(.+\\)$" txt)
  6305.         (let ((channel (subfield txt 1))
  6306.           (user (subfield txt 2)))
  6307.           (irc-insert (concat "%sUser(s) matching \"%s\""
  6308.                   " are banned from %s%s")
  6309.               irc-msg-info-pre user channel irc-msg-info-post)))
  6310.        (t (irc-insert "%%Unknown type 367 reply seen in irc-parse-RPL-3xx:")
  6311.           (irc-insert "%% \"%s\" (txt)" txt)
  6312.           (irc-insert "%% Please tell %s, it might be a bug."
  6313.               irc-hacker))))
  6314.      ((= num 368)                       ; RPL_BANLISTEND 
  6315.       (irc-insert (concat "%sEnd of list of banned users (who are"
  6316.                   " prohibited to join)%s")
  6317.               irc-msg-info-pre irc-msg-info-post))
  6318.      ((= num 369)                 ; RPL_ENDOFWHOWAS
  6319.       )
  6320.      ((= num 371)                       ; RPL_INFO
  6321.       (irc-insert "* %s" txt))
  6322.      ((= num 372)                       ; RPL_MOTD
  6323.       (cond
  6324.        ((string-match (concat "^ *: *\\([^: ]+\\)? +372 *\\([^: ]+\\)?"
  6325.                   " *: *Message-of-today +not +found +"
  6326.                   "in +server +\\([^: ]+\\) *$")
  6327.               str)
  6328.         (let* ((f (substring str (match-beginning 1) (match-end 1)))
  6329.            (frm (if (string= (upcase f) (upcase irc-server)) "" f))
  6330.            (at (substring str (match-beginning 3)
  6331.                   (match-end 3))))
  6332.           (if (not (string= (upcase origin) (upcase frm)))
  6333.           (irc-remember frm 'irc-servernames))
  6334.           (if (not (string= (upcase origin) (upcase at)))
  6335.           (irc-remember at 'irc-servernames))
  6336.           (irc-insert "%%%sNo message of the day at server %s."
  6337.               (if (string= frm "")
  6338.                   ""
  6339.                 (concat "(" frm ") "))
  6340.               (upcase at))))
  6341.        ((string-match (concat "^ *: *\\([^: ]+\\)? +372 *"
  6342.                   "\\([^: ]+\\)? *:? *"
  6343.                   "\\(start\\|end\\)?"
  6344.                   "\\( +at +server +\\)?"
  6345.                   "\\([A-Za-z.-.---]*\\|.*\\)"
  6346.                   "\\( *:\\)? *$")
  6347.               str)
  6348.         (let* ((from-1 (irc-non-num-to-0 (match-beginning 1)))
  6349.            (to-1 (irc-non-num-to-0 (match-end 1)))
  6350.            (from-2 (irc-non-num-to-0 (match-beginning 2)))
  6351.            (to-2 (irc-non-num-to-0 (match-end 2)))
  6352.            (from-3 (irc-non-num-to-0 (match-beginning 3)))
  6353.            (to-3 (irc-non-num-to-0 (match-end 3)))
  6354.            (from-4 (irc-non-num-to-0 (match-beginning 4)))
  6355.            (to-4 (irc-non-num-to-0 (match-end 4)))
  6356.            (from-5 (irc-non-num-to-0 (match-beginning 5)))
  6357.            (to-5 (irc-non-num-to-0 (match-end 5)))
  6358.            (from-6 (irc-non-num-to-0 (match-beginning 6)))
  6359.            (to-6 (irc-non-num-to-0 (match-end 6)))
  6360.            (server (substring str from-1 to-1))
  6361.            (user (substring str from-2 to-2))
  6362.            (direction (substring str from-3 to-3))
  6363.            (token (substring str from-4 to-4))
  6364.            (message (substring str from-5 to-5))
  6365.            (colon (substring str from-6 to-6)))
  6366.           (if (and (not (string= "" server))
  6367.                (not (string= (upcase origin) (upcase server))))
  6368.           (irc-remember server 'irc-servernames))
  6369.           (if (not (string= "" user))
  6370.           (irc-remember user 'irc-nicknames))
  6371.           (cond ((and (or (string= (downcase direction) "start")
  6372.                   (string= (downcase direction) "end"))
  6373.               (string-match "^ *at +server *$" token)
  6374.               (not (string= "" message))
  6375.               (string-match "^ *:$" colon)
  6376.               (not (string= (upcase origin)
  6377.                     (upcase message))))
  6378.              (irc-remember message 'irc-servernames))
  6379.             ((string-match "[^: ]" message)
  6380.              (irc-insert ">>> %s" (concat direction
  6381.                           token
  6382.                           message
  6383.                           colon))))))
  6384.        (t (irc-insert (concat "%%Unkown format on MOTD reply,"
  6385.                   " in function irc-parse-RPL-3xx,"
  6386.                   " num 372"))
  6387.           (irc-insert "%% \"%s\"." str))))
  6388. ;;;       ((= num 373)                       ; RPL_VERSION
  6389. ;;;        (irc-insert "DEBUG: RPL373 txt=\"%s\"." txt))
  6390.      ((= num 374)            ;RPL_INFO_END
  6391.       (irc-insert "%sEnd of information about this IRC server%s"
  6392.               irc-msg-info-pre irc-msg-info-post))
  6393.      ((= num 375)            ;RPL, start of MOTD
  6394.       (irc-insert ">>> %s" txt))
  6395.      ((= num 376)            ;RPL, end of MOTD
  6396.       (irc-insert "%sEnd of MOTD at %s%s"
  6397.               irc-msg-info-pre origin irc-msg-info-post))
  6398.      ((= num 377)
  6399.       (irc-insert ">>> %s" txt))
  6400.      ((= num 381)                       ; RPL_YOUREOPER
  6401.       (setq irc-operator " IOPR")
  6402.       (set-buffer-modified-p (buffer-modified-p))
  6403.       (irc-insert "%sOperator status for %s ENABLED%s"
  6404.               irc-msg-info-pre
  6405.               irc-nick-used
  6406.               irc-msg-info-post))
  6407.      ((= num 382)                       ; RPL_REHASHING
  6408.       (irc-insert "%sReread local ircd configuration information%s"
  6409.               irc-msg-info-pre
  6410.               irc-msg-info-post))
  6411. ;;;       ((= num 383)                       ; RPL_YOURESERVICE / Kim
  6412. ;;;        (irc-insert "DEBUG: RPL383, txt=\"%s\"." txt))
  6413. ;;;       ((= num 384)                       ; RPL_MYPORTIS / Kim
  6414. ;;;        (irc-insert "DEBUG: RPL384 txt=\"%s\"." txt))
  6415. ;;;       ((= num 385)            ; deop reply?
  6416. ;;;        (irc-insert "DEBUG: RPL385 txt=\"%s\"." txt))
  6417.      ((= num 391)                       ; RPL_TIME
  6418.       (setq irc-last-time (irc-get-time))
  6419.       (let* ((pair
  6420.           (if (string-match (concat
  6421.                      "^ *\\([^ :]+\\) *: *" ;srvr
  6422.                      "\\([A-Za-z][A-Za-z][A-Za-z]\\)"
  6423.                      "[A-Za-z]*day" ;weekday
  6424.                      " +\\(...\\)[^: ]* +" ;month
  6425.                      "\\([0-9]+\\) +"     ;monthday
  6426.                      "\\([0-9]+\\) +-* *") ;year
  6427.                     txt)
  6428.               (cons (subfield txt 1) 
  6429.                 (format "%s %s %s %s %s"
  6430.                     (substring txt (match-end 0)) ;clock
  6431.                     (subfield txt 2) ;weekday
  6432.                     (subfield txt 4) ;monthday
  6433.                     (subfield txt 3) ;month
  6434.                     (subfield txt 5))) ;year
  6435.             (progn (string-match "^\\([^: ]+\\) :" txt)
  6436.                (cons (subfield txt 1)
  6437.                  (irc-nuke-whitespace
  6438.                   (substring txt (match-end 0)))))))
  6439.          (server (car pair))
  6440.          (server (if (string= "" server) origin server))
  6441.          (date (irc-nuke-whitespace (cdr pair))))
  6442.         (irc-insert "%sLocal time at %s is %s%s%s"
  6443. ;;;             "%s%s%s local time is %s%s%s"
  6444.             irc-msg-info-pre
  6445.             (upcase server)
  6446. ;;;             (if (= ?S (aref (upcase server) (1- (length server))))
  6447. ;;;                 "'"
  6448. ;;;                 "'s")
  6449.             date
  6450.             (if (string= "0" irc-channel)
  6451.                 ""
  6452.               (concat " /" irc-channel))
  6453.             irc-msg-info-post)))
  6454.      ((or (= num 392)
  6455.           (= num 393))
  6456.       (irc-parse-notice (format ":%s NOTICE %s :%s"
  6457.                     origin user txt)))
  6458.      ((= num 394)
  6459.       (irc-insert "%sEnd of USERS at %s%s"
  6460.               irc-msg-info-pre origin irc-msg-info-post))
  6461.      ((= num 395)
  6462.       (irc-insert "%%No one logged in on Internet host %s" origin))
  6463.      (t                                 ; default
  6464.       (irc-insert (concat "%%Unrecognized numeric RPL 3xx message; "
  6465.                   "please tell %s:")
  6466.               irc-hacker)
  6467.       (irc-insert "%% str=\"%s\"." str)
  6468.       (irc-insert "%% Function irc-parse-RPL-3xx."))))
  6469.     ;; else
  6470.     (irc-insert (concat "%%Unrecognized nonnumeric RPL 3xx message follows; "
  6471.             "please tell %s:")
  6472.         irc-hacker)
  6473.     (irc-insert "%% \"%s\"." str)
  6474.     (irc-insert "%% Function irc-parse-RPL-3xx."))
  6475.   nil)
  6476.  
  6477.  
  6478. (defun irc-parse-topic (str)
  6479.   "Examine a TOPIC message from the IRC server.
  6480. TOPIC is sent to all of the users on a channel when someone changes the
  6481. topic of the channel.  Secret channels can not have the topic set.  TOPIC
  6482. messages are displayed as long as 'topic' is in irc-events, even if the user
  6483. changing the topic is being ignored.
  6484.  
  6485. This function returns t if a signal should be issued for the 'topic' event,
  6486. nil otherwise."
  6487.   (if (not (string-match "^:\\([^: ]+\\) +TOPIC +\\([^ ]*\\) *:" str))
  6488.       (progn (irc-insert "%%Unknown TOPIC command in irc-parse-topic:")
  6489.          (irc-insert "%% \"%s\"." str)
  6490.          (irc-insert "%% Please tell %s, it might be a bug." irc-hacker))
  6491.     (let* ((user (subfield str 1))
  6492.        (chnl (subfield str 2))
  6493.        (topic (substring str (match-end 0)))
  6494.        (old-chnl (let ((l (irc-recall-all 'irc-subscribed-channels)))
  6495.                (while (not (atom l))
  6496.              (setq l (if (irc-is-multijoinable-channel (car l))
  6497.                      (cdr l)
  6498.                    (car l))))
  6499.                (if (listp l) "" l)))
  6500.        (channel (if (string< "" chnl) chnl old-chnl)))
  6501.       (irc-remember user 'irc-nicknames)
  6502.       (irc-remember channel 'irc-subscribed-channels)
  6503.       (irc-insert (concat "%s%s has changed the topic of channel %s to \""
  6504.               (irc-clean-up-message topic)
  6505.               "\"%s")
  6506.           irc-msg-info-pre
  6507.           user
  6508.           channel
  6509.           irc-msg-info-post)
  6510.       (if (memq 'topic irc-events)
  6511.       (irc-signal user 'topic)))))
  6512.  
  6513.  
  6514. (defun irc-parse-wall (str)
  6515.   "Examine a WALL message from the IRC server.
  6516. WALL is sent by IRC operators to everyone on IRC.  A WALL message will
  6517. always be displayed even if the sender is being ignored.
  6518.  
  6519. This function returns t if a signal should be issued for the \"wall\" event,
  6520. nil otherwise."
  6521.   (if (not (string-match "^:? *\\([^: ]*\\) +WALL +:" str))
  6522.       (progn (irc-insert (concat "%%Internal error, function irc-parse-wall"
  6523.                  " called with a non-WALL message:"))
  6524.          (irc-insert "%% \"%s\"." str)
  6525.          (irc-insert "%%Please tell %s about it." irc-hacker)
  6526.          (irc-signal "<internal-error in irc-parse-wall>" 'wall))
  6527.       (let ((user (substring str (match-beginning 1) (match-end 1)))
  6528.         (msg (substring str (match-end 0))))
  6529.     (irc-remember user 'irc-nicknames)
  6530.     (irc-insert (concat (format irc-msg-wall
  6531.                     (concat " (" (irc-get-time) ") ")
  6532.                     user)
  6533.                 msg))
  6534.     (irc-signal user 'wall))))
  6535.  
  6536.  
  6537. (defun irc-parse-wallops (str)
  6538.   "Examine a WALLOPS message from the IRC server.
  6539. WALLOPS are sent by any user to all enabled operators on IRC. A WALLOPS will
  6540. allways be displayed, even if the sender is being ignores.
  6541.  
  6542. This function returns t if a signal should be issued for the \"wall\" event,
  6543. nil otherwise."
  6544.   (if (not (string-match "^: *\\([^: ]*\\) +WALLOPS +:" str))
  6545.       (progn (irc-insert (concat "%%Internal error, function irc-parse-wallops"
  6546.                  " called with a non-WALLOPS message:"))
  6547.          (irc-insert "%% \"%s\"." str)
  6548.          (irc-insert "%%Please tell %s about it." irc-hacker)
  6549.          (irc-signal "<internal-error in irc-parse-wallops>" 'wall))
  6550.       (let* ((sender (substring str (match-beginning 1) (match-end 1)))
  6551.          (msg (substring str (match-end 0))))
  6552.     (cond ((string-match (concat "^Remote 'CONNECT \\([^ ]+\\) +"
  6553.                      "\\([0-9]*\\)' from \\([^ ]+\\) *$")
  6554.                  msg)
  6555.            (let ((nsrv (substring msg (match-beginning 1) (match-end 1)))
  6556.              (port (substring msg (match-beginning 2) (match-end 2)))
  6557.              (user (substring msg (match-beginning 3) (match-end 3))))
  6558.          (cond ((irc-is-nickname user)
  6559.             (irc-remember user 'irc-nicknames))
  6560.                ((irc-is-hostname user)
  6561.             (irc-remember user 'irc-servernames)))
  6562.          (irc-insert (concat "%sTrying to establish a serverlink from"
  6563.                      " %s to %s on port %s on remote command"
  6564.                      " by user \"%s\"%s")
  6565.                  irc-msg-info-pre
  6566.                  (upcase sender)
  6567.                  (upcase nsrv)
  6568.                  port
  6569.                  user
  6570.                  irc-msg-info-post)))
  6571.           ((string-match (concat "Received SQUIT \\([^ ]+\\) +from"
  6572.                      " +\\(.+\\) *$")
  6573.                  msg)
  6574.            (let ((oded (substring msg (match-beginning 1) (match-end 1)))
  6575.              (orig (substring msg (match-beginning 2) (match-end 2))))
  6576.          (cond ((irc-is-nickname orig)
  6577.             (irc-remember orig 'irc-nicknames))
  6578.                ((irc-is-hostname orig)
  6579.             (irc-remember orig 'irc-servernames)))
  6580.          (irc-insert (concat "%sClosing the serverlink from %s to"
  6581.                      " server %s, by order of %s%s")
  6582.                  irc-msg-info-pre
  6583.                  (upcase sender)
  6584.                  (upcase oded) ;OD'ed server
  6585.                  (upcase orig)
  6586.                  irc-msg-info-post)))
  6587.           (t (let* ((head (format "%s%s" (concat
  6588.                           (format (format irc-msg-priv 0) 
  6589.                               (concat " ("
  6590.                                   (irc-get-time)
  6591.                                   ") ")
  6592.                               (concat sender
  6593.                                   " (WALLOPS)")))))
  6594.             (irc-msg-cont-used (make-string
  6595.                         (min
  6596.                          (length head)
  6597.                          (/ (window-width
  6598.                          (get-buffer-window
  6599.                           (current-buffer)))
  6600.                         2))
  6601.                         ? )))
  6602.            (cond ((and (irc-is-hostname sender)
  6603.                    (not (irc-is-nickname sender)))
  6604.               (irc-remember sender 'irc-servernames))
  6605.              ((irc-is-nickname sender)
  6606.               (irc-remember sender 'irc-nicknames)))
  6607.            (irc-insert (concat head (irc-clean-up-message msg))))))
  6608.     (if (irc-is-nickname sender)
  6609.         (irc-signal sender 'wall)
  6610.         (irc-later-execute-lusers)))))
  6611.  
  6612.  
  6613. (defun irc-parse-whoreply (str)
  6614.   "OBSELETE FUNCTION
  6615.  
  6616. Examine a WHOREPLY message from the IRC server.
  6617. The message is formatted into a line that is more easily understood than
  6618. the raw data.  
  6619. The status of the users is shown as a four letter word (:-) according to
  6620. the combination of their attributes. The possible attributes being
  6621. an IRC operator, being a channel operator and being marked away.
  6622.  
  6623.                                           Status field
  6624. A normal user having no attributes set:     (blank)
  6625. A normal user marked as being away:          Away
  6626. An IRC operator with no other attribues:     Iopr
  6627. An IRC operator marked as being away:        IoAw
  6628. A channel operator with no other attributes: Copr
  6629. A channel operator marked as being away:     CoAw
  6630. User being both IRC- and channel operator:   ICop
  6631. As above but also marked as being away:      ICAw
  6632.  
  6633. Being ignored takes precedence over all
  6634. other attributes, always shown as:           IGNR
  6635.  
  6636.  
  6637. No signals are issued for lines from the WHOREPLY."
  6638.   (string-match "^WHOREPLY +" str)
  6639.   (setq str (substring str (match-end 0)))
  6640.   (let ((is-header (or (string-match (concat "^\\* +User +Host +Server"
  6641.                          " +Nickname +S +: *Name *$")
  6642.                      str)
  6643.                (string-match (concat "^Channel +User +Host +Server"
  6644.                          " +Nickname +S +: *Name *$")
  6645.                      str)))
  6646.     (split))          ; make this a list of strings of each data item.
  6647.     ;; the elements of 'split' are:
  6648.     ;; 0 - full name (with possible hop count)
  6649.     ;; 1 - status
  6650.     ;; 2 - nickname
  6651.     ;; 3 - hostname of server
  6652.     ;; 4 - hostname of client
  6653.     ;; 5 - login name
  6654.     ;; 6 - channel
  6655.     (if (or (string-match (concat "^\\([^ ]+\\) +\\([^ ]+\\) +\\([^ ]+\\)"
  6656.                   " +\\([^ ]+\\) +\\([^ ]+\\) +\\([^ ]+\\)"
  6657.                   " +:\\([0-9]+\\)? *\\(.+\\)$")
  6658.               str))
  6659.     (let* ((channel (subfield str 1))
  6660.            (x-login-name (subfield str 2))
  6661.            (x-client-host (subfield str 3))
  6662.            (x-server-host (subfield str 4))
  6663.            (x-nickname (subfield str 5))
  6664.            (x-status (subfield str 6))
  6665.            (hop-count (subfield str 7))
  6666.            (x-full-name (subfield str 8))
  6667.            (name-col (string-match "-* *$" irc-who-stroke)) ;Last stroke
  6668.            (chan-col (string-match "-* +-+ *$" irc-who-stroke)) ;2nd last
  6669.            )
  6670.       (if (not (string= x-status "S")) ;Header?
  6671.           (progn
  6672.         ;; if it isn't the bogus header
  6673.         (irc-remember x-nickname 'irc-nicknames) ; add nick
  6674.         (if (and (not is-header)
  6675.              (irc-terminal-is-slow)
  6676.              (irc-server-has-end-of-who)
  6677.              (irc-nothing-remembered-p 'irc-whotree))
  6678.             (let ((irc-msg-cont-used
  6679.                (make-string name-col ? )))
  6680.               (irc-insert irc-who-header)
  6681.               (irc-insert irc-who-stroke)
  6682.               ;;(sit-for 0)
  6683.               (set-buffer-modified-p (buffer-modified-p))))
  6684.         (irc-remember x-server-host 'irc-servernames) ; hostnames.
  6685.         (irc-remember x-client-host 'irc-servernames)))
  6686.       (let* ((full-name (irc-clean-up-message
  6687.                  x-full-name))
  6688.          (nick-pad (make-string (max 0 (- (1- 10) (length x-nickname)))
  6689.                     ? ))
  6690.          (vsts (cond ((irc-recall x-nickname 'irc-ignored-ppl) "IGNR")
  6691.                  ((string= "H"   x-status) "    ") ;Norm
  6692.                  ((string= "G"   x-status) "Away") ;Away
  6693.                  ((string= "H*"  x-status) "Iopr") ;Iopr
  6694.                  ((string= "G*"  x-status) "IoAw") ;IoAw
  6695.                  ((string= "H@"  x-status) "Copr") ;Copr
  6696.                  ((string= "G@"  x-status) "CoAw") ;CoAw
  6697.                  ((string= "H*@" x-status) "ICop") ;ICop
  6698.                  ((string= "G*@" x-status) "ICAw") ;ICAw
  6699.                  ((string= "S"   x-status) "    ") ;Norm
  6700.                  (t (concat "\"" x-status "\""))))
  6701.          (vchnl (irc-format-channel
  6702.              (cond ((string= "-1" channel) "-")
  6703.                    ((string= "0" channel) "")
  6704.                    ((string= "*" channel) "")
  6705.                    (t channel))))
  6706.          (vusr (irc-clean-up-message x-login-name))
  6707.          (vclt (irc-clean-up-message x-client-host))
  6708.          (vsrv (irc-clean-up-message x-server-host))
  6709.           (line (format "%s%s %s %s <%s> %s@%s \"%s\" SERVER=%s"
  6710.                    x-nickname nick-pad vsts vchnl hop-count vusr
  6711.                    vclt full-name vsrv))
  6712.           (line (format "%s%s %s %s %s@%s \"%s\""
  6713.                    x-nickname nick-pad vsts vchnl vusr
  6714.                    vclt full-name))
  6715. ;         (line (format "%s%s %s %s@%s \"%s\""
  6716. ;                   x-nickname nick-pad vsts vusr vclt full-name))
  6717.          (irc-msg-cont-used (make-string 31 ? )))
  6718.         (if (and (irc-terminal-is-slow) (irc-server-has-end-of-who))
  6719.         (if (not is-header)
  6720.             (progn
  6721.               (setq irc-reply-count (1+ irc-reply-count))
  6722.               (let ((diff (irc-time-diff (irc-current-time)
  6723.                          irc-reply-count-time)))
  6724.             (cond ((or (> (nth 1 diff) 5) ;At least 5 seconds since
  6725.                    (> (nth 0 diff) 0)) ; last display?
  6726.                    (setq irc-reply-count-time (irc-current-time))
  6727.                    (message (format " %d nick%s ..."
  6728.                         irc-reply-count
  6729.                         (if (= 1 irc-reply-count)
  6730.                             ""
  6731.                             "s"))))))
  6732.               (irc-remember line 'irc-whotree)))
  6733.         (if is-header        ;No RPL_ENDOFWHO
  6734.             (let ((irc-msg-cont-used
  6735.                (make-string (string-match "-* *$" irc-who-stroke)
  6736.                     ? )))
  6737.               (irc-insert irc-who-header)
  6738.               (irc-insert irc-who-stroke))
  6739.             (irc-insert "%s" (irc-clean-up-message line))))))
  6740.     (irc-insert "%%Unkown WHOREPLY line: \"%s\"." str)))
  6741.     nil)
  6742.  
  6743.  
  6744. (defun irc-explain-channel-mode (mode &optional skip-direction)
  6745.   "Front end to irc-explain-mode."
  6746.   (irc-explain-mode mode 'channel skip-direction))
  6747.  
  6748.  
  6749. (defun irc-explain-user-mode (mode &optional skip-direction)
  6750.   "Front end to irc-explain-mode."
  6751.   (irc-explain-mode mode 'user skip-direction))
  6752.   
  6753.  
  6754. (defun irc-explain-mode (mode type &optional skip-direction)
  6755.   "Translate a channels MODE code into plain text. Use optional FLAG when
  6756. addition / removal information shouldn't be added."
  6757.   (let* ((known-modes '(((?a 0 "anonymous <A>")
  6758.              (?b 1 "ban (from channel) <B>" " of " " of ")
  6759.              (?i 0 "invite only <I>")
  6760.              (?k 1 "channel key <K> ")
  6761.              (?l 1 "limit number of users on channel <L>" " to ")
  6762.              (?m 0 "moderated <M>")
  6763.              (?n 0 "disallow nonlisteners to talk to channel <N>")
  6764.              (?o 1 "channel operator privilege <O>"
  6765.                    " for " " for ")
  6766.              (?p 0 "private <P>")
  6767.              (?s 0 "secret <S>")
  6768.              (?t 0 "topic lock <T>")
  6769.              (?v 1 "voice capability <V>" " to " " to "))
  6770.             .
  6771.             ((?i 0 "invisibility <I>")
  6772.              (?o 0 "IRC-operator <O>")
  6773.              (?s 0
  6774.               "subscription to local server status messages <S>")
  6775.              (?w 0 "subscription to WALLOPS <W>"))))
  6776.      (modes (cond ((eq type 'channel) (car known-modes))
  6777.               ((eq type 'user) (cdr known-modes))
  6778.               (t nil)))
  6779.      (cmds (if (string-match " +" mode) 
  6780.            (substring mode 0 (match-beginning 0))
  6781.            mode))
  6782.      (args (substring mode (length cmds)))
  6783.      (dir "added ")
  6784.      (argl ())
  6785.      (expl ""))
  6786.     (while (string-match "^ *\\([^: ]+\\)" args)
  6787.       (setq argl (append argl (list (subfield args 1)))
  6788.         args (substring args (match-end 1))))
  6789.     (while (not (string= cmds ""))
  6790.       (let ((c (string-to-char (substring cmds 0 1))))
  6791.     (cond ((= ?+ c) (setq dir "added "))
  6792.           ((= ?- c) (setq dir "removed "))
  6793.           (t (let ((p (assoc c modes)))
  6794.            (setq expl (concat expl
  6795.                       ", "
  6796.                       (if (not skip-direction) dir)
  6797.                       (if p
  6798.                       (nth 2 p)
  6799.                       (concat irc-msg-info-pre
  6800.                           "UNKNOWN '"
  6801.                           (char-to-string c)
  6802.                           "'"
  6803.                           irc-msg-info-post))
  6804.                       (cond ((and (string= dir "added ")
  6805.                           (nth 3 p))
  6806.                          (nth 3 p))
  6807.                         ((and (string= dir "removed ")
  6808.                           (nth 4 p))
  6809.                          (nth 4 p))
  6810.                         (t ""))
  6811.                       (let ((n (or (nth 1 p) 0))
  6812.                         (s ""))
  6813.                     (while (and (> n 0) (car argl))
  6814.                       (setq s (concat s (car argl))
  6815.                         argl (cdr argl)
  6816.                         n (1- n)))
  6817.                     s)))))))
  6818.       (setq cmds (substring cmds 1)))
  6819.     (concat (cond ((string-match "^\\(, *\\)[\000-\377]*\\(,\\) [^,]+" expl)
  6820.            (concat (substring expl (match-end 1) (match-beginning 2))
  6821.                " and"
  6822.                (substring expl (match-end 2))))
  6823.           ((string-match "^\\(, *\\)" expl)
  6824.            (substring expl (match-end 1)))
  6825.           ((string= expl "") (if skip-direction "normal" "none"))
  6826.           (t expl))
  6827.         (if (and (= (length argl) 1)
  6828.              (string-match "^[0-9]+$" (car argl)))
  6829.         (concat "; user limit is " (car argl))
  6830.         (progn (if (not (equal argl ()))
  6831.                (progn (irc-insert (concat "%%Warning: parts left"
  6832.                               " unparsed in function"
  6833.                               " irc-explain-mode."))
  6834.                   (irc-insert "%% \"%s\" (mode)." mode)
  6835.                   (irc-insert (concat "%% Please tell %s, it"
  6836.                               " might be a bug.")
  6837.                           irc-hacker))
  6838.                ""))))))
  6839.  
  6840. ;;;(defun irc-explain-who-mode (mode)
  6841. ;;;  ""
  6842. ;;;   (cond ((irc-recall x-nickname 'irc-ignored-ppl) "IGNR")
  6843. ;;;                 ((string= "H"   mode) "    ") ;Norm
  6844. ;;;                 ((string= "G"   mode) "Away") ;Away
  6845. ;;;                 ((string= "H*"  mode) "Iopr") ;Iopr
  6846. ;;;                 ((string= "G*"  mode) "IoAw") ;IoAw
  6847. ;;;                 ((string= "H@"  mode) "Copr") ;Copr
  6848. ;;;                 ((string= "G@"  mode) "CoAw") ;CoAw
  6849. ;;;                 ((string= "H*@" mode) "ICop") ;ICop
  6850. ;;;                 ((string= "G*@" mode) "ICAw") ;ICAw
  6851. ;;;                 ((string= "S"   mode) "    ") ;Norm
  6852. ;;;                 (t (concat "\"" mode "\""))))
  6853.  
  6854. (defun irc-ctcp-dequote (str)
  6855.   "Return STRING with quoted characters changed into the unquoted equivalents."
  6856.   (let ((new ""))
  6857.     (while (string-match "\\\\" str)    ;Get to next backslash, if any
  6858.       (let ((pos (match-beginning 0)))
  6859.     (if (>= (- (length str) pos) 2)
  6860.         (setq new (concat new
  6861.                   (substring str 0 pos)
  6862.                   (irc-ctcp-dequote-char (aref str (1+ pos))))
  6863.           str (substring str (+ 2 pos)))
  6864.         (irc-insert (concat "%%Received badly quoted CTCP string, ignored"
  6865.                 " superfluous backslash."))
  6866.         (setq new (concat new (substring str 0 pos))
  6867.           str (substring str (1+ pos))))))
  6868.     (concat new str)))
  6869.  
  6870.  
  6871. (defun irc-ctcp-dequote-char (char)
  6872.   "Map a two character STRING to it's corresponding character."
  6873.   (char-to-string (cond ((= char ?a) ?\001)
  6874.             ((= char ?\\) ?\\)
  6875.             (t char))))
  6876.  
  6877.  
  6878. (defun irc-ctcp-enquote (str)
  6879.   "Enquote a STRING, exchanging some characters to two character combinations."
  6880.   (let ((d "")
  6881.     (dirty "[\001\\]"))
  6882.     (while (string-match dirty str)
  6883.       (setq d (concat d
  6884.               (substring str 0 (match-beginning 0))
  6885.               (irc-ctcp-enquote-char (aref str (match-beginning 0))))
  6886.         str (substring str (match-end 0))))
  6887.     (concat d str)))
  6888.  
  6889.  
  6890. (defun irc-ctcp-enquote-char (char)
  6891.   "Map a character to it's corresponding one or two character STRING."
  6892.   (cond ((= char ?\001) "\\a")
  6893.     ((= char ?\\) "\\\\")
  6894.     (t (char-to-string char))))
  6895.  
  6896.  
  6897. (defun irc-lowlevel-dequote (str)
  6898.   "Return STRING with quoted characters changed into the unquoted equivalents."
  6899.   (let ((new ""))
  6900.     (while (string-match "\020" str)
  6901.       (let ((pos (match-beginning 0)))
  6902.     (if (< pos (1- (length str)))
  6903.         (setq new (concat new
  6904.                   (substring str 0 pos)
  6905.                   (irc-lowlevel-dequote-char (aref str (1+ pos))))
  6906.           str (substring str (+ 2 pos)))
  6907.         (setq new (concat new
  6908.                   (substring str 0 pos)
  6909.                   "<<ERROR in senders client: unquoted CNTRL/P>>")
  6910.           str "")
  6911.         )))
  6912.     (concat new str)))
  6913.  
  6914.  
  6915. (defun irc-lowlevel-dequote-char (char)
  6916.   "Map the CHARACTER after a \020 to it's corresponding character."
  6917.   (char-to-string (cond ((= char ?0) ?\000)
  6918.             ((= char ?n) ?\n)
  6919.             ((= char ?r) ?\r)
  6920.             ((= char ?\020) ?\020)
  6921.             (t char))))
  6922.  
  6923.  
  6924. (defun irc-lowlevel-enquote (str)
  6925.   "Enquote a STRING, exchanging some characters to two character combinations."
  6926.   (let ((d "")
  6927.     (dirty "[\000\n\r\020]"))
  6928.     (while (string-match dirty str)
  6929.       (setq d (concat
  6930.            d
  6931.            (substring str 0 (match-beginning 0))
  6932.            (irc-lowlevel-enquote-char (aref str (match-beginning 0))))
  6933.         str (substring str (match-end 0))))
  6934.     (concat d str)))
  6935.  
  6936.  
  6937. (defun irc-lowlevel-enquote-char (char)
  6938.   "Map a character to it's corresponding one or two character STRING."
  6939.   (cond ((= char ?\000) "\0200")
  6940.     ((= char ?\n) "\020n")
  6941.     ((= char ?\r) "\020r")
  6942.     ((= char ?\020) "\020\020")
  6943.     (t (char-to-string char))))
  6944.  
  6945.  
  6946. (defun irc-show-subscribed-channels ()
  6947.   "Show which channel's user is listening to, and which one is talked to."
  6948.   (if (not irc-multiple-leave-in-progress)
  6949.       (let ((listen (irc-clean-up-message
  6950.              (irc-listify
  6951.               (irc-recall-all 'irc-subscribed-channels)
  6952.               ", "
  6953.               "and"))))
  6954.     (cond ((irc-nothing-remembered-p 'irc-subscribed-channels)
  6955.            (cond ((string= "0" irc-channel)
  6956.               (irc-insert (concat "%sYou're neither listening nor"
  6957.                       " talking to any channel%s")
  6958.                   irc-msg-info-pre
  6959.                   irc-msg-info-post))
  6960.              (t (irc-insert (concat "%sYou're now talking and"
  6961.                         " listening to channel %s%s")
  6962.                     irc-msg-info-pre
  6963.                     irc-channel
  6964.                     irc-msg-info-post))))
  6965.           ((string= "0" irc-channel)
  6966.            (irc-insert (concat "%sYou're not talking to any channel, but"
  6967.                    " listening to %s%s")
  6968.                irc-msg-info-pre
  6969.                listen
  6970.                irc-msg-info-post))
  6971.           (t (let* ((part-1 (format "%sYou are now talking to channel "
  6972.                     irc-msg-info-pre))
  6973.             (irc-msg-cont-used (make-string (length part-1) ? )))
  6974.            (irc-insert "%s%s, while listening to %s%s"
  6975.                    part-1
  6976.                    irc-channel
  6977.                    listen
  6978.                    irc-msg-info-post)))))
  6979.       (set-buffer-modified-p (buffer-modified-p)))
  6980.   nil)
  6981.  
  6982.  
  6983. (defun irc-server-has-end-of-who ()
  6984.   "True if the current server end WHOREPLY with a \"end of list\" message."
  6985.   (or (> irc-major-version 2)
  6986.       (and (= irc-major-version 2)
  6987.        (>= irc-minor-version 4))))
  6988.  
  6989.  
  6990. (defun irc-server-has-end-of-names ()
  6991.   "True if the current server end NAMREPLY with a \"end of list\" message."
  6992.   (or (> irc-major-version 2)
  6993.       (and (= irc-major-version 2)
  6994.        (>= irc-minor-version 4))))
  6995.  
  6996.  
  6997. (defun irc-server-has-end-of-links ()
  6998.   "True if the current server end LINREPLY with a \"end of list\" message."
  6999.   (or (> irc-major-version 2)
  7000.       (and (= irc-major-version 2)
  7001.        (>= irc-minor-version 4))))
  7002.  
  7003.  
  7004. (defun irc-server-has-non-numeric-channel-names ()
  7005.   "True if the current server supports non nummeric IDs for channels."
  7006.   (or (> irc-major-version 2)
  7007.       (and (= irc-major-version 2)
  7008.        (or (> irc-minor-version 4)
  7009.            (and (= irc-minor-version 4)
  7010.             (>= irc-edit-version 2))))))
  7011.  
  7012.  
  7013. (defun irc-server-has-multijoinable-channels ()
  7014.   "True if the current server supports #-type channels and the commands JOIN
  7015. and PART. Probaly v2.6 or later."
  7016.   (or (> irc-major-version 2)
  7017.       (and (= irc-major-version 2)
  7018.        (>= irc-minor-version 6))))
  7019.  
  7020.  
  7021. (defun irc-server-has-channelname-in-msgs ()
  7022.   "True if the server gives the channels name in a RPL_CHANNELMODEIS message."
  7023.   (or (> irc-major-version 2)
  7024.       (and (>= irc-major-version 2)
  7025.        (or (> irc-minor-version 6)
  7026.            (and (>= irc-minor-version 6)
  7027.             (>= irc-edit-version 19))))))
  7028.  
  7029.  
  7030. (defun irc-server-has-end-of-whois ()
  7031.   "True if the server ends WHOIS replies with an enad marker."
  7032.   (or (> irc-major-version 2)
  7033.       (and (>= irc-major-version 2)
  7034.        (or (> irc-minor-version 6)
  7035.            (and (>= irc-minor-version 6)
  7036.             (>= irc-edit-version 20))))))
  7037.  
  7038.  
  7039. (defun irc-server-has-settable-topic-on-multijoinable-channel ()
  7040.   "True if the server supports setting topic for a multijoinable channel."
  7041.   (or (> irc-major-version 2)
  7042.       (and (>= irc-major-version 2)
  7043.        (>= irc-minor-version 7))))
  7044.  
  7045.  
  7046. (defun irc-active-servers ()
  7047.   "Return list of active IRC processes."
  7048.   (let ((lst (if (boundp 'irc-processes) irc-processes))
  7049.     (act nil))
  7050.     (while (consp lst)
  7051.       (if (and (memq (process-status (car lst)) '(open run))
  7052.            (stringp (buffer-name (process-buffer (car lst)))))
  7053.       (setq act (cons (car lst) act)))
  7054.       (setq lst (cdr lst)))
  7055.     (reverse act)))
  7056.  
  7057.  
  7058. (defun irc-host+port-to-buffer-name (host-name port-number)
  7059.   "Return a legal buffer name for a Kiwi session."
  7060.   (cond ((or (not (numberp port-number))
  7061.          (> 0 port-number)
  7062.          (> port-number 65535))
  7063.      (error (format "Kiwi: \"%s\" illegal TCP-port number" port-number)))
  7064.     (t (format "*Kiwi-%s/%d*" host-name port-number))))
  7065.  
  7066.  
  7067. (defun irc-host+port-to-buffer (host-name port-number)
  7068.   "Return the buffer a HOST-NAME in a Kiwi session is associated with.
  7069. If no such buffer exist, create it.
  7070.  
  7071. See also: irc-host-to-buffer-name <f>"
  7072.   (get-buffer-create (irc-host+port-to-buffer-name host-name port-number)))
  7073.  
  7074.  
  7075. (defun irc-session-to-buffer (session)
  7076.   "Convert a Kiwi SESSION (ie host name) to its associated buffer.
  7077. The buffer must exist."
  7078.   (get-buffer session))
  7079.  
  7080.  
  7081. (defun irc-session-names (proc-list)
  7082.   "Convert a LIST of Kiwi processes to a list of the processes host names."
  7083.   (mapcar (function (lambda (p)
  7084.          (buffer-name (process-buffer p))))
  7085.       proc-list))
  7086.  
  7087.  
  7088. (defun irc-get-host-from-session-name (session-name)
  7089.   "Extract the host name associated with a SESSION-NAME."
  7090.   (if (string-match irc-legal-session-name session-name)
  7091.       (subfield session-name 1)
  7092.       (error (format "Illegal session-name: \"%s\"." session-name))))
  7093.  
  7094.  
  7095. (defun irc-get-port-from-session-name (session-name)
  7096.   "Extract the TCP/IP port number associated with a SESSION-NAME."
  7097.   (if (string-match irc-legal-session-name session-name)
  7098.       (string-to-int (subfield session-name 2))
  7099.       (error (format "Illegal session-name: \"%s\"." session-name))))
  7100.  
  7101.  
  7102. (defun irc-terminal-is-slow ()
  7103.   "True if the terminal's speed (baud-rate) is lower than the variable
  7104. \"search-slow-speed\" (the variable is defined in either file loaddefs.el or
  7105. isearch.el in the lisp subdirectory)."
  7106.   (if (not (boundp 'search-slow-speed))    ;This should never happen.
  7107.       (progn (load "loaddefs"))
  7108.       (if (not (boundp 'search-slow-speed))
  7109.       (load "isearch"))
  7110.       (if (not (boundp 'search-slow-speed))
  7111.       (setq search-slow-speed 1200)))
  7112. ;;;  (if (boundp 'baud-rate)
  7113. ;;;      (<= baud-rate search-slow-speed)
  7114. ;;;    (<= (baud-rate) search-slow-speed))
  7115.   t)                    ;Patched.
  7116.  
  7117.  
  7118. (defun irc-non-num-to-0 (x)
  7119.   (if (numberp x)
  7120.       x
  7121.       0))
  7122.  
  7123.  
  7124. (defun irc-pong (&optional line)
  7125.   "Send a PONG message with the hostname as an argument.
  7126. This is usually used to answer a PING message."
  7127.   ;; it's interactive so it can be bound during testing.
  7128.   (interactive)
  7129.   (cond ((string-match "^PING +: *\\([0-9]+\\)$" line)
  7130.      (irc-send (concat "PONG :" (subfield line 1))))
  7131.     (t (irc-send (concat "PONG :" (system-name)))))
  7132.   (irc-who-is-on)
  7133.   nil)
  7134.  
  7135.  
  7136. (defun irc-new-scroll-step (scroll-step)
  7137.   "Calculate a new scroll-step value based on the current windows height
  7138. if terminal is slow (see function irc-terminal-is-slow)."
  7139.   (cond ((and (boundp 'irc-scroll-step)
  7140.           (numberp irc-scroll-step))
  7141.      irc-scroll-step)
  7142.     ((irc-terminal-is-slow)
  7143.      (let* ((h (- (window-height) 3))
  7144.         (x (- h (/ h 6))))
  7145.        (if (> window-min-height x)
  7146.            1
  7147.            (if (> (* 2 window-min-height) x)
  7148.            (/ x 2)
  7149.            x))))
  7150.     (t scroll-step)))        ;Else use old value.
  7151.  
  7152.  
  7153. (defun irc-last-found (str left-most char)
  7154.   "Search in STRING, position LEFT-MOST to end of string, for a CHARacter.
  7155. Return its position, or nil if not found."
  7156.   (let* ((n (length str))
  7157.      (m (while (and (>= n left-most)
  7158.             (not (= char (string-to-char (substring str n nil)))))
  7159.           (setq n (1- n)))))
  7160.     (if (>= n left-most) (1+ n) nil)))
  7161.  
  7162.  
  7163. (defun irc-choose-break-point (str left-most right-most delimiters)
  7164.   "Choose a nice point to break a string in. Break at a delimiting
  7165. character like space, bang or comma. Return a list of two strings,
  7166. the part before and the part after the breakpoint."
  7167.   (cond
  7168.     ((string-match "\n" str)
  7169.      (irc-split-string str (string-match "\n" str)))
  7170.     ((< (length str) right-most)
  7171.      (irc-split-string str (length str)))
  7172.     (t (let ((s (substring str 0 (1- right-most))))
  7173.      (if (or (null delimiters)
  7174.          (<= (min left-most (length str))
  7175.              0))
  7176.          (irc-split-string str (1- right-most))
  7177.          (let ((possible (irc-last-found s left-most (car delimiters))))
  7178.            (if possible
  7179.            (irc-split-string str possible)
  7180.            (irc-choose-break-point str
  7181.                        left-most
  7182.                        right-most
  7183.                        (cdr delimiters)))))))))
  7184.  
  7185.  
  7186. (defun irc-split-string (str n)
  7187.   "Split string STR into two at position N, trimming all white space
  7188. around the split point."
  7189.   (let* ((x (min n (length str)))
  7190.      (first-half (substring str 0 x))
  7191.      (second-half (substring str x))
  7192.      (a (progn (string-match "[\n\t ]*$" first-half)
  7193.            (match-beginning 0)))
  7194.      (b (progn (string-match "^[\n\t ]*" second-half)
  7195.            (match-end 0))))
  7196.     (cons (substring first-half 0 a)
  7197.       (substring second-half (match-end 0)))))
  7198.  
  7199.  
  7200. (defun irc-insert (format &rest args)
  7201.   "Insert before irc-mark the string created by FORMAT with substituted ARGS.
  7202. Resets the global variable \"scroll-step\" each time. If the string is to long
  7203. to be inserted on one line, insert just first part and give the rest to
  7204. \"irc-insert-more\"."
  7205.   (setq scroll-step (irc-new-scroll-step scroll-step))
  7206.   (let* ((str (apply 'format format args))
  7207.      (strlen (length str))
  7208.      (left-most (* (/ (window-width (get-buffer-window (current-buffer)))
  7209.               3)
  7210.                2))
  7211.      (splitted (irc-choose-break-point
  7212.             str
  7213.             left-most
  7214.             (window-width (get-buffer-window (current-buffer)))
  7215.             '(?, ?  ?\050 ?! ?? ?. ?\051)))
  7216.      (first-half (car splitted))
  7217.      (second-half (cdr splitted)))
  7218.     (save-excursion
  7219.       (goto-char (if (and (boundp 'irc-mark) (markerp irc-mark))
  7220.              irc-mark
  7221.              (point-max)))
  7222.       (insert-before-markers first-half "\n")
  7223.       (if (not (string= "" second-half))
  7224.       (irc-insert-more irc-msg-cont-used left-most second-half)))))
  7225.  
  7226.  
  7227. (defun irc-insert-more (continue left-most str)
  7228.   "Insert before irc-mark the line created by concatenating the CONTINUE string
  7229. and the MESSAGE string. If the line is to long, insert the first part and 
  7230. recurse with the rest."
  7231.   (let* ((cont (substring continue 0 (min (/ (* 3 (window-width
  7232.                            (get-buffer-window
  7233.                             (current-buffer))))
  7234.                          4)
  7235.                       (length continue))))
  7236.      (splitted (irc-choose-break-point str ;;QUICK ugly bug fix.... bleah!
  7237.                        (max 0 (- left-most (length cont)))
  7238.                        (- (window-width (get-buffer-window
  7239.                                  (current-buffer)))
  7240.                           (length cont))
  7241.                        '(?, ?  ?\( ?! ?? ?. ?;)))
  7242.      (first-half (concat cont (car splitted)))
  7243.      (second-half (cdr splitted)))
  7244.     (insert-before-markers first-half "\n")
  7245.     (if (not (string= "" second-half))
  7246.     (irc-insert-more cont left-most second-half))))
  7247.  
  7248.  
  7249. (defun irc-fix-wordwrap (line1 line2)
  7250.   "With arguments LINE1 and LINE2 apply some simple heuristics to see if the
  7251. line which they originally formed was broken in an acceptable place.  Returns
  7252. a dotted pair with LINE1 as the car and LINE2 as the cdr."
  7253.   (cond ((string-match "^ +" line2)
  7254.          ;; broke at whitespace; strip leading space from next line
  7255.          (setq line2 (substring line2 1)))
  7256.         ((string-match " +$" line1)
  7257.          ;; trailing whitespace on line.  might as well just nuke it all.
  7258.          (setq line1 (substring line1 0 (match-beginning 0))))
  7259.         ((string-match "\\( +\\)[^: ]+$" line1)
  7260.          ;; broke in a word, but it's wrappable.  just eat one space.
  7261.          (setq line2 (concat (substring line1 (1+ (match-beginning 1))) line2)
  7262.                line1 (substring line1 0 (match-beginning 0)))))
  7263.   (cons line1 line2))
  7264.  
  7265.  
  7266.  
  7267. ;; simple key functions -- self-insert, tab, destructive backspace
  7268. (defun irc-self-insert (arg)
  7269.   "Normaly just inserts the typed character in the input region.
  7270. If point is in the output region, irc-spacebar-pages is non-nil and a space
  7271. is typed, scroll-up otherwise point moves to end of input region and inserts
  7272. the character.
  7273.  
  7274. If the character to be inserted is a colon or semi-colon and it is the first
  7275. non-white space character on the line then the input region is updated to
  7276. begin with the last explicit sendlist, irc-last-explicit.
  7277.  
  7278. Inserts the character ARG times if self-inserting.  An argument is not
  7279. passed to scroll-up if paging with the spacebar."
  7280.   (interactive "p")
  7281.   (let* ((in-region (>= (point) irc-mark))
  7282.      (mapped (assoc last-command-char
  7283.             '((?\100 . ?\311)
  7284.               (?\133 . ?\304)
  7285.               (?\134 . ?\326)
  7286.               (?\135 . ?\305)
  7287.               (?\136 . ?\334)
  7288.               (?\140 . ?\351)
  7289.               (?\173 . ?\344)
  7290.               (?\174 . ?\366)
  7291.               (?\175 . ?\345)
  7292.               (?\176 . ?\374))))
  7293.      (invmapped (assoc last-command-char
  7294.                '((?\100 . ?\311)
  7295.                  (?\133 . ?\344)
  7296.                  (?\134 . ?\366)
  7297.                  (?\135 . ?\345)
  7298.                  (?\136 . ?\334)
  7299.                  (?\140 . ?\351)
  7300.                  (?\173 . ?\304)
  7301.                  (?\174 . ?\326)
  7302.                  (?\175 . ?\305)
  7303.                  (?\176 . ?\374))))
  7304.      (chr (if (and irc-map-keyboard-ISO-646-SE2-to-ISO-8859-1
  7305.                mapped)
  7306.           (cdr (if (eq t irc-map-keyboard-ISO-646-SE2-to-ISO-8859-1)
  7307.                mapped
  7308.              invmapped))
  7309.           last-command-char))
  7310.          ;; it's times like this that i wish someone would tell me what
  7311.          ;; a good indentation style is for this expression
  7312.          (expand-colon
  7313.           (and
  7314.        (or (= last-command-char ?\;) (= last-command-char ?:))
  7315.            (string-match "^ *$"
  7316.              (buffer-substring
  7317.               irc-mark
  7318.               (if in-region (point) (point-max)))))))
  7319.     (if (not expand-colon)
  7320.         (if in-region
  7321.         (while (> arg 0)
  7322.           (insert chr)
  7323.           (setq arg (1- arg)))
  7324.         ;; else
  7325.         (if (and irc-spacebar-pages
  7326.              (= last-command-char 32))
  7327.         ;; it's nice to be able to return to the input region just by
  7328.         ;; pounding on the spacebar repeatedly.
  7329.         (condition-case EOB (scroll-up nil)
  7330.           (end-of-buffer (goto-char (point-max))))
  7331.         (goto-char (point-max))
  7332.         (while (> arg 0)
  7333.           (insert chr)
  7334.           (setq arg (1- arg)))))
  7335.     (or in-region (goto-char (point-max)))
  7336.     ;; Kill white space. This also takes out previous lines in
  7337.     ;; input region.
  7338.     (delete-region irc-mark (point))
  7339.     (insert (if (= last-command-char ?:) irc-last-private irc-last-explicit))
  7340.     ;; put in the extra characters if need be.
  7341.     (setq arg (1- arg))
  7342.     (while (> arg 0)
  7343.       (insert chr)
  7344.       (setq arg (1- arg))))))
  7345.  
  7346.  
  7347. (defun irc-del-backward-char (arg)
  7348.   "If in the input region, delete ARG characters before point, restricting
  7349. deletion to the input region.  If in the output region and irc-spacebar-pages
  7350. then scroll-down (aka window-back) otherwise do nothing."
  7351.   (interactive "p")
  7352.   (if (> (point) irc-mark)
  7353.       ;; only delete as far back as irc-mark at most
  7354.       (if (> arg (- (point) irc-mark)) (delete-region (point) irc-mark)
  7355.       (delete-backward-char arg))
  7356.       (if (and (<= (point) irc-mark) irc-spacebar-pages) (scroll-down nil)
  7357.       (ding))))
  7358.  
  7359.  
  7360. (defun irc-tab ()
  7361.   "If point is in the input region then tab-to-tab-stop.  If it is in the
  7362. output region, go to the previous line if irc-spacebar-pages; do nothing
  7363. otherwise."
  7364.   (interactive)
  7365.   (if (>= (point) irc-mark) (tab-to-tab-stop)
  7366.       (if irc-spacebar-pages (previous-line 1)
  7367.       (ding))))
  7368.  
  7369.  
  7370.  
  7371. ;; top-level -- entry, sentinel and mode
  7372. (defun irc (&optional universal-argument)
  7373.   "Enter the Internet Relay Chat conferencing system.
  7374. If no connexion to an irc-server is open, then one is started.  If no buffer
  7375. *IRC* exists then it is created otherwise the existing buffer is used.  If
  7376. a connexion is already active then the most recently started IRC session
  7377. is switched to in the current window.  This makes binding 'irc' to a key
  7378. much more convenient.
  7379.  
  7380. With prefix argument NEW-BUFFER, another *IRC* buffer is created and a
  7381. new IRC session is started.  This is provided so that multiple IRC
  7382. sessions can co-exist in one Emacs, which is sometimes a useful thing."
  7383.   (interactive "P")
  7384.   (load "w3" 'noerr)
  7385.   (let* ((act (irc-active-servers))
  7386.      (session-names (irc-session-names act))
  7387.      (number-of-sessions (length session-names))
  7388.      (ask-for-session (> number-of-sessions 1))
  7389.      (session (let ((s (if ask-for-session
  7390.                    (irc-nuke-whitespace
  7391.                 (irc-read-object
  7392.                  "Select which Kiwi session? (RET for new) "
  7393.                  ""
  7394.                  session-names))
  7395.                    "")))
  7396.             (if (or (irc-member-general s
  7397.                         session-names
  7398.                         'string=)
  7399.                 (string= "" s))
  7400.             s
  7401.             (error (format "No such active session: %s" s)))))
  7402.      (ask-for-host (or universal-argument
  7403.                (= 0 number-of-sessions)
  7404.                (and ask-for-session
  7405.                 (string= "" session))))
  7406.      (host (downcase
  7407.         (cond
  7408.           (ask-for-host
  7409.            (let ((h (irc-nuke-whitespace
  7410.                  (read-string
  7411.                   (concat "Connect new Kiwi session to which"
  7412.                       " internet host? (RET for "
  7413.                       irc-server
  7414.                       ") ")))))
  7415.              (if (string= "" h) irc-server h)))
  7416.           (ask-for-session
  7417.            (irc-get-host-from-session-name session))
  7418.           ((= 1 number-of-sessions)
  7419.            (irc-get-host-from-session-name (car session-names)))
  7420.           (t ""))))
  7421.      (port (cond
  7422.          (ask-for-host
  7423.           (let* ((p (irc-nuke-whitespace
  7424.                  (read-string
  7425.                   (concat "Use which TCP port for new connection?"
  7426.                       " (RET for "
  7427.                       (int-to-string irc-port)
  7428.                       ", * for 194) "))))
  7429.              (n (string-to-int p)))
  7430.             (cond ((string= "*" p) 194)
  7431.               ((string= "" p) irc-port)
  7432.               ((and (> n 0) (> 65535 n)) n)
  7433.               (t (error "Illegal TCP port")))))
  7434.          (ask-for-session
  7435.           (irc-get-port-from-session-name session))
  7436.          ((= 1 number-of-sessions)
  7437.           (irc-get-port-from-session-name (car session-names)))
  7438.          (t nil)))
  7439.      (buffer (irc-host+port-to-buffer host port)))
  7440.     (make-variable-buffer-local 'irc-port)
  7441.     (setq irc-port port)
  7442.     (switch-to-buffer buffer)
  7443.     (if (not (get-buffer-process (current-buffer)))
  7444.     (progn
  7445.       (goto-char (point-max))
  7446.       (irc-mode)
  7447.       (irc-insert "")
  7448.       (irc-insert "")
  7449.       (irc-insert "%s for GNU Emacs v18.57 and around...." irc-version)
  7450.       (irc-insert "Comments to %s." irc-hacker)
  7451.       (irc-insert "")
  7452.       (condition-case NOT-IRCED
  7453.           (let ((proc (open-network-stream
  7454.                "irc" buffer host port)))
  7455.         (set-process-filter proc 'irc-filter)
  7456.         (set-process-sentinel proc 'irc-sentinel)
  7457.         (setq irc-server host)
  7458.         (setq-default irc-server host)
  7459.         (irc-send (concat "NICK " irc-nick))
  7460.         (irc-send (format "USER %s %s %s :%s"
  7461.                   (user-login-name)
  7462.                   (system-name)
  7463.                   irc-server
  7464.                   (or (getenv "IRCNAME")
  7465.                       (getenv "NAME")
  7466.                       (user-full-name)
  7467.                       "<<USERNAME UNKNOWN>>")))
  7468.         ;; a new process, so initialize the variables.  they aren't set
  7469.         ;; in irc-mode so that irc-mode can be called at any time.
  7470.         ;; (irc-remember irc-nick 'irc-nicknames)
  7471.         (let ((s (irc-recall-all 'irc-services)))
  7472.           (while (and (listp s) s)
  7473.             (irc-remember (car s) 'irc-nicknames)
  7474.             (setq s (cdr s))))
  7475.         (irc-remember irc-server 'irc-servernames)
  7476.         (setq irc-nick-used ".Not.connected.yet."
  7477.               irc-major-version 0
  7478.               irc-minor-version 0
  7479.               irc-edit-version 0
  7480.               irc-motd-lines nil
  7481.               irc-list-stats '(0 0)
  7482.               irc-away nil
  7483.               irc-channel "0"
  7484.               irc-history-index -1
  7485.               irc-operator nil
  7486.               irc-scratch ""
  7487.               irc-last-command  ""
  7488.               irc-last-explicit "*;"
  7489.               irc-last-private "*;"
  7490.               irc-last-time (irc-get-time)
  7491.               ;; this next bit of messiness just ups irc-last-stamp
  7492.               ;; in an effort to make nice numbers out of the time
  7493.               ;; stamps -- ie, if the time is now 13:53 with an
  7494.               ;; interval of 15 minutes, this makes it 13:45
  7495.               irc-last-stamp 0
  7496.               irc-total-time (string-to-int
  7497.                       (substring irc-last-time 3))
  7498.               irc-last-stamp (if (zerop irc-time-stamp)
  7499.                      0
  7500.                      (while (< (+ irc-last-stamp
  7501.                               irc-time-stamp)
  7502.                            irc-total-time)
  7503.                        (setq irc-last-stamp
  7504.                          (+ irc-last-stamp
  7505.                             irc-time-stamp)))
  7506.                      irc-last-stamp)
  7507.               irc-last-notify irc-last-stamp
  7508.               irc-processes (cons proc irc-processes))
  7509.         (irc-send "CLIENT-START"))
  7510.         (error
  7511.          (irc-insert (concat "%%Couldn't connect to the TCP/IP"
  7512.                  " port %s at the internet host %s --"
  7513.                  " sorry: %s")
  7514.              port
  7515.              host
  7516.              NOT-IRCED)
  7517.          ))))))
  7518.  
  7519.  
  7520. (defun irc-mode ()
  7521.   "To understand some documentation given with irc-mode variables and
  7522. functions, \"output region\" is defined as everything before the irc-mark.
  7523. irc-mark is a marker kept by irc-mode to know where to insert new text
  7524. from IRC.  Text in the output region cannot be modified by the most common
  7525. methods of typing a self-inserting character or pressing delete.
  7526.  
  7527. The input region is everything which follows irc-mark.  It is what
  7528. gets processed by irc-mode when you type LFD or RET.  If irc-spacebar-pages
  7529. is non-nil, the following keys are in effect when the cursor is in the
  7530. output region:
  7531.  
  7532. SPC             scroll-forward       DEL     scroll-backward
  7533. LFD or RET      next-line            TAB     previous-line
  7534.  
  7535. Local keys:
  7536. \\{irc-mode-map}"
  7537.   (interactive)
  7538.   (setq buffer-offer-save t)
  7539.   (kill-all-local-variables)
  7540.   (setq major-mode 'irc-mode
  7541.     mode-name "Kiwi"
  7542.     fill-column (- (window-width (get-buffer-window (current-buffer))) 5))
  7543.   (set (make-local-variable 'irc-away) nil) ; for the mode-line
  7544.   (set (make-local-variable 'irc-channel) nil) ; for sendlists and broken PRIVMSGs
  7545.   (set (make-local-variable 'irc-edit-version) nil) ; edit version number of server
  7546.   (set (make-local-variable 'irc-history-index) nil) ; for the message history
  7547.   (set (make-local-variable 'irc-last-command) nil) ; for the command history
  7548.   (set (make-local-variable 'irc-last-explicit) nil) ; for sendlist ; auto-expansion
  7549.   (set (make-local-variable 'irc-last-private) nil) ; for sendlist : auto-expansion
  7550.   (set (make-local-variable 'irc-last-stamp) nil) ; for time-sentinel
  7551.   (set (make-local-variable 'irc-last-time) nil) ;
  7552.   (set (make-local-variable 'irc-list-stats) nil) ; for RPL_LIST statistics (temp)
  7553.   (set (make-local-variable 'irc-major-version) nil) ; major version number of server
  7554.   (set (make-local-variable 'irc-minor-version) nil) ; major version number of server
  7555.   (set (make-local-variable 'irc-nick-used) nil) ; the nick used at the server
  7556.   (set (make-local-variable 'irc-operator) nil)    ; for special privileges
  7557.   (set (make-local-variable 'irc-scratch) nil) ; for accumulating server messages
  7558.   (set (make-local-variable 'irc-total-time) nil) ;
  7559.   (set (make-local-variable 'irc-count-incoming-messages) 0)
  7560.   (set (make-local-variable 'irc-idle-last-sent) -1)
  7561. ;;;  (set (make-local-variable 'irc-idle-scratch-file)
  7562. ;;;       (expand-file-name
  7563. ;;;    (concat (make-temp-name "/tmp/.Kiwi.")
  7564. ;;;        "."
  7565. ;;;        (user-login-name)
  7566. ;;;        ".may-safely-be-deleted-anytime")))
  7567. ;;;  (if (file-exists-p irc-idle-scratch-file)
  7568. ;;;      (delete-file irc-idle-scratch-file))
  7569.   (set (make-local-variable 'irc-ignored-ppl) ;Nicks actually ignored
  7570.        (irc-create-new-hash-table 7))
  7571.   (set (make-local-variable 'irc-last-NOTICE-rcv) "")
  7572.   (set (make-local-variable 'irc-last-NOTICE-src) "")
  7573.   (set (make-local-variable 'irc-links-header) "Known server links.")
  7574.   (set (make-local-variable 'irc-links-stroke) "-------------------")
  7575.   (set (make-local-variable 'irc-linksinfo) ; for LINREPLY & RPL364 data (temp)
  7576.        (irc-create-new-hash-table 149))    ;2*(65-70 seen links, oct -91)
  7577.   (set (make-local-variable 'irc-list-header) "Name of channel  Users Topic")
  7578.   (set (make-local-variable 'irc-list-stroke) "---------------  ----- -----")
  7579.   (set (make-local-variable 'irc-listtree) ; for RPL_LIST 322 data (temp)
  7580.        (irc-create-new-hash-table 163))    ;2*(50-80 channels, oct -91)
  7581.   (set (make-local-variable 'irc-msg-cont-used) irc-msg-cont)
  7582.   ;; Indentation for continued long lines when displaying NAMREPLY's.
  7583.   (set (make-local-variable 'irc-names-cont-msg) (make-string 24 ? ))
  7584.   (set (make-local-variable 'irc-notify-looked-for)
  7585.        (irc-create-new-hash-table 149))
  7586.   (set (make-local-variable 'irc-notify-detected)
  7587.        (irc-create-new-hash-table 149))
  7588.   (set (make-local-variable 'irc-namtree) ; for NAMREPLY data (temp)
  7589.        (irc-create-new-hash-table 853))    ;2*(200-400 users, oct -91)
  7590.   (set 'irc-nicknames            ; for sendlists
  7591.        (irc-create-new-hash-table 853)) 
  7592.   (set 'irc-servernames            ; for server completion
  7593.        (irc-create-new-hash-table 997))    ;2*((60-70 seen links)+(200-400usrs))
  7594.   (set (make-local-variable 'irc-subscribed-channels) ; channels we listen to
  7595.        (irc-create-new-hash-table 7))    ;max 11
  7596.   (set (make-local-variable 'irc-services) ; for services like NICKSERV
  7597.        (irc-create-new-hash-table 17))
  7598.   (set (make-local-variable 'irc-who-header)
  7599.        (concat "Nickname  Stat Channel name   "
  7600.            " <Hop count> Login@Client \"Real name\" SERVER=srvr"))
  7601.   (set (make-local-variable 'irc-who-header)
  7602.        (concat "Nickname  Stat Random channel  Whatever@clientmachine \"Real name\""))
  7603.   (set (make-local-variable 'irc-who-stroke)
  7604.        (concat "--------  ---- --------------  "
  7605.            "------------------------------------------------"))
  7606.   (set (make-local-variable 'irc-whotree) ; for WHOREPLY data (temp)
  7607.        (irc-create-new-hash-table 853))    ;(200-400 users, oct -91)
  7608.   (set (make-local-variable 'mode-line-format)
  7609.        (list (purecopy "--- %14b ")
  7610.          'global-mode-string
  7611.          (purecopy " %[(")
  7612.          'mode-name 'minor-mode-alist 'irc-operator
  7613.          (purecopy ")%] ")
  7614.          'irc-nick-used ":" 'irc-channel
  7615.          " " 'irc-away (purecopy "-%-")))
  7616.   ;; too many ways to get unbalanced parens (most notably ":-)")
  7617.   (set (make-local-variable 'blink-matching-paren) nil)
  7618.   ;; as closest we can come to "natural" terminal scrolling
  7619.   (set (make-local-variable 'scroll-step) 1) ; Reset in irc.
  7620.   (set-marker (set (make-local-variable 'irc-mark) (make-marker)) (point-max))
  7621.   (let ((nicks irc-ignores))
  7622.     (while (not (null nicks))
  7623.       (irc-remember (car nicks) 'irc-ignored-ppl)
  7624.       (setq nicks (cdr nicks))))
  7625.   (let ((services '(;;"AMIGASERV"
  7626.             ;;"ARSKA"        ;TZoper of #42.
  7627.             ;;"CDSERV"
  7628.             ;;"CONVSERV"    ;Convert from Celsius to Fahrenheit etc
  7629.             ;;"EU-OPER"        ;TZoper of #Eu-opers.
  7630.             "IRCIIHELP"        ;Help automaton for ircII commands
  7631.             ;;"JIRCC"        ;Japanese Kanjii/ASCII translator
  7632.             ;;"MSGSERV"        ;Stores and forwards user-user messages
  7633.             "NICKSERV"        ;Register for nick names
  7634.             ;;"NOTE-NO"
  7635.             ;;"NOTESERV"    ;"Wait for user" and "store messages".
  7636.             ;;"SWEDESERV"
  7637.             ;;"TZOPER"        ;Copr ioprs on #Twilight_Zone
  7638.             ;;"WEBSERV"
  7639.             )))
  7640.     (while services
  7641.       (irc-remember (car services) 'irc-services)
  7642.       (irc-remember (car services) 'irc-nicknames)
  7643.       (setq services (cdr services))))
  7644.   (buffer-enable-undo)
  7645.   (irc-wrap-display-time)
  7646.   (turn-on-auto-fill)
  7647.   ;; "invisible subwindows" or whatever you would like to call them would be
  7648.   ;; nice.  That way I could make the output-region read-only.  The two things
  7649.   ;; most likely to screw up the buffer are backward-kill-word and kill-region
  7650.   (use-local-map irc-mode-map)
  7651.   (run-hooks 'irc-mode-hook))
  7652.  
  7653.  
  7654. (defun irc-sentinel (proc stat)
  7655.   "The sentinel for the IRC connexion.
  7656. Takes the normal sentinel arguments PROCESS and STATUS."
  7657.   ;; ignore anything but finished; i don't know what to do with the others
  7658.   (cond ((or (string= stat "finished\n")
  7659.          (string-match "^exit" stat))
  7660.          (save-excursion
  7661.            (set-buffer (cond ((processp proc) (process-buffer proc))
  7662.                  ((bufferp proc) proc)
  7663.                  (t (get-buffer
  7664.                  (irc-host+port-to-buffer irc-server
  7665.                               irc-port)))))
  7666.            (goto-char (point-max))
  7667.        (ding nil)
  7668.        (ding nil)
  7669.        (ding nil)
  7670.        (irc-insert "")
  7671.        (irc-insert "")
  7672.        (irc-insert (make-string (1- (window-width
  7673.                      (get-buffer-window (current-buffer))))
  7674.                     ?*))
  7675.        (let ((msg (format "Your IRC session ended at %s." (irc-get-time))))
  7676.          (irc-insert "%s%s"
  7677.              (make-string (max (/ (- (window-width
  7678.                           (get-buffer-window
  7679.                            (current-buffer)))
  7680.                          (length msg))
  7681.                           2)
  7682.                        0)
  7683.                       ? )
  7684.              msg))
  7685.        (irc-insert (make-string (1- (window-width
  7686.                      (get-buffer-window (current-buffer))))
  7687.                     ?*))
  7688.        (irc-insert ""))
  7689.          ;; all that needs to be done is a little maintenance ...
  7690.          (setq irc-processes (delq proc irc-processes)))))
  7691.  
  7692.  
  7693.  
  7694. ;; processing input
  7695.  
  7696. (defun irc-process-input ()
  7697.   "If in the input region, parse it for messages and commands.
  7698. In the output region, next-line if irc-spacebar-pages, otherwise do nothing.
  7699.  
  7700. All of the lines in the input region are rejoined during processing to be
  7701. handled as one.  A command is any line starting with a / after leading
  7702. whitespace is stripped away; commands can not exceed 510 characters.  Messages
  7703. can be longer but they will be split into 510 character segments for IRC.  The
  7704. buffer will reflect how the message was sent if it needed to be broken; the
  7705. split(s) will be indicated by \" >>\" to mean that the message is continued."
  7706.   (interactive)
  7707.   ;; do the simple stuff for the output region
  7708.   (if (< (point) irc-mark)
  7709.       (if (and (fboundp 'url-get-url-at-point)
  7710.            (fboundp 'w3-follow-url-at-point-other-frame)
  7711.            (stringp (url-get-url-at-point)))
  7712.       (let ((p (point)))
  7713.         (next-line 1)
  7714.         (w3-follow-url-at-point-other-frame p))
  7715.     (if irc-spacebar-pages
  7716.         (next-line 1)
  7717.       (ding)))
  7718.     (if (not (processp (get-buffer-process (current-buffer))))
  7719.     (irc-insert (concat "%%Buffer not connected to any IRC-server, type"
  7720.                 " M-x irc RET to connect to a server."))
  7721.       (irc-check-time)
  7722.       ;; the input region is more work ...
  7723.       ;; first, toast extraneous spaces, tabs and newlines
  7724.       ;; at end of input region
  7725.       (delete-region (goto-char (point-max))
  7726.              (if (re-search-backward "[^ \n]" irc-mark t)
  7727.              (1+ (point))
  7728.                (point)))
  7729.       ;; nuke the white space at the beginning of input region, too
  7730.       (delete-region (goto-char irc-mark)
  7731.              (progn (re-search-forward " *")
  7732.                 (point)))
  7733.       (setq irc-history-index -1)    ; reset the history scroll location
  7734.       (let ((txt (buffer-substring irc-mark (point-max)))
  7735.         (maxlen (- irc-max-server-message-length 2))
  7736.         send
  7737.         ass)
  7738.     ;; check to see if the input region is empty
  7739.     (if (string= "" txt)
  7740.         (message "%%Nothing sent to the irc-server.")
  7741.       (while (string-match "\n" txt)
  7742.         (aset txt (match-beginning 0) ? ))
  7743.       (if (string-match "^/" txt)  ; it's a command
  7744.           (if (< (length txt) maxlen)
  7745.           (progn
  7746.             (goto-char (point-max))
  7747.             (insert "\n")
  7748.             (set-marker irc-mark (point))
  7749.             (irc-execute-command
  7750.              (setq irc-last-command (substring txt 1))))
  7751.         ;; can't use error because that kills the function
  7752.         (ding)
  7753.         (message "IRC commands can't exceed %d characters."
  7754.              maxlen))
  7755.         ;; "a specified sendlist" -- was there one?
  7756.         (setq ass (irc-find-to txt 'explicit))
  7757.         (if (and ass
  7758.              (string-match "^[^;:]" txt))
  7759.         ;; a real sendlist was specified, so
  7760.         ;; update irc-last-explicit
  7761.         (setq irc-last-explicit (irc-find-to txt)))
  7762.         (irc-add-to-hist (concat (if (not ass)
  7763.                      irc-default-to)
  7764.                      (buffer-substring irc-mark
  7765.                                (point-max))))
  7766.         (while (> (length txt) maxlen)
  7767.           (setq send (substring txt 0 maxlen)
  7768.             txt  (substring txt maxlen)
  7769.             send (irc-fix-wordwrap send txt)
  7770.             txt  (concat (if ass
  7771.                      irc-last-explicit
  7772.                    irc-default-to)
  7773.                     z
  7774.                     (cdr send))
  7775.             send (concat (car send) " >>"))
  7776.           (goto-char (+ irc-mark (- (length send) 3)))
  7777.           (insert " >>\n" (if ass
  7778.                   irc-last-explicit
  7779.                 irc-default-to))
  7780.           (if (looking-at " ")
  7781.           (delete-char 1))
  7782.           (beginning-of-line)
  7783.           (set-marker irc-mark (point))
  7784.           (irc-execute-msg send))
  7785.         (goto-char (point-max))
  7786.         (insert "\n")
  7787.         (set-marker irc-mark (point))
  7788.         (irc-execute-msg txt))))))
  7789.   (setq irc-idle-last-sent (irc-current-time)))
  7790.  
  7791.  
  7792. (defun irc-execute-command (str)
  7793.   "Execute the \"/\" command of STR.  STR should not begin with a slash.
  7794. Commands are first looked up in the irc-alias-alist; if it is found there
  7795. then the alias gets passed recursively with any arguments the original
  7796. had.  The irc-command-alist is checked next and finally the irc-operator-alist.
  7797. A command is considered \"found\" when it matches either exactly or
  7798. unambiguously starting at the first character.  That is, J would match JOIN,
  7799. but OIN would not."
  7800.   (let* ((case-fold-search t)
  7801.          (cmd (substring str 0 (string-match "\\( +\\|$\\)" str)))
  7802.          (text (substring str (match-end 0)))
  7803.          (ambig (irc-check-list
  7804.                  (mapcar 'car (append irc-alias-alist irc-command-alist
  7805.                                       (if irc-operator irc-operator-alist)))
  7806.                  cmd 'start-only))
  7807.          (matches nil)
  7808.      (irc-called-from-buffer t))
  7809.     ;; if no matches are found the command might still be a valid command
  7810.     ;; name hiding behind non-operator status.  i don't like messages that
  7811.     ;; lie and say "Unknown command '/REHASH'" so this should make it not lie.
  7812.     (if (and (not irc-operator) (null ambig))
  7813.         (setq ambig (irc-check-list (mapcar 'car irc-operator-alist) cmd t)))
  7814.     ;; first determine any ambiguities among the lists
  7815.     (if (null ambig)
  7816.         ;; no matches at all were found
  7817.         (irc-insert "%%Unknown command \"/%s\".  Type /HELP for help."
  7818.                     (upcase cmd))
  7819.     ;; this is here for when a regular command gets aliased.  it shows up
  7820.     ;; as being ambiguous but it really isn't later on.
  7821.     (if (irc-member-general (car ambig) (cdr ambig) 'string=)
  7822.         (setq ambig (cdr ambig)))
  7823.     (if (> (length ambig) 1)
  7824.         (irc-insert "%%Ambiguous command \"/%s\".  Could be %s."
  7825.             (upcase cmd)
  7826.             (irc-subst-comma
  7827.              (mapconcat (function (lambda (arg)
  7828.                       (concat "/" arg)))
  7829.                     ambig
  7830.                     ", ")
  7831.              "or"))
  7832.         ;; alias list has highest priority
  7833.         (setq matches (irc-check-list (mapcar 'car irc-alias-alist) cmd t))
  7834.         ;; make sure matches is what we set out to looking for ...
  7835.         (if (and matches (string= (car matches) (car ambig)))
  7836.         ;; call this function again with the text as argument
  7837.         (irc-execute-command
  7838.          (concat (cdr (assoc (car matches) irc-alias-alist))
  7839.              ;; the servers won't grok trailing whitespace for some
  7840.              ;; messages so only use it to separate an argument
  7841.              (if (string< "" text) " ") text))
  7842.         ;; next try the command alist
  7843.         (setq matches (irc-check-list (mapcar 'car irc-command-alist)
  7844.                           cmd
  7845.                           t))
  7846.         (if (and matches
  7847.              (not (irc-check-list (mapcar 'car irc-operator-alist)
  7848.                           cmd
  7849.                           t)))
  7850.             ;; call the appropriate irc-execute-* function
  7851.             (funcall (intern-soft
  7852.                   (concat "irc-execute-"
  7853.                       (cdr (assoc (car matches)
  7854.                           irc-command-alist))))
  7855.                  text)
  7856.             ;; no matches yet.  last resort is the operator alist
  7857.             (setq matches (irc-check-list (mapcar 'car
  7858.                               irc-operator-alist)
  7859.                           cmd
  7860.                           t))
  7861.             (if matches
  7862.             (if irc-operator
  7863.                 (funcall
  7864.                  (intern-soft (concat
  7865.                        "irc-execute-"
  7866.                        (cdr
  7867.                         (assoc (car matches)
  7868.                            irc-operator-alist))))
  7869.                  text)
  7870.                 (irc-insert (concat "%%Only enabled IRC Operators"
  7871.                         " can use the /%s command. Use"
  7872.                         " /OPER to enable yourself.")
  7873.                     (upcase (car matches)))))))))))
  7874.  
  7875.  
  7876. (defun irc-send (str)
  7877.   "Send STR to process in the current buffer.
  7878. A CR-LFD pair is appended automatically as per the 'official' IRC protocol,
  7879. but it seems unnecessary.  Returns its argument STR."
  7880.   (setq str (irc-lowlevel-enquote str))
  7881.   (let* ((proc (get-buffer-process (current-buffer)))
  7882.      (sent (if (processp proc)
  7883.            (condition-case x
  7884.                (send-string proc (concat str "\r\n"))
  7885.              (error x))))
  7886.      (ok (and (processp proc)
  7887.           (eq sent nil))))
  7888.     (if (not ok)
  7889.     (let ((stars (make-string (1- (window-width (get-buffer-window
  7890.                              (current-buffer))))
  7891.                   ?*)))
  7892.       (irc-insert "")
  7893.       (irc-insert "")
  7894.       (irc-insert "%s" stars)
  7895.       (irc-insert "?Failed sending to server!")
  7896.       (cond ((not (processp proc))
  7897.          (irc-insert "?No \"process\" to send to."))
  7898.         ((consp sent)
  7899.          (irc-insert (concat "?Signaled condition is \"%s\" and"
  7900.                      " associated data is \"%s\".")
  7901.                  (car sent)
  7902.                  (cdr sent)))
  7903.         (t (irc-insert "?Unknown reason, proc=%s, sent=%s."
  7904.                    proc
  7905.                    sent)))
  7906.       (irc-insert "?Your IRC session aborted at %s." (irc-get-time))
  7907.       (irc-insert "%s" stars)
  7908.       (if (processp proc) (delete-process proc))
  7909.       (error "IRC aborted"))
  7910.     (irc-log-in-debug-buffer (concat "+ " str)))))
  7911.  
  7912.  
  7913.  
  7914. ;; sending messages to people
  7915. (defun irc-execute-privmsg (str)
  7916.   "Usage: /MSG recipient(s) message
  7917.  
  7918. This command is provided simply for compatability with the C client.
  7919. It is preferable instead to just type the name of the user followed by
  7920. a semi-colon and then the message. That is, \"tale;hi!\" will send the
  7921. message \"hi!\" to the user with the nickname which starts with
  7922. \"tale\".  A semi-colon at the beginning of the line means to send to
  7923. the last recipient explicity specified; typing a semi-colon at the
  7924. beginning of a line expands it to the last recipient(s) specified. The
  7925. recipients for a message can be a comma separated list of users and/or
  7926. channels. Don't use any spaces left of the semi-colon.
  7927.  
  7928. You can send messages to users and channels, and if you are an enabled
  7929. IRC operator, you can also send broadcasts to server machines and
  7930. client machines.
  7931.  
  7932. Examples:
  7933. /msg wiz hi there           send \"hi there\" to user with nickname wiz
  7934. wiz;hi there                send to user wiz
  7935. msa,wiz;hi there            send to the users wiz and msa
  7936. 42;hi there                 send into channel 42
  7937. 42,wiz;hi there             channel 42 and user wiz
  7938.  
  7939. If you are an enabled IRC operator:
  7940. $minsk.docs.uu.se;...       send a message to all users using server minsk
  7941. $*.se;...                   send to all users using swedish servers
  7942. #cia.docs.uu.se;...         send to all users running their clients on cia
  7943. #*.se;...                   all user running their clients on swedish machines"
  7944.   (irc-add-to-hist
  7945.    (irc-execute-msg
  7946.     (concat
  7947.      (setq irc-last-explicit (concat (substring str 0 (string-match " +\\|$"
  7948.                                     str))
  7949.                      ";"))
  7950.      (substring str (match-end 0))))))
  7951.  
  7952.  
  7953. (defun irc-execute-msg (str)
  7954.   "Send a message to a channel or another user.  Returns its argument STR,
  7955. munged slightly to indicate where it was attempted to be sent."
  7956.   ;; this really is an indirect function of the UI (ie, not through a /COMMAND)
  7957.   ;; so it isn't interactive
  7958.   (let ((tolist nil)
  7959.     (orig str)
  7960.     (icw nil)
  7961.     (confirm nil)
  7962.     (on-hash (irc-is-multijoinable-channel irc-channel))
  7963.     (newsrvr (irc-server-has-multijoinable-channels)))
  7964.     (if (string-match "^[:;]" str)
  7965.         ;; a little bit of fill-in-the-blank
  7966.         (setq str (concat irc-last-explicit (substring str 1)))
  7967.     (if (not (irc-find-to str 'explicit))
  7968.         ;; prepend an implicit sendlist if need be
  7969.         (if irc-default-to
  7970.         (setq str (concat irc-default-to str))
  7971.         (irc-insert "%%You have no default sendlist."))))
  7972.     (if (irc-find-to str 'explicit)
  7973.         (setq icw (irc-find-to str)
  7974.               tolist (irc-burst-comma (substring icw 0 (1- (length icw))))
  7975.           tolist (mapcar 'irc-clean-up-message tolist)
  7976.               str (irc-find-message str)
  7977.               ;; kill on leading space if it exists.  ie, "tale: hi" will
  7978.               ;; send "hi" as a message not " hi".
  7979.               str (if (string-match "^ *" str)
  7980.               (substring str (match-end 0)))))
  7981.     (setq confirm (delq            ; whee.  lisp indentation is fun.
  7982.            nil
  7983.            (mapcar
  7984.             (function
  7985.              (lambda (to)
  7986.               (if (not (zerop (string-to-int to)))
  7987.               (if (string= to irc-channel)
  7988.                   (progn
  7989.                 (irc-send
  7990.                  (if (and newsrvr on-hash)
  7991.                      (concat "PRIVMSG " irc-channel " :" str)
  7992.                      (concat "MSG :" str)))
  7993.                 to)
  7994.                   ;; new in 1.2 -- you _can_ send to a channel you
  7995.                   ;; are not on
  7996.                   (irc-send (concat "PRIVMSG " to " :" str))
  7997.                   to)
  7998.               (if (not (or (string= to "*")
  7999.                        (string= to "0")))
  8000.                   (setq icw (irc-check-list (irc-recall-all
  8001.                              'irc-nicknames)
  8002.                             to)))
  8003.               (cond ((string= to "*")
  8004.                  (if (string= "0" irc-channel)
  8005.                      (progn
  8006.                        (irc-insert (concat "%%You are not"
  8007.                                " talking to any"
  8008.                                " channel."))
  8009.                        nil)
  8010.                      (irc-send
  8011.                       (if (and newsrvr on-hash)
  8012.                       (concat "PRIVMSG " irc-channel
  8013.                           " :" str)
  8014.                       (concat "MSG :" str)))
  8015.                      irc-channel))
  8016.                 ((string= to "0")
  8017.                  (irc-insert "%%You can't send to channel 0.")
  8018.                  nil)
  8019.                 ((= (length icw) 1)
  8020.                  (irc-send (concat "PRIVMSG "
  8021.                            (car icw)
  8022.                            " :"
  8023.                            str))
  8024.                  (car icw))
  8025.                 ((not icw)
  8026.                  ;; Wox! No one found, but we'll do a
  8027.                  ;; nonomatching. Try sending it anyway and
  8028.                  ;; let the server bitch if necessary.
  8029.                  ;; So don't remember this "nonmatch".
  8030.                  (irc-send (concat "PRIVMSG " to " :" str))
  8031.                  to)
  8032.                 (t (irc-insert (concat "%%Ambiguous recipient"
  8033.                                " \"%s\"; could be %s.")
  8034.                            to
  8035.                            (irc-subst-comma
  8036.                         (mapconcat
  8037.                          (function
  8038.                           (lambda (arg)
  8039.                            (concat "\"" arg "\"")))
  8040.                          icw
  8041.                          ", ")
  8042.                         "or"))
  8043.                    nil)))))
  8044.             tolist)))
  8045.     (setq confirm (let ((foo ())
  8046.             (bar confirm))
  8047.             (while (> (length bar) 0)
  8048.               (setq foo (cons
  8049.                  (concat
  8050.                   (cond
  8051.                     ((irc-is-nickname (car bar)) "user")
  8052.                     ((irc-is-channelname (car bar)) "channel")
  8053.                     ((irc-is-broadcastname (car bar)) "server")
  8054.                     (t "receiver"))
  8055.                   " "
  8056.                   (car bar))
  8057.                  foo)
  8058.                 bar (cdr bar)))
  8059.             foo))
  8060.     (let* ((rcvr (irc-subst-comma (mapconcat 'eval confirm ", ")
  8061.                   "and"))
  8062.        (data (irc-clean-up-message (format irc-msg-sent rcvr))))
  8063.       (if (and confirm irc-confirm)
  8064.       (let ((c confirm))
  8065.         (while c
  8066.           (let ((r (irc-clean-up-message (format irc-msg-sent (car c)))))
  8067.         (irc-insert "%s%s" (make-string
  8068.                     (max 0 (- (window-width
  8069.                            (get-buffer-window
  8070.                         (current-buffer)))
  8071.                           (length r)
  8072.                           1))
  8073.                     ? )
  8074.                 r)
  8075.         (setq c (cdr c)))))
  8076.       (if (not confirm)
  8077.           (irc-insert "%% Message not sent. Use /HELP for help."))))
  8078.     orig))
  8079.  
  8080.  
  8081. (defun irc-execute-oops (newto)
  8082.   "Usage: /OOPS intended-recipient
  8083. Send irc-oops to recipient(s) of last message and resend message to
  8084. 'intended-recipient'.  This command is handy when you've just sent a message
  8085. to the wrong place and you want the person/people who saw it to know that they
  8086. should just disregard it.  The message which was originally sent then gets
  8087. forwarded to its proper destination."
  8088.   (interactive '(""))
  8089.   (if (not irc-called-from-buffer)
  8090.       (progn (irc-insert "")
  8091.          (irc-insert "/OOPS")))  
  8092.   (let* ((prev (irc-find-to (car irc-history)))
  8093.      (data (concat prev irc-oops)))
  8094.     ;; first do the oops message
  8095.     (irc-execute-msg data)
  8096.     ;; then resend the original
  8097.     (if (and (string= "" newto) irc-called-from-buffer)
  8098.     (irc-insert (concat "%%No new receiver given. Oops said to %s. Not"
  8099.                 " redirected.")
  8100.             prev)
  8101.     (irc-execute-redirect newto)))
  8102.   (setq irc-idle-last-sent (irc-current-time)))
  8103.  
  8104.  
  8105. (defun irc-execute-redirect (newto)
  8106.   "Usage: /REDIRECT additional-recipient
  8107.  
  8108. Send to 'additional-recipient' the last message which you sent.  This 
  8109. command can be fairly easily duplicated using the history mechanism by hand
  8110. but it is provided to make it even easier."
  8111.   (interactive '(""))
  8112.   (if (not irc-history)
  8113.       (irc-insert "%%No message sent yet, nothing to redirect.")
  8114.       (let* ((default (if irc-default-to 
  8115.               (substring irc-default-to 0 (string-match
  8116.                                "[:;]" irc-default-to))
  8117.               ""))
  8118.          (prompt (if (string< "" default)
  8119.              (concat "(RET for "
  8120.                  (irc-nuke-whitespace
  8121.                   (concat
  8122.                    default
  8123.                    (if (string-match "\\*" default)
  8124.                        (concat "; where *=\""
  8125.                            irc-channel
  8126.                            "\""))))
  8127.                  ") ")
  8128.              ""))
  8129.          (n (irc-nuke-whitespace
  8130.          (if (and (string= "" newto) (not irc-called-from-buffer))
  8131.              (irc-read-object
  8132.               (format "Send copy of last message (%s) to whom? %s"
  8133.                   (let ((m (irc-find-message (car irc-history))))
  8134.                 (if (> (length m) 5)
  8135.                     (concat (substring m 0 5) "...")
  8136.                     m))
  8137.                   prompt)
  8138.               ""
  8139.               (irc-recall-all 'irc-nicknames))
  8140.              newto)))
  8141.          (new (if (string= "" n) default n)))
  8142.     (if (not (irc-is-receiver new))
  8143.         (irc-insert (concat "%%\"%s\" is not a valid receiver. Message not"
  8144.                 " redirected.")
  8145.             new)
  8146.         (let ((to (if (string= "" new)
  8147.               default
  8148.               (concat new ";"))))
  8149.           (setq irc-last-explicit to)
  8150.           (irc-add-to-hist
  8151.            (irc-execute-msg
  8152.         (concat to (irc-find-message (car irc-history)))))))))
  8153.   (setq irc-idle-last-sent (irc-current-time)))
  8154.  
  8155.  
  8156.  
  8157. ;; /commands for the server
  8158. (defun irc-execute-quote (msg)
  8159.   "Usage: /QUOTE string
  8160.  
  8161. This command is used to send 'string' directly to the IRC server without
  8162. any local processing.  Warning: this has the potential to screw up some
  8163. things in irc-mode, particularly if it is used to change your nickname or
  8164. to switch channels."
  8165.   (interactive '(""))
  8166.   (let ((m (if (and (string= "" msg) (not irc-called-from-buffer))
  8167.            (read-string "String to send to server: ")
  8168.            msg)))
  8169.     (cond ((string-match "^ *\\([^ ]+\\)" m)
  8170.        (let ((cmd (subfield m 1)))
  8171.          (irc-send m)
  8172.          (irc-send (concat "CLIENT-SYNCH :QUOTE " cmd))))
  8173.       (t (irc-insert "%%Nothing was sent to the IRC server."))))
  8174.   (setq irc-idle-last-sent (irc-current-time)))
  8175.  
  8176.  
  8177. (defun irc-execute-who (channel)
  8178.   "Usage: /WHO { channel | user }
  8179.  
  8180. Get a list of the users on IRC. The argument \"channel\" means to show
  8181. just the users on that channel, with * representing the current channel.
  8182. User can be any mask, ie *.se for current swedish IRCjunkies.
  8183.  
  8184. Each user is indicated on a separate line with their nickname, status,
  8185. channel, login name, host and real name. The second column, \"Stat\"
  8186. gives the status for the user, and is shown as a four letter word (:-)
  8187. according to the combination of their attributes. The possible
  8188. attributes are being an IRC operator, being a channel operator and
  8189. being marked as being away.
  8190.  
  8191.                                           Status field
  8192. A normal user having no attributes set:     (blank)
  8193. A normal user marked as being away:          Away
  8194. An IRC operator with no other attribues:     Iopr
  8195. An IRC operator marked as being away:        IoAw
  8196. A channel operator with no other attributes: Copr
  8197. A channel operator marked as being away:     CoAw
  8198. User being both IRC- and channel operator:   ICop
  8199. As above but also marked as being away:      ICAw
  8200.  
  8201. Being ignored takes precedence over all
  8202. other attributes, always shown as:           IGNR     (cf \"/HELP IGNORE\"). 
  8203.  
  8204. Users being on either no channel at all, or on channels with the mode
  8205. PRIVATE are appear with a blank \"Channel\" field. If you are
  8206. connected to a server of version 2.6, and are requesting a \"general\"
  8207. who listing (ie for users potentially on different channels), all
  8208. users \"Channel\" field will be blank.
  8209.  
  8210. An %-sign is appended to the name or number of your current
  8211. channel.
  8212.  
  8213. BE WARNED: on some servers, the operators CAN see who's on a negative channel.
  8214. On some of these servers, the channel number is disclosed, on others only
  8215. the fact that a user is on a negative channel, but not which one.
  8216. The same goes for \"private\" and \"secret\" channels.
  8217.  
  8218. If a single \"user\" is given as the argument, (ie a word starting with neither
  8219. a + nor a digit) it is taken to be the nickname of a user on IRC and more
  8220. information, if available, is given about the person.
  8221.  
  8222. If this function is called interactively then the prefix argument is used
  8223. as the channel to query.  No argument means all of them and an argument
  8224. of \"-\" or \"*\" means the current channel." 
  8225.   (interactive '(""))
  8226.   (let* ((c (if (and (string= "" channel) (not irc-called-from-buffer))
  8227.         (irc-read-object (concat "Who? "
  8228.                      (if (not (string= "0" irc-channel))
  8229.                          (concat "(Press return for "
  8230.                              irc-channel
  8231.                              ") ")
  8232.                          ""))
  8233.                  ""
  8234.                  (irc-get-channels-and-nicks-and-servers))
  8235.         channel))
  8236.      (c2 (irc-nuke-whitespace c))
  8237.      (chan (cond ((or (string= "" c2)
  8238.               (string= "*" c2))
  8239.               irc-channel)
  8240.              (t c2))))
  8241.     (if (string= "0" chan)
  8242.     (irc-insert (concat "%%No argument (or argument 0) given to /WHO,"
  8243.                 " this would certainly disconnect your"
  8244.                 " IRC-session. You can use /QUOTE WHO 0 if you"
  8245.                 " *really* want to do this."))
  8246.       (let ((s (irc-recall-all 'irc-services)))
  8247.     (irc-forget-all 'irc-nicknames)
  8248.     (irc-remember irc-nick-used 'irc-nicknames)
  8249.     (while (and (listp s) s)
  8250.       (irc-remember (car s) 'irc-nicknames)
  8251.       (setq s (cdr s)))
  8252.     (if (not irc-called-from-buffer)
  8253.         (progn (irc-insert "")
  8254.            (irc-insert "/WHO %s" chan)))
  8255.     (if (and irc-called-from-buffer (irc-is-nickname chan))
  8256.         (irc-execute-whois chan)
  8257.       (irc-send (concat "WHO " chan))))
  8258.       (setq irc-idle-last-sent (irc-current-time)))))
  8259.  
  8260.  
  8261. (defun irc-execute-whois (user)
  8262.   "Usage: /WHOIS user
  8263.  
  8264. Get a two line description of who and where \"user\" is.  If user is not
  8265. provided it is read from the minibuffer with a completing-read.
  8266. If * is given instead of a user name, you will be informed about ALL users.
  8267.  
  8268. BUG: The list of users used when * is given may be somewhat obsolete,
  8269. therefore first give a NAMES command."
  8270.   (interactive '(""))
  8271.   (let ((wholist (irc-recall-all 'irc-nicknames)))
  8272.     (if (and (string-match "^ *$" user) (not irc-called-from-buffer))
  8273.     (setq user (irc-read-object "Who is who? "
  8274.                     user
  8275.                     wholist)))
  8276.     (if (string< "" user)
  8277.     (progn (if (not irc-called-from-buffer)
  8278.            (progn (irc-insert "")
  8279.               (irc-insert "/WHOIS %s" user)))
  8280.            (irc-send (concat "WHOIS " user)))
  8281.     (irc-insert "%%Who is who? No nick given.")))
  8282.   (setq irc-idle-last-sent (irc-current-time)))
  8283.  
  8284.  
  8285. (defun irc-execute-motd (server)
  8286.   "Usage: /MOTD [ server ]
  8287.  
  8288. Tells the message of the day at the server."
  8289.   (interactive '(""))
  8290.   (let ((host (if (string= "" server)
  8291.           (if (not irc-called-from-buffer)
  8292.               (irc-read-object
  8293.                "Get message of the day for which host? "
  8294.                ""
  8295.                (irc-recall-all 'irc-servernames))
  8296.               "")
  8297.           server)))
  8298.     (if (string-match "^ *\\([^: ]*\\)" host)
  8299.     (let ((host (substring host (match-beginning 1) (match-end 1))))
  8300.       (if (not irc-called-from-buffer)
  8301.           (progn (irc-insert "")
  8302.              (irc-insert "/MOTD %s" host)))
  8303.       (irc-send (concat "MOTD " host)))
  8304.     (irc-insert (concat "%%Internal error in function irc-execute-motd,"
  8305.                 " please try another syntax and notify %s"
  8306.                 " by email.")
  8307.             irc-hacker)))
  8308.   (setq irc-idle-last-sent (irc-current-time)))
  8309.  
  8310.  
  8311. (defun irc-execute-version (server)
  8312.   "Usage: /VERSION [ server | user ]
  8313.  
  8314. Shows the version of the server, or of a user. If the argument looks
  8315. like a nickname, that user's client is queried using CTCP (client to
  8316. client protocol) about which client it is and which version of it it
  8317. is. If the queried client doesn't understand CTCP, no answer will
  8318. follow."
  8319.   (interactive '(""))
  8320.   (let* ((host (irc-nuke-whitespace
  8321.         (if (string= "" server)
  8322.             (if (not irc-called-from-buffer)
  8323.             (irc-read-object
  8324.              "Get version of which server/nick? "
  8325.              ""
  8326.              (irc-get-channels-and-nicks-and-servers))
  8327.             "")
  8328.             server)))
  8329.      (host (if (string= "" host) irc-server host))
  8330.      (hst (if (string= "*" host) irc-channel host)))
  8331.     (if (string-match "^ *\\([^: ]*\\)" hst)
  8332.     (let ((h (substring hst (match-beginning 1) (match-end 1))))
  8333.       (cond ((or (irc-is-nickname h)
  8334.              (irc-is-channelname h))
  8335.          (if (not irc-called-from-buffer)
  8336.              (progn (irc-insert "")
  8337.                 (irc-insert (concat "/VERSION " h))))
  8338.          (irc-insert (concat "%sQuerying client of user%s %s for"
  8339.                      " version of client%s")
  8340.                  irc-msg-info-pre
  8341.                  (if (irc-is-channelname h) "s on channel" "")
  8342.                  h
  8343.                  irc-msg-info-post)
  8344.          (irc-send (concat "PRIVMSG " h " :\001"
  8345.                    (irc-ctcp-enquote "VERSION")
  8346.                    "\001")))
  8347.         (t (if (not irc-called-from-buffer)
  8348.                (progn (irc-insert "")
  8349.                   (irc-insert "/VERSION %s" h)))
  8350.            (irc-send (concat "VERSION " h)))))
  8351.     (irc-insert "%%Give only one word please. \"%s\" is not valid."
  8352.             hst)))
  8353.   (setq irc-idle-last-sent (irc-current-time)))
  8354.  
  8355.  
  8356. (defun irc-execute-list (channel)
  8357.   "Usage: /LIST [channel]
  8358.  
  8359. Get a list of the discussions that are on IRC. If a channel is given,
  8360. only the topic for that channel is shown. A * denotes your current
  8361. channel, if any. An %-sign is appended to your current channel's name
  8362. or number."
  8363.   (interactive '(""))
  8364.   (if (not irc-called-from-buffer)
  8365.       (progn (irc-insert "")
  8366.          (irc-insert "/LIST %s" channel)))
  8367.   (irc-send (concat "LIST " channel))
  8368.   (setq irc-idle-last-sent (irc-current-time)))
  8369.  
  8370.  
  8371. (defun irc-execute-links (mask)
  8372.   "Usage: /LINKS [ mask ]
  8373.  
  8374. Show the names of all the servers which can communicate with your server.
  8375. The links can go down isolating different parts of the IRC-net, so this
  8376. is a good way to find out how extensive it is at the moment.
  8377.  
  8378. Given a mask like *.se, only server names matching the mask are displayed."
  8379.   (interactive '(""))
  8380.   (let ((m (if (and (string= "" mask) (not irc-called-from-buffer))
  8381.            (irc-read-object (concat "Check for which servers? (RET for"
  8382.                     " all, *.SE for swedish servers etc) ")
  8383.                 ""
  8384.                 (irc-recall-all 'irc-servernames))
  8385.            mask)))
  8386.     (cond ((string-match "^ *\\*? *$" m)
  8387.        (irc-forget-all 'irc-servernames)
  8388.        (irc-forget-all 'irc-linksinfo)))
  8389.     (if (not irc-called-from-buffer)
  8390.     (progn (irc-insert "")
  8391.            (irc-insert "/LINKS %s" m)))
  8392.     (irc-send (concat "LINKS " m)))
  8393.   (setq irc-idle-last-sent (irc-current-time)))
  8394.  
  8395.  
  8396. (defun irc-execute-lusers (mask)
  8397.   "Usage: /LUSERS [servermask]
  8398.  
  8399. Get the number of users and servers on your IRC network. 
  8400.  
  8401. There is a optional argument you can use if you only want
  8402. to see the count of some part of the IRCnet. For instance,
  8403. to see how many swedish users are on, try /lusers *.se"
  8404.   (interactive '(""))
  8405.   (let* ((mask (irc-nuke-whitespace mask)))
  8406.     (if (not irc-called-from-buffer)
  8407.     (progn (irc-insert "")
  8408.            (irc-insert (format "/LUSERS %s" mask))))
  8409.     (irc-send (concat "LUSERS " mask))
  8410.     (setq irc-idle-last-sent (irc-current-time))))
  8411.  
  8412.  
  8413. (defun irc-execute-admin (server)
  8414.   "Usage: /ADMIN [ server ]
  8415.  
  8416. Get information about the IRC administrator for 'server'; if server is not
  8417. supplied just query for the server to which you are connected."
  8418.   (interactive '(""))
  8419.   (let ((s (if (and (string= "" server) (not irc-called-from-buffer))
  8420.            (irc-read-object "Administrative info about which server? "
  8421.                 ""
  8422.                 (irc-recall-all 'irc-servernames))
  8423.            server)))
  8424.     (if (not irc-called-from-buffer)
  8425.     (progn (irc-insert "")
  8426.            (irc-insert "/ADMIN %s" s)))
  8427.     (irc-send (concat "ADMIN " s)))
  8428.   (setq irc-idle-last-sent (irc-current-time)))
  8429.  
  8430.  
  8431. (defun irc-execute-time (&optional server)
  8432.   "Usage: /TIME [ server ]
  8433.  
  8434. Get the current time on 'server'; is no server is provided use the one to which
  8435. you are connected.  When called with a interactively with a prefix-argument
  8436. the server name is read using the minibuffer.
  8437.  
  8438. Querying other servers can be handy given that people on IRC are spread out
  8439.  from the west coast of the United States to Finland.  The question \"What
  8440. time is it in Finland?\" comes up so frequently that an alias -- /TF -- has
  8441. been provided by default to get the answer.  This alias should work as long
  8442. as tut.fi is connected to your IRC-net."
  8443.   (interactive '(""))
  8444.   (let ((s (if (and (stringp server)
  8445.             (string= "" server)
  8446.             (not irc-called-from-buffer))
  8447.            (irc-read-object "Get the time at which server? "
  8448.                 ""
  8449.                 (irc-recall-all 'irc-servernames))
  8450.            server)))
  8451.     (if (and (stringp server) (not irc-called-from-buffer))
  8452.     (progn (irc-insert "")
  8453.            (irc-insert "/TIME %s" s)))
  8454.     (irc-send (concat "TIME " s)))
  8455.   (setq irc-idle-last-sent (irc-current-time)))
  8456.  
  8457.  
  8458. (defun irc-execute-join (channel)
  8459.   "Usage: /JOIN channel [mode]
  8460.  
  8461. Join \"channel\" on IRC.  If channel is not provided it is requested
  8462. in the minibuffer; when called interactively, the channel is prompted
  8463. for in the minibuffer.  Use /LEAVE to exit the channel.
  8464.  
  8465. You can supply an initial mode for the channel. If the channel didn't
  8466. exist before you joined it, the channel will be sat to the supplied mode.
  8467. If the channel already existed, the mode will be ignored by the server.
  8468.  
  8469. One can be listening on several channels at once. Up to 10 channels
  8470. can be listened to at any single time, either 10 #channels, or 1 old
  8471. style (either a +channel or a nummeric channel) and 9 #channels. Use
  8472. /JOIN to join (ie start listening and talkinging to) a channel and
  8473. /LEAVE to stop listening to a channel. If you /LEAVE the channel you
  8474. were talking to, you will end up not talking to any channel; just use
  8475. /JOIN again to remedy that situation.  There is no way yet to start
  8476. listening to a channel without choosing that channel as the one you
  8477. will talk to. Of course, another /JOIN will help..."
  8478.  
  8479.   (interactive '(""))
  8480.   (let* ((pair (cond
  8481.          ((string-match "^ *\\([^ ]+\\) +\\([^ ]\\)" channel)
  8482.           (cons (subfield channel 1)
  8483.             (concat (subfield channel 2)
  8484.                 (substring channel (match-end 0)))))
  8485.          ((string-match "^ *\\([^ ]+\\) *$" channel)
  8486.           (cons (subfield channel 1) ""))
  8487.          (t (cons "" ""))))
  8488.      (c (car pair))
  8489.      (m (cdr pair))
  8490.      (subchnls (irc-recall-all 'irc-subscribed-channels))
  8491.      (chn (irc-nuke-whitespace
  8492.            (if (and (string= c "")
  8493.             (not irc-called-from-buffer))
  8494.            (irc-read-object "Channel to join? "
  8495.                     ""
  8496.                     subchnls)
  8497.            c)))
  8498.      (mode (irc-nuke-whitespace
  8499.         (if (and (string= m "")
  8500.              (not irc-called-from-buffer)
  8501.              (not (irc-recall chn 'irc-subscribed-channels)))
  8502.             (irc-read-object (format
  8503.                       "Initial mode for channel \"%s\"? "
  8504.                       chn)
  8505.                      ""
  8506.                      '("A combination of +-biklmnopst"))
  8507.             m)))
  8508.      (digit-start (string-match "^-?[0-9]" chn)))
  8509.     (if (string= "" chn) ; well, so much for that 
  8510.     (irc-insert "%%No channel given. continuing talking to %s."
  8511.             irc-channel)
  8512.     (let* ((newsrvr (irc-server-has-multijoinable-channels)) 
  8513.            (mtch (irc-recall chn 'irc-subscribed-channels)))
  8514.       (cond ((string= "0" chn) 
  8515.          (setq irc-channel "0")
  8516.          (irc-show-subscribed-channels)) 
  8517.         ((and (not mtch)
  8518.               (not (irc-is-channelname chn)))
  8519.          (irc-insert (concat "%%Warning, that channel name (%s) looks" 
  8520.                      " strange, but will try to /join it"
  8521.                      " anyway. You might be in for a surprise,"
  8522.                      " thought.")
  8523.                  chn)
  8524.          (if (not irc-called-from-buffer) 
  8525.              (progn (irc-insert "")
  8526.                 (irc-insert "/JOIN %s %s" chn mode))) 
  8527.          (irc-send (format "%s %s %s"
  8528.                    (if newsrvr "JOIN " "CHANNEL ")
  8529.                    chn
  8530.                    mode)))
  8531.         (mtch (setq irc-channel mtch)
  8532.               (if (not irc-called-from-buffer) 
  8533.               (progn (irc-insert "")
  8534.                  (irc-insert "/JOIN %s" mtch)))
  8535.               (irc-show-subscribed-channels))
  8536.         (t (if (not irc-called-from-buffer)
  8537.                (progn (irc-insert "")
  8538.                   (irc-insert "/JOIN %s %s" chn mode)))
  8539.            (irc-send (format "%s %s %s"
  8540.                      (if newsrvr "JOIN " "CHANNEL ")
  8541.                      chn
  8542.                      mode))))))
  8543.     (setq irc-msg-cont-used
  8544.       (if (string= "0" chn) ;On private?
  8545.           irc-msg-cont 
  8546.           (make-string (1- (length (concat irc-msg-cont chn)))
  8547.                (string-to-char " ")))) )
  8548.   (setq irc-idle-last-sent (irc-current-time)))
  8549.  
  8550.  
  8551. (defun irc-execute-leave (channel)
  8552.   "Usage: /LEAVE [channel]
  8553.  
  8554. Leave your current channel (or a selected one from the set of joined channels,
  8555. if you're using a v2.6 or later server). Don't join another channel.
  8556.  
  8557. Also see /HELP JOIN."
  8558.   (interactive '(""))
  8559.   (let* ((c (if (and (string-match "^ *$" channel)
  8560.              (not irc-called-from-buffer))
  8561.         (irc-read-object (concat "Leave which channel? (0 for ALL"
  8562.                      (if (string= "0" irc-channel)
  8563.                          ") "
  8564.                          (concat ", RET for "
  8565.                              irc-channel
  8566.                              ") ")))
  8567.                  ""
  8568.                  (irc-recall-all 'irc-subscribed-channels))
  8569.         channel))
  8570.      (chan (irc-nuke-whitespace
  8571.         (if (and (not (string= "0" irc-channel))
  8572.              (or (string= "*" c) (string= "" c)))
  8573.             irc-channel
  8574.           (if (and (string= "" c)
  8575.                (not irc-called-from-buffer))
  8576.               (message "%%No channel chosen"))
  8577.           c))))
  8578.     (if (string= "0" chan)
  8579.     (progn
  8580.       (let ((lst (irc-recall-all 'irc-subscribed-channels))
  8581.         (irc-multiple-leave-in-progress t)
  8582.         (irc-called-from-buffer t))
  8583.         (while (not (null lst))
  8584.           (irc-send (concat "PART " (car lst)))
  8585.           (setq lst (cdr lst))))
  8586.       (irc-show-subscribed-channels))
  8587.     (if (not irc-called-from-buffer)
  8588.         (progn (irc-insert "")
  8589.            (irc-insert "/LEAVE %s" chan)))
  8590.     (if (string< "" chan)
  8591.         (progn (irc-insert "%sLeaving channel %s%s"
  8592.                    irc-msg-info-pre chan irc-msg-info-post)
  8593.            (if (irc-server-has-multijoinable-channels)
  8594.                (irc-send (concat "PART " chan))
  8595.                (irc-send "CHANNEL 0")))
  8596.         (irc-insert (concat "%%Leave which channel? No channel given. Try"
  8597.                 " /MEMBERSHIPS")))))
  8598.   (setq irc-idle-last-sent (irc-current-time)))
  8599.  
  8600.  
  8601. (defun irc-execute-nick (name)
  8602.   "Usage: /NICKNAME name
  8603.  
  8604. Change your nickname in IRC.  A nickname can contain alphanumeric characters,
  8605. underscores (_), hyphens (-) or the special characters left brace ({), right
  8606. brace (}), vertical bar (|), left bracket ([), right bracket (]) and back
  8607. slash (\\). These special character are alphabetic characters in some
  8608. languages like the scandinavian ones.  The name cannot start with a hyphen or
  8609. number and only the first nine characters are used.
  8610.  
  8611. Unfortunately, due to the way confirmation from the servers work, it might be
  8612. falsely reported that your nickname was successfully changed when it was not.
  8613. The server will come back and say so and finally irc-mode will wise-up and
  8614. note that your nickname was not changed.
  8615.  
  8616. All the above things change from server version to server version, so they may
  8617. or may not work. Try it."
  8618.   (interactive '(""))
  8619.   (let ((newnick (if (and (string= "" name) (not irc-called-from-buffer))
  8620.              (irc-nuke-whitespace (read-string "New nickname? "))
  8621.              name)))
  8622.     (if (string= "" newnick)
  8623.     (irc-insert "%sNickname not changed%s"
  8624.             irc-msg-info-pre
  8625.             irc-msg-info-post)
  8626.     (progn
  8627.       (if (not irc-called-from-buffer)
  8628.           (progn (irc-insert "")
  8629.              (irc-insert "/NICK %s" newnick)))
  8630.       (irc-insert "%sTrying to change your nickname to \"%s\"%s"
  8631.               irc-msg-info-pre
  8632.               newnick
  8633.               irc-msg-info-post)
  8634.       (set-buffer-modified-p (buffer-modified-p))
  8635.       (irc-send (concat "NICK " newnick)))))
  8636.   (setq irc-idle-last-sent (irc-current-time)))
  8637.  
  8638.  
  8639. (defun irc-execute-quit (text)
  8640.   "Usage: /QUIT [reason]
  8641.  
  8642. Exit IRC.  The connection is closed but the buffer is left behind.
  8643. If you want, you can give a reason for quitting IRC."
  8644.   (interactive '(""))
  8645.   (if (not irc-called-from-buffer)
  8646.       (progn (if (string-match "^ *$" text)
  8647.          (setq text (yow)))
  8648.          (let ((parias '("\n" "  " "\t"))
  8649.            (ok nil)
  8650.            (n 0))
  8651.            (while (not ok)
  8652.          (let ((p parias))
  8653.            (while p
  8654.              (while (string-match (car p) text)
  8655.                (setq text (concat (substring text
  8656.                              0
  8657.                              (match-beginning 0))
  8658.                       " "
  8659.                       (substring text (match-end 0)))))
  8660.              (setq p (cdr p))))
  8661.          (setq n (1+ n))
  8662.          (if (> n 10)
  8663.              (setq text ""))
  8664.          (if (< (length text) 80)
  8665.              (setq ok t)
  8666.              (setq text (yow)))))
  8667.          (irc-insert "")
  8668.          (irc-insert "/QUIT %s" text)))
  8669.   (irc-send (concat "QUIT :" text))
  8670.   (sit-for 2)                ;Give server a chance to react.
  8671.   (let ((proc (get-buffer-process (current-buffer))))
  8672.     (cond ((processp proc)
  8673.        (irc-sentinel proc "finished\n")
  8674.        (delete-process proc))))
  8675.   (setq irc-idle-last-sent (irc-current-time)))
  8676.  
  8677.  
  8678. (defun irc-execute-away (text)
  8679.   "Usage: /AWAY [message]
  8680.  
  8681. Mark yourself as away, giving TEXT to people who send you private messages.
  8682. Without any arguments it will just insert a message about your current status."
  8683.   (interactive '(""))
  8684.   (let ((reason (if (and (string= "" text) (not irc-called-from-buffer))
  8685.             (read-string "Reason to be away? ")
  8686.             text)))
  8687.     (if (string= "" reason)
  8688.     (if irc-away
  8689.         (let ((pre (concat irc-msg-info-pre "You are ")))
  8690.           (irc-insert (concat "%smarked as being away: \"%s\", "
  8691.                   "use /HERE to remove the mark%s")
  8692.               pre
  8693.               (substring irc-away 2 -1)
  8694.               irc-msg-info-post))
  8695.         (irc-insert "%sYou are not currently marked as being away%s"
  8696.             irc-msg-info-pre
  8697.             irc-msg-info-post))
  8698.     (if (not irc-called-from-buffer)
  8699.         (progn (irc-insert "")
  8700.            (irc-insert "/AWAY %s" reason)))
  8701.     (irc-send (concat "AWAY :" reason))
  8702.     (setq irc-away (concat " [" reason "]")))
  8703.     (set-buffer-modified-p (buffer-modified-p)))
  8704.   (setq irc-idle-last-sent (irc-current-time)))
  8705.  
  8706.  
  8707. (defun irc-execute-here (cruft)
  8708.   "Usage: /HERE
  8709.  
  8710. Mark yourself as present (ie, not \"away\") on IRC.  Any arguments to this
  8711. command are ignored."
  8712.   (interactive '(""))
  8713.   (if (not irc-called-from-buffer)
  8714.       (progn (irc-insert "")
  8715.          (irc-insert "/HERE")))
  8716.   (irc-send "AWAY")
  8717.   (setq irc-away nil)
  8718.   (set-buffer-modified-p (buffer-modified-p))
  8719.   (setq irc-idle-last-sent (irc-current-time)))
  8720.  
  8721.  
  8722. (defun irc-execute-topic (topic)
  8723.   "Usage: /TOPIC channel [topic ...]
  8724.       or: /TOPIC [topic ...]
  8725.  
  8726. Make 'topic' the description of the named channel; * for channelname means
  8727. the current channel you're talking to.
  8728.  
  8729. With no topic, doesn't change the topic but only inspects it.
  8730.  
  8731. If no channel is given (and the first word of the topic doesn't looks like
  8732. a channel name), the command operates on the current channel you're talking to.
  8733. "
  8734.   (interactive '(""))
  8735.   (let* ((top1 (cond ((and (string= "" topic) (not irc-called-from-buffer))
  8736.               (read-string (concat "Topic for channel "
  8737.                        irc-channel
  8738.                        "? (RET to check) ")))
  8739.              (t topic)))
  8740.      (top (if (string-match "^\\([#&][^ :]+\\) *" top1)
  8741.           (substring top1 (match-end 0))
  8742.           top1))
  8743.      (chn (if (string-match "^\\([#&][^ :]+\\) *" top1)
  8744.           (subfield top1 1)
  8745.           irc-channel)))
  8746.     (if (not irc-called-from-buffer)
  8747.     (progn (irc-insert "")
  8748.            (irc-insert "/TOPIC %s %s" chn top)))
  8749.     (cond ((string= "0" chn)
  8750.        (irc-insert "%%You aren't on any channel."))
  8751.       ((and (irc-is-multijoinable-channel chn)
  8752.         (irc-server-has-settable-topic-on-multijoinable-channel))
  8753.        (if (string-match "^ *$" top)
  8754.            (irc-send (concat "TOPIC " chn))
  8755.            (irc-send (concat "TOPIC " chn " :" top))))
  8756.       ((irc-is-multijoinable-channel irc-channel)
  8757.        (irc-insert "%%Can't set the topic of a #channel."))
  8758.       (t (irc-send (concat "TOPIC :" top)))))
  8759.   (setq irc-idle-last-sent (irc-current-time)))
  8760.  
  8761.  
  8762. (defun irc-execute-oper (oper)
  8763.   "Usage: /OPER [ name [ password ]]
  8764.  
  8765. Attempt to become an IRC Operator.  Can take the name of the operator
  8766. and the password as arguments.  If name is missing then it will be read
  8767. from the minibuffer; if password is missing it will be read and hidden
  8768. in the minibuffer.
  8769.  
  8770. If you become an operator then the word \"operator\" will appear in the
  8771. minibuffer along with the mode name."
  8772.   (interactive '(""))
  8773.   (let* ((pair (cond
  8774.          ((string-match "^ *\\([^: ]+\\) +" oper)
  8775.           (cons (subfield oper 1) (substring oper (match-end 0))))
  8776.          ((string-match "^ *\\([^: ]+\\) *$" oper)
  8777.           (cons (subfield oper 1) ""))
  8778.          (t (cons "" ""))))
  8779.      (n (car pair))
  8780.      (n1 (if (string= "" n)
  8781.          (read-string (concat "Operator name at server "
  8782.                       (upcase irc-server)
  8783.                       "? "))
  8784.          n))
  8785.      (name (irc-nuke-whitespace n1))
  8786.      (p (irc-nuke-whitespace (cdr pair)))
  8787.      (p1 (if (and (string= "" p) (string< "" name))
  8788.          (irc-read-passwd (concat "Password for operator "
  8789.                       name
  8790.                       " at server "
  8791.                       (upcase irc-server)
  8792.                       "? "))
  8793.          p))
  8794.      (password (irc-nuke-whitespace p1)))
  8795.     (cond ((string= "" name)
  8796.        (irc-insert "%%No operator name given."))
  8797.       ((string= "" password)
  8798.        (irc-insert "%%No password given."))
  8799.       (t (if (not irc-called-from-buffer)
  8800.          (progn (irc-insert "")
  8801.             (irc-insert "/OPER ...")))
  8802.          (irc-send (concat "OPER " name " " password)))))
  8803.   (setq irc-idle-last-sent (irc-current-time)))
  8804.  
  8805.  
  8806. (defun irc-execute-summon (user)
  8807.   "Usage: /SUMMON login-name@server
  8808.  
  8809. Summon a user not on IRC to join IRC.  The argument provided may either be
  8810. a user name on the local machine or user@server, where server is another
  8811. machine on the IRC-net.  The user must be signed on to the specified server."
  8812.   (interactive '(""))
  8813.   (let* ((pair (cond ((string-match (concat "^ *\\([^ @]*\\) *@ *"
  8814.                         "\\([^ @]*\\) *$")
  8815.                     user)
  8816.               (cons
  8817.                (substring user (match-beginning 1) (match-end 1))
  8818.                (substring user (match-beginning 2) (match-end 2))))
  8819.              ((string-match "^ *\\([^ @]*\\) *$" user)
  8820.               (cons
  8821.                (substring user (match-beginning 1) (match-end 1))
  8822.                ""))
  8823.              (t (cons "" ""))))
  8824.      (login (irc-nuke-whitespace
  8825.          (if (and (string= "" (car pair)) (not irc-called-from-buffer))
  8826.              (read-string "Login-name of person to summon? ")
  8827.              (car pair))))
  8828.      (s (irc-nuke-whitespace
  8829.          (if (and (not (string= "" login))
  8830.               (string= "" (cdr pair))
  8831.               (not irc-called-from-buffer))
  8832.          (irc-read-object (format "Server \"%s\" is on? " login)
  8833.                   ""
  8834.                   (irc-recall-all 'irc-servernames))
  8835.          (cdr pair))))
  8836.      (server (if (string= "" s) irc-server s)))
  8837.     (if (string= "" login)
  8838.     (irc-insert "%%No login name given.")
  8839.     (progn (if (not irc-called-from-buffer)
  8840.            (progn (irc-insert "")
  8841.               (irc-insert "/SUMMON %s@%s" login server)))
  8842.            (irc-send (concat "SUMMON " login "@" server)))))
  8843.   (setq irc-idle-last-sent (irc-current-time)))
  8844.  
  8845.  
  8846. (defun irc-execute-users (host)
  8847.   "Usage: /USERS [ server ]
  8848.  
  8849. Get a list of the users signed on to \"server\".  If no server name is provided
  8850. then the server to which you are connected is used.  When called interactively
  8851. a prefix argument means to prompt for the server to query."
  8852.   (interactive '(""))
  8853.   (let* ((h (irc-nuke-whitespace
  8854.          (if (and (string= "" host) (not irc-called-from-buffer))
  8855.          (irc-read-object (format (concat "List users on which host?"
  8856.                           " (RET for %s) ")
  8857.                       irc-server)
  8858.                   ""
  8859.                   (irc-recall-all 'irc-servernames))
  8860.          host)))
  8861.      (hst (if (string= "" h) irc-server h)))
  8862.     (if (not irc-called-from-buffer)
  8863.     (progn (irc-insert "")
  8864.            (irc-insert "/USERS %s" hst)))
  8865.     (irc-send (concat "USERS " hst)))
  8866.   (setq irc-idle-last-sent (irc-current-time)))
  8867.  
  8868.  
  8869. (defun irc-execute-ignore (user)
  8870.   "Usage: /IGNORE username@host [event]
  8871.  
  8872. Used to ignore a user. The first argument is a specification of whose messages
  8873. to ignore. The second specifies which kind of messages should be ignored from
  8874. that particular user.
  8875.  
  8876. When specifying a user, you can give either just the user's login name at the
  8877. remote site (you can see what it is by doing a /whois), or you can give the
  8878. user's login name followed by a @ and the name of the user's and the host of
  8879. the user (i.e. the name of host the user's client is running on). You can give
  8880. a * instead of a username to ignore everyone at the given client machine.
  8881.  
  8882. One can either ignore all signs of the user, or just certain events. The events
  8883. include
  8884.     CTCP-ANSWER = Don't display any client to client protocol answers (they
  8885.                   *might* be spurios). Also, don't react on erronous answers.
  8886.     CTCP-QUERY  = Neither display nor answer any client to client protocoll
  8887.                   questions from the user.
  8888.     INVITE      = Don't display 
  8889.     JOIN
  8890.     NICK
  8891.     NOTICE
  8892.     PART
  8893.     PRIVMSG
  8894.     QUIT
  8895.     channel
  8896.     
  8897. THIS IS ALL NOT YET IMPLEMENTED.
  8898.  
  8899. "
  8900.   (interactive '(""))
  8901.   (let ((usr (irc-nuke-whitespace
  8902.           (if (and (string= "" user) (not irc-called-from-buffer))
  8903.           (irc-read-object "Ignore which user? (RET to view) "
  8904.                    user
  8905.                    (irc-recall-all 'irc-nicknames))
  8906.           user))))
  8907.     (if (string= "" usr)
  8908.     (if (not (irc-nothing-remembered-p 'irc-ignored-ppl))
  8909.         (irc-insert "%sYou are currently ignoring %s%s"
  8910.             irc-msg-info-pre
  8911.             (irc-subst-comma (mapconcat
  8912.                       'eval
  8913.                       (irc-recall-all 'irc-ignored-ppl)
  8914.                       ", ")
  8915.                      "and")
  8916.             irc-msg-info-post)
  8917.         (irc-insert "%sYou are not ignoring anyone%s"
  8918.             irc-msg-info-pre
  8919.             irc-msg-info-post))
  8920.     (progn (irc-remember usr 'irc-ignored-ppl)
  8921.            (irc-insert "%sYou are now ignoring %s%s"
  8922.                irc-msg-info-pre
  8923.                usr
  8924.                irc-msg-info-post))))
  8925.   (setq irc-idle-last-sent (irc-current-time)))
  8926.  
  8927.  
  8928. (defun irc-execute-info (nick)
  8929.   "Usage: /INFO nick
  8930.  
  8931. With * as the argument, show some information about who built IRC.
  8932. Else query a users client and show the information she/he has given
  8933. about her/himself. With no argument, show the information you have
  8934. given about yourself. You can set the information with the command
  8935. /USERINFO."
  8936.   (interactive '(""))
  8937.   (let* ((name (irc-nuke-whitespace
  8938.         (if (and (string= "" nick) (not irc-called-from-buffer))
  8939.             (irc-read-object
  8940.              (concat "Info for which user or server? (RET"
  8941.                  " for yourself, * for server program)"
  8942.                  " ")
  8943.              ""
  8944.              (irc-get-names-and-servers))
  8945.             nick))))
  8946.     (cond ((and (string= "" name)
  8947.         (stringp irc-userinfo))
  8948.        (let* ((pre (concat irc-msg-info-pre "You have "))
  8949.           (irc-msg-cont-used (make-string (length pre) ? )))
  8950.          (irc-insert (concat "%sgiven the information \"%s\" about"
  8951.                  " yourself. Use /USERINFO to change it."
  8952.                  " (Warning: /USERINFO with no argument will"
  8953.                  " clear the information)%s")
  8954.              pre
  8955.              irc-userinfo
  8956.              irc-msg-info-post)))
  8957.       ((string= "" name)
  8958.        (let* ((pre (concat irc-msg-info-pre "You haven't "))
  8959.           (irc-msg-cont-used (make-string (length pre) ? )))
  8960.          (irc-insert (concat "%sgiven any information about"
  8961.                  " yourself yet. Use /USERINFO to do so%s")
  8962.              pre
  8963.              irc-msg-info-post)))
  8964.       ((string= "*" name)
  8965.        (if (not irc-called-from-buffer)
  8966.            (progn (irc-insert "")
  8967.               (irc-insert "/INFO *")))
  8968.        (irc-send "INFO"))
  8969.       ((irc-is-receiver name)
  8970.        (if (not irc-called-from-buffer)
  8971.            (progn (irc-insert "")
  8972.               (irc-insert (concat "/INFO " name))))
  8973.        (irc-insert (concat "%sQuerying client of user %s for user supplied"
  8974.                    " information%s")
  8975.                irc-msg-info-pre name irc-msg-info-post)
  8976.        (irc-send (format "WHOIS %s %s" name name)) ;Get names servers idea
  8977.                     ;of names idle time.
  8978.        (irc-send
  8979.         (concat "PRIVMSG "
  8980.             name
  8981.             " :\001FINGER\001"
  8982.             "\001VERSION\001"
  8983.             "\001USERINFO\001"
  8984.             "\001SOURCE\001")))
  8985.       ((irc-is-hostname name)
  8986.        (if (not irc-called-from-buffer)
  8987.            (progn (irc-insert "")
  8988.               (irc-insert (concat "/ADMIN " name))))
  8989.        (irc-send (concat "ADMIN " name)))
  8990.       (t (irc-insert "%%Can't be a users nickname: \"%s\"." name))))
  8991.   (setq irc-idle-last-sent (irc-current-time)))
  8992.  
  8993.  
  8994. (defun irc-execute-userinfo (information)
  8995.   "Usage: /USERINFO [information]
  8996.  
  8997. Set some information (any text you want) to be given out to anybody
  8998. querying this client for it. With no argument, remove all information
  8999. you have given about yourself, making further queries \"draw a
  9000. blank\". You can use /INFO to query other clients. Be warned though,
  9001. other clients may or may not know of this query so you may sometimes
  9002. get back no answer or strange responses."
  9003.   (interactive '(""))
  9004.   (let ((info (if (and (string= "" information) (not irc-called-from-buffer))
  9005.           (read-string (concat "What information do you wish to"
  9006.                        " disclose? (RET to remove) "))
  9007.           information)))
  9008.     (let ((inf (irc-nuke-whitespace info)))
  9009.       (cond ((string= "" inf)
  9010.          (setq irc-userinfo nil)
  9011.          (irc-insert "%sCleared your information string%s"
  9012.              irc-msg-info-pre irc-msg-info-post))
  9013.         (t (setq irc-userinfo inf)
  9014.            (irc-insert "%sThe information string is: \"%s\"%s"
  9015.                irc-msg-info-pre
  9016.                irc-userinfo
  9017.                irc-msg-info-post)))))
  9018.   (setq irc-idle-last-sent (irc-current-time)))
  9019.  
  9020.  
  9021. (defun irc-execute-kill (user-etc)
  9022.   "Usage: /KILL user comment
  9023.  
  9024. Forcibly remove a user from IRC. The mandotory comment will be displayed to
  9025. the victim and to all the IRC operators online. The topic should be in English,
  9026. which after all is the lingua franca of IRC.
  9027.  
  9028. This command is reserved for IRC operators."
  9029.   (interactive '(""))
  9030.   (let* ((pair (cond ((string-match "^ *\\([^ ]+\\) +\\(.\\|\n\\)+ *$"
  9031.                     user-etc)
  9032.               (cons (subfield user-etc 1) (subfield user-etc 2)))
  9033.              ((string-match "^ *\\([^ ]+\\) *$" user-etc)
  9034.               (cons (subfield user-etc 1) ""))
  9035.              (t (cons "" ""))))
  9036.      (u (irc-nuke-whitespace (car pair)))
  9037.      (user (irc-nuke-whitespace
  9038.         (if (and (string= "" u) (not irc-called-from-buffer))
  9039.             (irc-read-object "Nuke which user? "
  9040.                      ""
  9041.                      (irc-recall-all 'irc-nicknames))
  9042.             u)))
  9043.      (c (irc-nuke-whitespace (cdr pair)))
  9044.      (comm (irc-nuke-whitespace
  9045.         (if (and (string= "" c)
  9046.              (string< "" user)
  9047.              (not irc-called-from-buffer))
  9048.             (read-string "Comment? (In English please) ")
  9049.             c))))
  9050.     (if (string< "" user)
  9051.     (if (string< "" comm)
  9052.         (progn (if (not irc-called-from-buffer)
  9053.                (progn (irc-insert "")
  9054.                   (irc-insert "/KILL %s %s" user comm)))
  9055.            (irc-send (concat "KILL " user " " comm)))
  9056.         (irc-insert "%%No comment given to /KILL command."))
  9057.     (irc-insert "%%No user given, no killing take place.")))
  9058.   (setq irc-idle-last-sent (irc-current-time)))
  9059.  
  9060.  
  9061. (defun irc-execute-invite (user)
  9062.   "Usage: /INVITE user [ channel ]
  9063.  
  9064. Ask \"user\" on IRC to join \"channel\".  If channel is 0, * or not provided
  9065. then the invitation de faults to your current channel, ie the on you're talking
  9066. to. If you are not talking to any channel and channel is 0 or not provided then
  9067. no invitation is sent -- you can't invite someone to \"go private\". When
  9068. called interactively, channel is set to the prefix argument; with no argument
  9069. or - the current channel is assumed."
  9070.   (interactive '(""))
  9071.   (let* ((pair (cond ((string-match "^ *\\([^ ]+\\) +\\([^ ]+\\) *$"
  9072.                     user)
  9073.               (cons
  9074.                (substring user (match-beginning 1) (match-end 1))
  9075.                (substring user (match-beginning 2) (match-end 2))))
  9076.              ((string-match " *\\([^ ]+\\) *$" user)
  9077.               (cons (substring user (match-beginning 1) (match-end 1))
  9078.                 ""))
  9079.              (t (cons "" ""))))
  9080.      (usr (irc-nuke-whitespace
  9081.            (if (and (string= "" (car pair)) (not irc-called-from-buffer))
  9082.            (irc-read-object "Invite which user? "
  9083.                     ""
  9084.                     (irc-recall-all 'irc-nicknames))
  9085.            (car pair))))
  9086.      (c1 (irc-nuke-whitespace
  9087.           (if (and (string= "" (cdr pair))
  9088.                (string< "" usr)
  9089.                (not irc-called-from-buffer))
  9090.           (irc-read-object
  9091.            (if (string= "0" irc-channel)
  9092.                (format "Invite \"%s\" to which channel? " usr)
  9093.                (format "Invite \"%s\" %s \"%s\") "
  9094.                    usr
  9095.                    "to which channel? (RET for"
  9096.                    irc-channel))
  9097.            ""
  9098.            (irc-recall-all 'irc-subscribed-channels))
  9099.           (cdr pair))))
  9100.      (chn (if (string= "" c1) irc-channel c1)))
  9101.     (cond ((string= "" usr) (irc-insert "%%No users nick given."))
  9102.       ((string= "0" chn) (irc-insert "%%Can't invite to \"channel\" 0."))
  9103.       (t (if (not irc-called-from-buffer)
  9104.          (progn (irc-insert "")
  9105.             (irc-insert "/INVITE %s %s"
  9106.                     usr
  9107.                     (irc-clean-up-message chn))))
  9108.          (irc-send (format "INVITE %s %s" usr chn)))))
  9109.   (setq irc-idle-last-sent (irc-current-time)))
  9110.  
  9111.  
  9112. (defun irc-execute-names (channel)
  9113.   "Usage: /NAMES [ channel ]
  9114.  
  9115. Show which channels everyone is on.  Optional argument \"channel\" means
  9116. to show just the users on that channel.  * means to show people on the
  9117. current channel.
  9118.  
  9119. Each line starts with a column for the channel number and is followed
  9120. by the nicknames of the people on that channel.  Users who are on
  9121. private channels or who are not on any channel are listed as
  9122. \"Private\".  Users who are on secret channels (channels less than 0)
  9123. are not shown at all.  A %-sign is appended to the current channel's
  9124. name or number."
  9125.   (interactive '(""))
  9126.   (let* ((c (if (and (string= "" channel) (not irc-called-from-buffer))
  9127.          (irc-read-object (format
  9128.                   "Names of persons on which channel? (%s) "
  9129.                   (if (string= "0" irc-channel)
  9130.                       "RET for all"
  9131.                       (concat "RET for all, * for "
  9132.                           irc-channel)))
  9133.                  ""
  9134.                  (irc-recall-all 'irc-subscribed-channels))
  9135.         channel))
  9136.      (chn (if (string= "*" c) irc-channel c)))
  9137.     (if (string= "" chn)
  9138.      (let ((lst (irc-recall-all 'irc-services)))
  9139.       (irc-forget-all 'irc-nicknames)
  9140.       (while lst
  9141.         (irc-remember (car lst) 'irc-nicknames)
  9142.         (setq lst (cdr lst)))))
  9143.     (if (not irc-called-from-buffer)
  9144.      (progn (irc-insert "")
  9145.            (irc-insert "/NAMES %s" chn)))
  9146.     (irc-send (concat "NAMES " chn))
  9147.     (if (not (and (irc-terminal-is-slow)
  9148.           (irc-server-has-end-of-names)))
  9149.     (progn (irc-insert "")
  9150.            (irc-insert "Name of channel Users Nicknames")
  9151.            (irc-insert "--------------- ----- ---------")
  9152.            (set-buffer-modified-p (buffer-modified-p)))))
  9153.   (setq irc-idle-last-sent (irc-current-time)))
  9154.  
  9155.  
  9156. (defun irc-execute-wall (message)
  9157.   "Usage: /WALL message
  9158.  
  9159. Send 'message' to everyone on IRC.  This can only be done by IRC Operators."
  9160.   (interactive '(""))
  9161.   (let ((msg (if (and (string= "" message) (not irc-called-from-buffer))
  9162.          (read-string "Message to send to everyone? ")
  9163.          message)))
  9164.     (if (string= "" msg)
  9165.     (irc-insert "%%No message.")
  9166.     (if (not irc-called-from-buffer)
  9167.         (progn (irc-insert "")
  9168.            (irc-insert "/WALL %s" msg)))
  9169.     (irc-send (concat "WALL " msg))))
  9170.   (setq irc-idle-last-sent (irc-current-time)))
  9171.  
  9172.  
  9173. (defun irc-execute-wallops (message)
  9174.   "Usage: /WALLOPS message
  9175.  
  9176. Send 'message' to every enabled IRC-operator on IRC.
  9177. If you got any problems you think an enabled IRC operator might be the right
  9178. person to help you with, *use* /WALLOPS. (But please don't *ABuse* it)."
  9179.   (interactive '(""))
  9180.   (let ((msg (if (and (string= "" message) (not irc-called-from-buffer))
  9181.          (read-string "Message to send to all enabled IRC operators? ")
  9182.          message)))
  9183.     (if (string< "" msg)
  9184.     (let ((data (format irc-msg-sent "all ENABLED operators of IRC")))
  9185.       (if (not irc-called-from-buffer)
  9186.           (progn (irc-insert "")
  9187.              (irc-insert "/WALLOPS %s" msg)))
  9188.       (irc-send (concat "WALLOPS " msg))
  9189.       (if irc-confirm
  9190.           (irc-insert "%s%s" (make-string
  9191.                   (max 0 (- (window-width
  9192.                          (get-buffer-window
  9193.                           (current-buffer)))
  9194.                         (length data)
  9195.                         1))
  9196.                   ? )
  9197.               data)))
  9198.     (irc-insert "%%No message given, no message sent.")))
  9199.   (setq irc-idle-last-sent (irc-current-time)))
  9200.  
  9201.  
  9202. (defun irc-execute-rehash (cruft)
  9203.   "Usage: /REHASH
  9204.  
  9205. Force the server to which you are connected to reread it's irc.conf file.
  9206. Arguments are ignored.  This command is only available to IRC Operators."
  9207.   (interactive '(""))
  9208.   (if (not irc-called-from-buffer)
  9209.       (progn (irc-insert "")
  9210.          (irc-insert "/REHASH")))
  9211.   (irc-send "REHASH")
  9212.   (setq irc-idle-last-sent (irc-current-time)))
  9213.  
  9214.  
  9215. (defun irc-execute-trace (server)
  9216.   "Usage: /TRACE [ server ]
  9217.  
  9218. Find the route from the server to which you are attached to 'server'; if the
  9219. server argument is not provided then the servers to which the current server
  9220. is directly connected are listed.  This command is only available to IRC
  9221. Operators."
  9222.   (interactive '(""))
  9223.   (let ((srvr (if (and (string= "" server) (not irc-called-from-buffer))
  9224.           (irc-read-object (concat "Trace route to server/user?"
  9225.                        " (RET for " irc-server ") ")
  9226.                    ""
  9227.                    (irc-get-names-and-servers))
  9228.           server)))
  9229.     (if (not irc-called-from-buffer)
  9230.     (progn (irc-insert "")
  9231.            (irc-insert "/TRACE %s" srvr)))
  9232.     (irc-send (concat "TRACE " srvr)))
  9233.   (setq irc-idle-last-sent (irc-current-time)))
  9234.  
  9235.  
  9236. (defun irc-execute-squit (server)
  9237.   "Usage: /SQUIT [ server ]
  9238.  
  9239. Shut down a server-to-server link.
  9240. The link shut down is the the one next farest away from you, ie if you do a
  9241. /SQUIT BYE.EDU and the path to it is your.server.edu!a!b!bye.edu, then the
  9242. link between b and bye.edu will be disconnected.
  9243.  
  9244. You have to be an enabled IRC operator to issue this conmmand."
  9245.   (interactive '(""))
  9246.   (let ((srvr (if (and (string= "" server) (not irc-called-from-buffer))
  9247.           (irc-read-object "Shut down link to which server? "
  9248.                    ""
  9249.                    (irc-recall-all 'irc-servernames))
  9250.           server)))
  9251.     (if (not irc-called-from-buffer)
  9252.     (progn (irc-insert "")
  9253.            (irc-insert "/SQUIT %s" srvr)))
  9254.     (irc-send (concat "SQUIT " srvr))
  9255.     (irc-insert "%sClosing the link to server %s%s"
  9256.         irc-msg-info-pre srvr irc-msg-info-post))
  9257.   (setq irc-idle-last-sent (irc-current-time)))
  9258.  
  9259.  
  9260. (defun irc-execute-connect (new)
  9261.   "Usage: /CONNECT [ newhost [ port [remoteserver ] ] ]
  9262.  
  9263. Connect the local server to SERVER on tcp-port PORT.
  9264.  
  9265. You have to be an enabled IRC operator to issue this conmmand."
  9266.   (interactive '(""))
  9267.   (let* ((tri (cond ((string-match
  9268.               (concat "^ *\\([^ ]+\\) +\\([^ ]+\\) +"
  9269.                   "\\([^ ]+\\) *$")
  9270.               new)
  9271.              (cons (subfield new 1)
  9272.                (cons (subfield new 2)
  9273.                  (subfield new 3))))
  9274.             ((string-match "^ *\\([^ ]+\\) +\\([^ ]+\\) *$"
  9275.                    new)
  9276.              (cons (subfield new 1)
  9277.                (cons (subfield new 2)
  9278.                  "")))
  9279.             ((string-match "^ *\\([^ ]+\\) *$" new)
  9280.              (cons (subfield new 1) (cons "" "")))
  9281.             (t (cons "" (cons "" "")))))
  9282.      (h1 (car tri))
  9283.      (h2 (if (and (string= "" h1) (not irc-called-from-buffer))
  9284.          (irc-read-object (concat "Connect server-link to which"
  9285.                       " internet host? ")
  9286.                   ""
  9287.                   (irc-recall-all 'irc-servernames))
  9288.          h1))
  9289.      (new-host (irc-nuke-whitespace h2))
  9290.      (p1 (car (cdr tri)))
  9291.      (p2 (if (and (string= "" p1)
  9292.               (string< "" new-host)
  9293.               (not irc-called-from-buffer))
  9294.          (irc-read-object (concat "Use which TCP-port for"
  9295.                       " server-link? (RET for 6667) ")
  9296.                   ""
  9297.                   (list "194" "6667"))
  9298.          p1))
  9299.      (p3 (irc-nuke-whitespace p2))
  9300.      (new-port (if (string= "" p3)
  9301.                6667 
  9302.                (string-to-int p3)))
  9303.      (s1 (cdr (cdr tri)))
  9304.      (s2 (if (and (string= "" s1)
  9305.               (string< "" new-host)
  9306.               (not irc-called-from-buffer))
  9307.          (irc-read-object (concat "Execute connect command at which"
  9308.                       " (reachable) server? (RET for"
  9309.                       " local) ")
  9310.                   ""
  9311.                   (irc-recall-all 'irc-servernames))
  9312.          s1))
  9313.      (s3 (irc-nuke-whitespace s2))
  9314.      (remote-server (if (string= "" s3) irc-server s3)))
  9315.     (cond ((string-match " " new-host)
  9316.        (irc-insert "%%Spaces aren't allowed in hostnames (%s)." new-host))
  9317.       ((string-match " " remote-server)
  9318.        (irc-insert "%%Spaces aren't allowed in servername (%s)."
  9319.                remote-server))
  9320.       (t (if (not irc-called-from-buffer)
  9321.          (progn (irc-insert "")
  9322.             (if (string= "" new-host)
  9323.                 (irc-insert "/CONNECT")
  9324.                 (irc-insert "/CONNECT %s %d %s"
  9325.                     new-host new-port remote-server))))
  9326.          (if (string= "" new-host)
  9327.          (irc-insert "%%No host to connect too given.")
  9328.          (irc-send (format "CONNECT %s %d %s"
  9329.                    new-host new-port remote-server))
  9330.          (irc-insert (concat "%sConnecting a server-link to host %s on"
  9331.                      " port %d from server %s%s")
  9332.                  irc-msg-info-pre
  9333.                  (upcase new-host)
  9334.                  new-port
  9335.                  (upcase remote-server)
  9336.                  irc-msg-info-post)))
  9337.       (setq irc-idle-last-sent (irc-current-time)))))
  9338.  
  9339. ;; /command just for the client  (need /stamp /alias /unalias)
  9340. (defun irc-execute-send (slist)
  9341.   "Usage: /SEND [ sendlist | - ]
  9342.  
  9343. Set the default sendlist for IRC messages.  This is a comma separated list
  9344. of the intended recipient(s) of messages which do not have an explicit
  9345. sendlist.  '-' as an argument means to disable the default sendlist; every
  9346. message sent then must have an explicit recipient provided with the message.
  9347. Without any arguments this command just displays the current default sendlist.
  9348.  
  9349. Each item specified is checked to see whether you can send there; ambiguous
  9350. references to users are not allowed.
  9351.  
  9352. \"*\" is always allowed and means to send to the current channel, ie the
  9353. channel you are talking to.
  9354. If no item in the new list can be set then the sendlist is not changed."
  9355.   (interactive "sDefault recipient(s) for messages? ")
  9356.   ;; blast some whitespace
  9357.   (setq slist (irc-nuke-whitespace slist))
  9358.   (let (matches)
  9359.     ;; first the easiest case
  9360.     (if (string= "-" slist) (setq irc-default-to nil)
  9361.     (setq matches
  9362.           (delq nil                   ; more indentation fun.  can someone
  9363.             (mapcar               ; recommend a good style manual?
  9364.              (function (lambda (arg)
  9365.                (setq matches (irc-check-list
  9366.                       (irc-recall-all 'irc-nicknames)
  9367.                       arg))
  9368.                (cond
  9369.              ((string= arg "*") arg)
  9370.              ((string= arg "0")
  9371.               (irc-insert "%%You can't send to channel 0.")
  9372.               nil)
  9373.              ((= (length matches) 1) (car matches))
  9374.              ((eq matches nil)
  9375.               (irc-insert "%%No names found to match \"%s\"." arg)
  9376.               nil)
  9377.              (t (irc-insert (concat "%%Ambiguous recipient %s;"
  9378.                         " could be %s.")
  9379.                     arg
  9380.                     (irc-subst-comma
  9381.                      (mapconcat (function (lambda (arg)
  9382.                               (concat "\"" arg "\"")))
  9383.                             matches
  9384.                             ", ")
  9385.                      "or"))
  9386.                 nil))))
  9387.              (irc-burst-comma slist))))
  9388.     (if matches
  9389.         (setq irc-default-to (concat (mapconcat 'eval matches ",") ";"))
  9390.         (or (string= "" slist)  ; only print the error if tried to set it.
  9391.         (irc-insert "%%No matches -- sendlist not changed."))))
  9392.     (cond ((not irc-default-to)
  9393.        (irc-insert (concat "%%Your default sendlist is disabled. (Ie you"
  9394.                    " are not sending to anyone when failing to"
  9395.                    " give an explicit receiver)")))
  9396.       ((string= irc-default-to "*;")
  9397.        (irc-insert (concat "%sYou are now using the default send list (ie"
  9398.                    " sending to the current channel (%s) when"
  9399.                    " failing to give an explicit receiver)%s")
  9400.                irc-msg-info-pre
  9401.                (if (string= "0" irc-channel) "none" irc-channel)
  9402.                irc-msg-info-post))
  9403.       (t (irc-insert (concat "%sYou are sending to %s, use /SEND * to"
  9404.                  " get back default sendlist%s")
  9405.              irc-msg-info-pre
  9406.              (irc-subst-comma
  9407.               (mapconcat 'eval
  9408.                      (irc-burst-comma
  9409.                       (substring irc-default-to 0
  9410.                          (1- (length irc-default-to))))
  9411.                      ", ")
  9412.               "and")
  9413.              irc-msg-info-post))))
  9414.   (setq irc-idle-last-sent (irc-current-time)))
  9415.  
  9416.  
  9417. (defun irc-execute-service (service)
  9418.   "Usage: /SERVICE [ [+]nick | -nick ]
  9419.  
  9420. Show or update list of services. A service is an automaton which looks
  9421. like a normal user, ie it has a nickname. It doesn't act as a normal
  9422. user though; normaly you can ask it for some service. For instance, at
  9423. NICKSERV you can register your nick name (do \"nickserv; help\" for
  9424. more information). Services often talk to you with so called NOTICE's.
  9425. When a service isn't marked as being one, these messages will be
  9426. displayed in a somewhat annoying format. Use this command to get a
  9427. nicer display.
  9428.  
  9429. With no argument, show which nicknames are assumed to be services."
  9430.   (interactive '(""))
  9431.   (let* ((pair (cond ((string-match (concat "^ *\\(+\\|-\\) *"
  9432.                         "\\([^ ]+\\) *$")
  9433.                     service)
  9434.               (cons (subfield service 1) (subfield service 2)))
  9435.              ((string-match "^ *\\([^ ]+\\) *$" service)
  9436.               (cons "+" (subfield service 1)))
  9437.              (t (cons "" ""))))
  9438.      (a (car pair))
  9439.      (a2 (irc-nuke-whitespace
  9440.           (if (and (string= "" a) (not irc-called-from-buffer))
  9441.           (irc-read-object (concat "Mark or unmark nick as"
  9442.                        " service? (RET to mark) ")
  9443.                    ""
  9444.                    '("mark" "unmark"))
  9445.           a)))
  9446.      (action (if (string-match "\\(unmark\\|-\\)" (downcase a2)) nil t))
  9447.      (n (cdr pair))
  9448.      (nick (irc-nuke-whitespace
  9449.         (if (and (string= "" n) (not irc-called-from-buffer))
  9450.             (irc-read-object (format "%sark which %s as service? (%s) "
  9451.                          (if action "M" "Unm")
  9452.                          (if action "nick" "service")
  9453.                          "RET to view existing")
  9454.                      ""
  9455.                      (if action
  9456.                      (irc-recall-all 'irc-nicknames)
  9457.                      (irc-recall-all 'irc-services)))
  9458.             n)))
  9459.      (s-list (irc-recall-all 'irc-services))
  9460.      (s-len (length s-list))
  9461.      (plural (if (= 1 s-len) "" "s"))
  9462.      (lst (irc-listify s-list ", " "and")))
  9463.     (if (not irc-called-from-buffer)
  9464.     (progn (irc-insert "")
  9465.            (irc-insert "/SERVICE %s%s" (if action "+" "-") nick)))
  9466.     (if (string= "" nick)
  9467.     (if (irc-nothing-remembered-p 'irc-services)
  9468.         (irc-insert "%sNo users marked as automatons%s"
  9469.             irc-msg-info-pre irc-msg-info-post)
  9470.         (irc-insert (concat "%s%d \"user%s\" marked as being"
  9471.                 " automaton%s (which provide some service):"
  9472.                 " %s%s")
  9473.             irc-msg-info-pre s-len plural plural lst
  9474.             irc-msg-info-post))
  9475.     (let ((irc-called-from-buffer t))
  9476.       (irc-insert "%s%sing \"%s\" %s being treated as a service%s"
  9477.               irc-msg-info-pre
  9478.               (if action "Add" "Remov")
  9479.               nick
  9480.               (if action "as" "from")
  9481.               irc-msg-info-post)
  9482.       (if action
  9483.           (irc-remember nick 'irc-services)
  9484.           (irc-forget nick 'irc-services))
  9485.       (irc-execute-service ""))))
  9486.   (setq irc-idle-last-sent (irc-current-time)))
  9487.  
  9488.  
  9489. (defun irc-execute-event (events)
  9490.   "Usage: /EVENT [ [+]event | -event ] [...]
  9491.  
  9492. Set the list of events to notify you about with a message.  Notification
  9493. is a one-line message inserted when someone causes that event to occur.
  9494. Events are added with +event or simply event; they are removed with -event.
  9495. + adds all supported events and - removes all supported events.  More than
  9496. one event can be specified in the arguments.  In case of conflict, the argument
  9497. which appears later overrides the argument with which it conflicts.
  9498.  
  9499. Currently supported by /EVENT are the \"ctcp\", \"join\", \"nick\", \"quit\"
  9500. and \"topic\" events.
  9501.  
  9502. CTCP happens whenever someone send you a CTCP query.
  9503. Join happens whenever someone enters or leaves a channel which you are on.
  9504. Nick occurs when someone changes nicknames; recognition of this event is
  9505. currently limited to when the person making the change is on the same channel
  9506. as you.
  9507. Quit happens when someone quits from IRC and you see it.
  9508. Topic happens when the topic of a channel you listen to is changed.
  9509.  
  9510.  
  9511. "
  9512.   (interactive "sNotify for events: ")
  9513.   ;; die scurvy whitespace
  9514.   (setq events (irc-nuke-whitespace events))
  9515.   (let ((recog '(ctcp join nick quit topic))
  9516.     (str events)
  9517.     sym
  9518.     off
  9519.     event
  9520.     (count 0))
  9521.     (while (string< "" events)
  9522.       ;; multiple args are okay.  we'll do one at a time.
  9523.       (setq str (substring events 0 (or (string-match " +" events)
  9524.                     (string-match "$" events)))
  9525.         events (substring events (match-end 0)))
  9526.       (string-match "^\\([---+]?\\)" str)
  9527.       (setq off (string= "-" (substring str (match-beginning 1) (match-end 1)))
  9528.         event (substring str (match-end 0))
  9529.         sym (if (string= "" event) nil
  9530.             (car (delq nil    ; do some minor pattern matching
  9531.                    (mapcar    ; to find the intended event
  9532.                 (function
  9533.                  (lambda (arg)
  9534.                   (if (string-match
  9535.                        (concat "^" (regexp-quote event))
  9536.                        (prin1-to-string arg))
  9537.                       arg))) recog)))))
  9538.       (cond
  9539.     ((and (string= "" event) off) (setq irc-events nil))
  9540.     ;; the only way for this to happen and not the above is str == "+"
  9541.     ((string= "" event) (setq irc-events recog))
  9542.     ((null sym)
  9543.      (irc-insert "%sEvent: Unknown argument \"%s\"%s"
  9544.              irc-msg-info-pre
  9545.              event
  9546.              irc-msg-info-post))
  9547.     (t (setq irc-events (if off (delq sym irc-events)
  9548.                   (if (not (memq sym irc-events)) ; avoid
  9549.                       (cons sym irc-events) ; redundancy
  9550.                       irc-events))))))
  9551.     (if irc-events
  9552.     (irc-insert "%sEvent notification is currently enabled for %s%s"
  9553.             irc-msg-info-pre
  9554.             (irc-subst-comma (mapconcat 'prin1-to-string irc-events
  9555.                         ", ") "and")
  9556.             irc-msg-info-post)
  9557.     (irc-insert "%sNotification is currently disabled%s"
  9558.             irc-msg-info-pre
  9559.             irc-msg-info-post)))
  9560.   (setq irc-idle-last-sent (irc-current-time)))
  9561.  
  9562.  
  9563. (defun irc-execute-confirm (str)
  9564.   "Usage: /CONFIRM [ + | - ]
  9565.  
  9566. Turn on message confirmation with + or off with -.  Any other arguments or no
  9567. arguments just gives a message about the current setting.
  9568.  
  9569. Message confirmation is a line indicating to whom a message was sent.
  9570. Occasionally this will say that a message has been sent to someone who
  9571. was not present but another message soon after will set the record straight."
  9572.   (interactive '(""))
  9573.   (let* ((c1 (irc-nuke-whitespace
  9574.           (if (and (string= "" str) (not irc-called-from-buffer))
  9575.           (irc-read-object "Turn confirm on or off? (RET to view) "
  9576.                    ""
  9577.                    '("+" "on" "-" "off"))
  9578.           str)))
  9579.      (conf (cond ((string-match "^\\(on\\|+\\)$" c1) "+")
  9580.              ((string-match "^\\(off\\|-\\)$" c1) "-")
  9581.              ((string= "" c1) "")
  9582.              (t nil))))
  9583.     (if (not conf)
  9584.     (irc-insert "%Huh? Try /HELP CONFIRM.")
  9585.     (progn (if (string= "+" conf) (setq irc-confirm t))
  9586.            (if (string= "-" conf) (setq irc-confirm nil))
  9587.            (irc-insert "%sMessage confirmation is %s%s"
  9588.                irc-msg-info-pre
  9589.                (if irc-confirm "on" "off")
  9590.                irc-msg-info-post))))
  9591.   (setq irc-idle-last-sent (irc-current-time)))
  9592.  
  9593.  
  9594. (defun irc-execute-notify (users)
  9595.   "Usage: /NOTIFY [ + | [-]nick ... ]
  9596.  
  9597. Add and delete nicknames from your notifylist. When people on the list get
  9598. detected, you will be notified. When they quit IRC, you will be notified of
  9599. this fact too.
  9600.  
  9601. With no argument, show the people on list, no matter if they've been
  9602. detected or not.
  9603.  
  9604. With a list of nicknames as the argument (each optionally prepended by
  9605. a \"-\"), add those nicknames to the list, unless a \"-\" was
  9606. prepended, in which case the nickname is removed."
  9607.   (interactive '(""))
  9608.   (let* ((str (irc-nuke-whitespace
  9609.            (if (and (string= "" users) (not irc-called-from-buffer))
  9610.            (irc-read-object
  9611.             "Notify when detecting whom? (RET to show list) "
  9612.             ""
  9613.             (irc-recall-all 'irc-nicknames))
  9614.            users)))
  9615.      (list (mapcar 'irc-nuke-whitespace (reverse (irc-burst-comma str))))
  9616.      (added ())
  9617.      (removed ())
  9618.      (show-current (null list)))
  9619.     (while (not (null list))
  9620.       (let* ((subtract (= ?- (aref (car list) 0)))
  9621.          (name (if subtract (substring (car list) 1) (car list)))
  9622.          (is-in-list (irc-recall name 'irc-notify-looked-for)))
  9623.     (cond ((not (irc-is-nickname name))
  9624.            (irc-insert "%%This doesn't look like a nickname: \"%s\"."
  9625.                name))
  9626.           (subtract
  9627.            (if is-in-list
  9628.            (setq removed (cons name removed)))
  9629.            (irc-forget (substring (car list) 1) 'irc-notify-looked-for))
  9630.           (t (if (not is-in-list)
  9631.              (setq added (cons name added)))
  9632.          (irc-remember (car list) 'irc-notify-looked-for))))
  9633.       (setq list (cdr list)))
  9634.     (irc-who-is-on (irc-recall-all 'irc-notify-looked-for))
  9635.     (if show-current
  9636.     (let* ((detected (irc-recall-all 'irc-notify-detected))
  9637.            (looked-for (irc-recall-all 'irc-notify-looked-for))
  9638.            (pre (format "%sOf the persons "
  9639.                 irc-msg-info-pre))
  9640.            (irc-msg-cont-used (make-string (length pre) ? )))
  9641.       (if (null looked-for)
  9642.           (irc-insert "%sYou're not looking for anybody%s"
  9643.               irc-msg-info-pre irc-msg-info-post)
  9644.           (progn
  9645.         (irc-insert "%syou want notifications for (%s),"
  9646.                 pre
  9647.                 (irc-listify looked-for ", " "and"))
  9648.         (setq irc-msg-cont-used (substring
  9649.                      irc-msg-cont-used
  9650.                      0
  9651.                      (- (length "the persons "))))
  9652.         (irc-insert "%s%s on IRC at the moment%s"
  9653.                 irc-msg-cont-used
  9654.                 (if (null detected)
  9655.                 "no one is"
  9656.                 (concat
  9657.                  "the person"
  9658.                  (if (= 1 (length detected)) " " "s ")
  9659.                  (irc-listify detected ", " "and")
  9660.                  (if (= 1 (length detected)) " is" " are")))
  9661.                 irc-msg-info-post))))
  9662.     (let* ((a (if added
  9663.               (format "Added %s to"
  9664.                   (irc-listify (reverse added) ", " "and"))))
  9665.            (r (if removed
  9666.               (format "%semoved %s from"
  9667.                   (if added ", and r" "R")
  9668.                   (irc-listify (reverse removed) ", " "and"))))
  9669.            (str (cond ((and added removed) (format "%s%s" a r))
  9670.               (added a)
  9671.               (removed r)
  9672.               (t "No change to")))
  9673.            (indent (or (and (string-match " " str) (1+ (match-end 0)))
  9674.                irc-msg-cont-used))
  9675.            (irc-msg-cont-used (make-string indent ? )))
  9676.       (irc-insert "%s%s the notification list%s"
  9677.               irc-msg-info-pre str irc-msg-info-post)))))
  9678.  
  9679.  
  9680. (defun irc-execute-unignore (user)
  9681.   "Usage: /UNIGNORE user | + | -
  9682.  
  9683. Stop ignoring a user who has been /IGNOREd.  The special arguments + or -
  9684. mean to stop ignoring everyone who is being ignored."
  9685.   (interactive '(""))
  9686.   (let ((usr (irc-nuke-whitespace
  9687.           (if (and (string= "" user) (not irc-called-from-buffer))
  9688.           (irc-read-object "Stop ignoring whom? (RET to view) "
  9689.                    ""
  9690.                    (irc-recall-all 'irc-ignored-ppl))
  9691.           user))))
  9692.     (if (string= "" usr)
  9693.     (if (irc-nothing-remembered-p 'irc-ignored-ppl)
  9694.         (irc-insert "%sYou are not ignoring anyone%s"
  9695.             irc-msg-info-pre
  9696.             irc-msg-info-post)
  9697.         (irc-insert "%sYou are currently ignoring %s%s"
  9698.             irc-msg-info-pre
  9699.             (irc-subst-comma
  9700.              (mapconcat 'eval
  9701.                     (irc-recall-all 'irc-ignored-ppl)
  9702.                     ", ")
  9703.              "and")
  9704.             irc-msg-info-post))
  9705.     (if (string-match "^[---+]$" usr)
  9706.         (progn (irc-forget-all 'irc-ignored-ppl)
  9707.            (irc-insert "%sYou are no longer ignoring anyone%s"
  9708.                    irc-msg-info-pre
  9709.                    irc-msg-info-post))
  9710.         (if (string< "" user)
  9711.         (progn (irc-forget user 'irc-ignored-ppl)
  9712.                (irc-insert "%sYou are no longer ignoring %s%s"
  9713.                    irc-msg-info-pre
  9714.                    user
  9715.                    irc-msg-info-post))))))
  9716.   (setq irc-idle-last-sent (irc-current-time)))
  9717.  
  9718.  
  9719. (defun irc-execute-kick (kick)
  9720.   "Usage: /KICK user [channel]
  9721.    or: /KICK channel user
  9722.  
  9723. Kick user out from a channel. If no channel is given, defaults to the channel
  9724. you are currently talking to."
  9725.   (interactive)
  9726.   (let* ((c (if (string-match "^ *[^: ]+ +\\([^: ]+\\) *$" kick)
  9727.         (substring kick (match-beginning 1) (match-end 1))
  9728.         irc-channel))
  9729.      (chn (if (string= c "*") irc-channel c))
  9730.      (usr (if (string-match "^ *\\([^: ]+\\) +[^: ]+ *$" kick)
  9731.            (substring kick (match-beginning 1) (match-end 1))
  9732.            kick))
  9733.      (reversed (and (or (irc-is-channelname usr)
  9734.                 (string= usr "*"))
  9735.             (irc-is-nickname chn)))
  9736.      (chan (if reversed (if (string= "*" usr) irc-channel usr) chn))
  9737.      (user (if reversed chn usr)))
  9738.     (if (string-match "^ *$" user)
  9739.     (irc-insert "%%No user given, use /HELP KICK for help.")
  9740.     (if (not irc-called-from-buffer)
  9741.         (progn (irc-insert "")
  9742.            (irc-insert "/KICK %s %s" user chan)))
  9743.     (irc-send (concat "KICK " chan " :" user))))
  9744.   (setq irc-idle-last-sent (irc-current-time)))
  9745.  
  9746.  
  9747. (defun irc-execute-mail (m)
  9748.   "Usage: /MAIL [command [arguments]]
  9749.  
  9750. Give commands to the MAIL subsystem of IRC. This has nothing to do with
  9751. \"regular email\".
  9752. Do \"/MAIL HELP\" for seeing what commands are supported and how to use them.
  9753. Be warned though, the syntax in the help is somewhat ... nonstandard."
  9754.   (interactive)
  9755.   (if (not irc-called-from-buffer)
  9756.       (progn (irc-insert "")
  9757.          (irc-insert "/MAIL %s" m)))
  9758.   (irc-send (concat "MAIL " m))
  9759.   (setq irc-idle-last-sent (irc-current-time)))
  9760.  
  9761.  
  9762. (defun irc-execute-stats (args)
  9763.   "Usage: /STATS [ type [ server ] ]
  9764.  
  9765. Get statistics from a server. There are different kind of statistics
  9766. one can obtain:
  9767.     C    tells which other servers etc a server will accept
  9768.         connections from and will connect to
  9769.     H    tells which servers are treated as HUBS and LEAVES
  9770.     I    tells which masks are used to allow client connections
  9771.         at a server
  9772.     K    tells which user isn't allowed to use a specific server
  9773.     L    tells how much data has passed over the currently
  9774.         active links
  9775.         M       tells how many times the different (server level) commands
  9776.                 has been seen by the server
  9777.         N       same as C
  9778.     Q    tells which servers are in quarantine, ie for which servers
  9779.         a server disconnects its local link in that direction
  9780.         R       tells some internal resource statistics regarding traffic on
  9781.                 the server
  9782.         S       tells which services are connected to a server
  9783.         U       tells the uptime of a server
  9784.     Y    tells the connection classes in effect at a server
  9785.         Z       tells some internal resource statistics regarding the servers
  9786.                 memory usage
  9787.  
  9788. If no server is given, the current server (ie the one your client is
  9789. connected to at the time of the command) is used."
  9790.   (interactive '(""))
  9791.   (let* ((pair (cond ((string-match "^ *\\([^ ]+\\) +\\([^ ]+\\) *$" args)
  9792.               (cons (subfield args 1) (subfield args 2)))
  9793.              ((string-match "^ *\\([^ ]+\\) *$" args)
  9794.               (cons (subfield args 1) ""))
  9795.              (t (cons "" ""))))
  9796.      (c (car pair))
  9797.      (s (cdr pair))
  9798.      (cmd (irc-nuke-whitespace
  9799.            (if (and (string= "" c) (not irc-called-from-buffer))
  9800.            (irc-read-object (concat "Which STATS command? (C, I, K, L,"
  9801.                         " M, Q, R, S, U, Y or Z) ")
  9802.                     ""
  9803.                     '("C" "I" "K" "L" "M" "Q" "R" "S" "U" "Y"
  9804.                       "Z"))
  9805.            c)))
  9806.      (server (irc-nuke-whitespace
  9807.           (if (and (string= "" s) (not irc-called-from-buffer))
  9808.               (irc-read-object (concat "STATS at which server? "
  9809.                            "(RET for "
  9810.                            irc-server
  9811.                            ") ")
  9812.                        ""
  9813.                        (irc-recall-all 'irc-servernames))
  9814.               s))))
  9815.     (if (not irc-called-from-buffer)
  9816.     (progn (irc-insert "")
  9817.            (irc-insert "/STATS %s"
  9818.                (concat (upcase cmd)
  9819.                    (if (not (string= "" cmd))
  9820.                        " "
  9821.                        "")
  9822.                    server))))
  9823.     (irc-send (concat "STATS " (concat cmd " " server)))
  9824.     (setq irc-idle-last-sent (irc-current-time))))
  9825.  
  9826.  
  9827. (defun irc-execute-mode (mode)
  9828.   "Usage: /MODE [channel [commands [arguments]]]
  9829.    or: /MODE nick [commands [arguments]]
  9830.  
  9831. Change or inspect the mode of a channel or a user.
  9832. The following modes exist for channels:
  9833.    a      Make channel anonymous (not supported by any servers yet)
  9834.    b      Manipulate a channels list of banned people
  9835.    i      Make channel joinable only with an invitation
  9836.    k      Add or remove channel key (password)
  9837.    l      Limit the number of users on the channel (argument: count)
  9838.    m      Make channel moderated
  9839.    n      Forbid /MSG's into channel
  9840.    o      Make someone a channel operator of this channel (argument: user)
  9841.    p      Make the channel private (ie channel invisible, users shown as being
  9842.           on some private channel)
  9843.    s      Make the channel secret (ie both channel and users invisible)
  9844.    t      Lock the topic of the channel (only settable by channel operators)
  9845.    v      Gives a user a voice on a moderated channel
  9846.  
  9847. The following modes exist for a user:
  9848.    i      Invisible
  9849.    o      Operator on IRC - can only be set with /OPER command
  9850.    s      Statusmessages, receive from server
  9851.    w      WALLOPS, receive from server
  9852. At the moment, only one self can be manipulated, and only i, s and w
  9853. can be set.
  9854.  
  9855. Prepend the mode command character with a + to turn the correspending
  9856. mode on, or with a - to turn it off.
  9857.  
  9858. Examples:
  9859.     /mode                    Show the mode of the current channel.
  9860.     /mode #foo               Show the mode of the channel named \"#foo\".
  9861.     /mode #foo +t            Locks the topic of channel \"#foo\".
  9862.     /mode * +i+o WiZ         Makes the current channel invite only and
  9863.                              gives user WiZ channel operator status.
  9864.     /mode * -o+l+o WiZ 3 `   Removes channel operator status for the
  9865.                              current channel from user WiZ, sets the
  9866.                              maximum number of users to 3 and makes
  9867.                              user ` a channel operator.
  9868.  
  9869.     /mode WiZ                Show the mode of user WiZ.
  9870.     /mode WiZ +s             Start receiving local status messages, such as
  9871.                              other servers connecting to this server etc.
  9872.     /mode WiZ +i-w           Become invisible and stop receiving WALLOPS.
  9873.  
  9874. "
  9875.   (interactive '(""))
  9876.   (let* ((tri (cond ((string-match "^ *\\([^ ]+\\) +\\([^ ]+\\) +\\([^ ]\\)"
  9877.                    mode)
  9878.              (cons (subfield mode 1)
  9879.                (cons (subfield mode 2)
  9880.                  (concat (subfield mode 3)
  9881.                      (substring mode (match-end 0))))))
  9882.             ((string-match "^ *\\([^ ]+\\) +\\([^ ]\\)" mode)
  9883.              (cons (subfield mode 1)
  9884.                (cons (concat (subfield mode 2)
  9885.                      (substring mode (match-end 0)))
  9886.                  "")))
  9887.             ((string-match "^ *[^ ]" mode)
  9888.              (cons (irc-nuke-whitespace mode) (cons "" "")))
  9889.             (t (cons "" (cons "" "")))))
  9890.      (ch1 (irc-nuke-whitespace (car tri)))
  9891.      (ch2 (irc-nuke-whitespace
  9892.            (if (and (string= "" ch1) (not irc-called-from-buffer))
  9893.            (irc-read-object (concat "Get/set mode of what channel/user"
  9894.                         "? "
  9895.                         (if (not (string= "0" irc-channel))
  9896.                         (format "(RET for %s) "
  9897.                             irc-channel)))
  9898.                     ""
  9899.                     (append
  9900.                      (irc-recall-all 'irc-subscribed-channels)
  9901.                      (list irc-nick)))
  9902.            ch1)))
  9903.      (channel (if (or (string= "" ch2) (string= "*" ch2)) irc-channel ch2))
  9904.      (is-nick (irc-is-nickname channel))
  9905.      (cmd1 (irc-nuke-whitespace (car (cdr tri))))
  9906.      (command (irc-nuke-whitespace
  9907.            (if (and (string= "" cmd1)
  9908.                 (string< "" channel)
  9909.                 (not irc-called-from-buffer))
  9910.                (irc-read-object (format (concat "Mode commands for"
  9911.                             " channel %s? (RET to"
  9912.                             " view) ")
  9913.                         channel)
  9914.                     ""
  9915.                     (if is-nick
  9916.                         '("+" "-" "i" "o" "s" "w")
  9917.                         '("+" "-" "b" "i" "k" "l" "m" "n"
  9918.                           "o" "p" "s" "t" "v")))
  9919.                cmd1)))
  9920.      (a1 (irc-nuke-whitespace (cdr (cdr tri))))
  9921.      (arg (irc-nuke-whitespace
  9922.            (if (and (string= "" a1)
  9923.             (string< "" channel)
  9924.             (string-match "[LOlo]" command)    ;Needs arguments?
  9925.             (not irc-called-from-buffer))
  9926.            (irc-read-object (format "Arguments to \"/MODE %s %s\"? "
  9927.                         channel command)
  9928.                     ""
  9929.                     (irc-recall-all 'irc-nicknames))
  9930.            a1))))
  9931.     (if (not irc-called-from-buffer)
  9932.     (progn (irc-insert "")
  9933.            (irc-insert "/MODE %s %s %s" channel command arg))) 
  9934.     (irc-send (format "MODE %s %s %s" channel command arg)))
  9935.   (setq irc-idle-last-sent (irc-current-time)))
  9936.  
  9937.  
  9938. (defun irc-execute-die (&optional dummy)
  9939.   "Usage: /DIE
  9940.  
  9941. Tells your local server to go belly-up."
  9942.   (interactive)
  9943.   (if (not irc-called-from-buffer)
  9944.       (progn (irc-insert "")
  9945.          (irc-insert "/DIE")))
  9946.   (irc-send (concat "DIE"))
  9947.   (setq irc-idle-last-sent (irc-current-time)))
  9948.  
  9949.  
  9950. (defun irc-execute-finger (nick)
  9951.   "Usage: /FINGER user
  9952.  
  9953. Query a users client to get users finger information. As some clients don't
  9954. understand this query, you might or might not get back a valid answer.
  9955. Sometime you'll get back a confused \"What?\" from user instead."
  9956.   (interactive '(""))
  9957.   (let* ((u (irc-nuke-whitespace nick))
  9958.      (user (irc-nuke-whitespace
  9959.         (if (and (string= "" u) (not irc-called-from-buffer))
  9960.             (irc-read-object "Get FINGER info from whom? "
  9961.                      ""
  9962.                      (irc-recall-all 'irc-nicknames))
  9963.             u))))
  9964.     (if (string= "" user)
  9965.     (irc-insert "%%No nick name given.")
  9966.     (if (not irc-called-from-buffer)
  9967.         (progn (irc-insert "")
  9968.            (irc-insert "/FINGER %s" user)))
  9969.     (irc-send (concat "PRIVMSG " user " :\001FINGER\001"))))
  9970.   (setq irc-idle-last-sent (irc-current-time)))
  9971.  
  9972.  
  9973. (defun irc-execute-describe (str)
  9974.    "Usage: /DESCRIBE user action
  9975.  
  9976. Send a CTCP ACTION message to a user. As some clients don't understand
  9977. this message, you might get back a confused \"What?\" from user instead.
  9978.  
  9979. See also: /ME"
  9980.    (interactive '(""))
  9981.    (let* ((nick (substring str 0 (string-match " +\\|$" str)))
  9982.       (action (substring str (match-end 0)))
  9983.       (u (irc-nuke-whitespace nick))
  9984.       (user (irc-nuke-whitespace
  9985.          (if (and (string= "" u) (not irc-called-from-buffer))
  9986.              (irc-read-object "Send a ACTION message to whom? "
  9987.                       ""
  9988.                       (irc-recall-all 'irc-nicknames))
  9989.              u)))
  9990.       (m (irc-nuke-whitespace action))
  9991.       (msg (irc-nuke-whitespace
  9992.             (if (and (string= "" m) (not irc-called-from-buffer))
  9993.             (irc-read-object "What is your action? "
  9994.                      ""
  9995.                     nil)
  9996.            m))))
  9997.      (if (string= "" user)
  9998.      (irc-insert "%%No nick name given.")
  9999.     (if (string= "" msg)
  10000.        (irc-insert "%%No action given.")
  10001.       (if (not irc-called-from-buffer)
  10002.          (progn (irc-insert "")
  10003.             (irc-insert "/DESCRIBE %s %s" user msg)))
  10004.      (irc-send (concat "PRIVMSG " user " :\001ACTION " msg "\001")))))
  10005.    (setq irc-idle-last-sent (irc-current-time)))
  10006.  
  10007.  
  10008. (defun irc-execute-me (action)
  10009.    "Usage: /ME action
  10010.  
  10011. Send a CTCP ACTION message to current channel. As some clients don't
  10012. understand this message, you might get back a confused \"What?\" from
  10013. some users.
  10014.  
  10015. See also: /DESCRIBE"
  10016.    (interactive '(""))
  10017.    (let* ((m (irc-nuke-whitespace action))
  10018.       (msg (irc-nuke-whitespace
  10019.             (if (and (string= "" m) (not irc-called-from-buffer))
  10020.             (irc-read-object "What is your action? "
  10021.                     ""
  10022.                     nil)
  10023.            m)))
  10024.       (on-hash (irc-is-multijoinable-channel irc-channel))
  10025.       (newsrvr (irc-server-has-multijoinable-channels)))
  10026.      (if (string= "" msg)
  10027.      (irc-insert "%%No action given.")
  10028.     (if (not irc-called-from-buffer)
  10029.        (progn (irc-insert "")
  10030.           (irc-insert "/ME %s" msg)))
  10031.        (irc-send (concat (if (and newsrvr on-hash)
  10032.                  (concat "PRIVMSG " irc-channel)
  10033.                 "MSG")
  10034.              " :\001ACTION " msg "\001"))
  10035.        (let* ((confirm (format "(Description sent to channel %s)" irc-channel))
  10036.           (padding (make-string (max 0 (- (window-width
  10037.                            (get-buffer-window
  10038.                         (current-buffer)))
  10039.                           (length confirm)
  10040.                           1))
  10041.                     ? )))
  10042.      (irc-insert "%s%s" padding confirm))
  10043.        ))
  10044.    (setq irc-idle-last-sent (irc-current-time)))
  10045.  
  10046.  
  10047. (defun irc-execute-ping (nicks)
  10048.   "Usage: /PING nick ...
  10049.  
  10050. Query a user's client (using CTCP) and calculate the distance between
  10051. the two of you in tenth of seconds. As some clients don't understans this
  10052. query, you might or might not get back a valid answer. Sometimes you
  10053. might even get back a confused \"What?\" from the user of the client.
  10054.  
  10055. Due to some technical limits and sojges laziness, the measurment isn't
  10056. foolproof. If the result seems to be totally wrong, resubmit the query.
  10057.  
  10058. The granularity is 500 ms."
  10059.   (interactive '(""))
  10060.   (while (string-match "^ *\\([^ :]+\\) *" nicks)
  10061.     (sit-for 0)
  10062.     (let* ((nick (subfield nicks 1))
  10063.        (dummy (setq nicks (substring nicks (match-end 1))))
  10064.        (n (irc-nuke-whitespace nick))
  10065.        (v (irc-nuke-whitespace
  10066.            (if (and (string= "" n) (not irc-called-from-buffer))
  10067.            (irc-read-object "Get PING distance to whom? "
  10068.                     ""
  10069.                     (irc-recall-all 'irc-nicknames))
  10070.            n)))
  10071.        (victim (if (string= "*" v) irc-channel v)))
  10072.       (if (string= "" victim)
  10073.       (irc-insert "%%No name given.")
  10074.       (if (not irc-called-from-buffer)
  10075.           (progn (irc-insert "")
  10076.              (irc-insert "/PING %s" victim)))
  10077.       (irc-send (format (concat "PRIVMSG %s :"
  10078.                     "\001ERRMSG PING RELAY %d\001"
  10079.                     "\001PING %d\001")
  10080.                 victim
  10081.                 (car (cdr (irc-current-time)))
  10082.                 (car (cdr (irc-current-time))))))))
  10083.   (setq irc-idle-last-sent (irc-current-time)))
  10084.  
  10085.  
  10086. (defun irc-execute-memberships (&optional dummy)
  10087.   "Usage: /MEMBERSHIPS
  10088.  
  10089. Show which channels you're listening to, and which one you're talking to.
  10090.  
  10091. Use /JOIN to join more or other channels, /LEAVE to leave some."
  10092.   (interactive '(""))
  10093.   (if (not irc-called-from-buffer)
  10094.       (progn (irc-insert "")
  10095.          (irc-insert "/MEMBERSHIPS")))
  10096.   (irc-show-subscribed-channels)
  10097.   (setq irc-idle-last-sent (irc-current-time)))
  10098.  
  10099.  
  10100. (defun irc-execute-signal (sigs)
  10101.   "Usage: /SIGNAL [ + | - | [+]event | -event ] [...]
  10102.  
  10103. Set the events which will get signals (aks bells or dings) when they
  10104. occur.  Events supported are:
  10105.  
  10106. backtalk -- your nick is mentioned            private  -- private messages
  10107. detect   -- nick in notify list seen/gone     public   -- public messages
  10108. invite   -- invitations                       topic    -- channel topic changes
  10109. join     -- channel changes                   wall     -- broadcast messages
  10110. nick     -- nickname changes                  
  10111.  
  10112. Without any arguments /SIGNAL simply prints a message about what signals
  10113. are currently enabled.  With event or +event turn on all signalling for that
  10114. event.  Remove all signals for an event with -event.  /SIGNAL + or /SIGNAL -
  10115. adds or removes all signals respectively.  Multiple arguments are accepted;
  10116. later ones take precedence over the ones which came before them.  For example,
  10117. \"/SIGNAL - +w +i\" would turn off all signals and then turn on signalling only
  10118. for wall messages and invitations."
  10119.   (interactive "sSet signal: ")
  10120.   ;; blow some whitespace away.  curiously this doesn't work correctly in debug
  10121.   (setq sigs (irc-nuke-whitespace sigs))
  10122.   (let ((recog '(backtalk
  10123.          detect
  10124.          invite
  10125.          join
  10126.          nick
  10127.          private
  10128.          public
  10129.          wall
  10130.          topic))
  10131.     str
  10132.     sym
  10133.     on
  10134.     off
  10135.     event)
  10136.     (while (string< "" sigs)
  10137.       ;; take one argument at a time
  10138.       (setq str  (substring sigs 0 (string-match " +\\|$" sigs))
  10139.         sigs (substring sigs (match-end 0)))
  10140.       (string-match "^\\([---+]?\\)" str)
  10141.       (setq off (string= "-" (substring str (match-beginning 1) (match-end 1)))
  10142.         event (substring str (match-end 0))
  10143.         sym (if (string= "" event) nil
  10144.             (car (delq nil
  10145.                    (mapcar
  10146.                 (function
  10147.                  (lambda (arg)
  10148.                   (if (string-match
  10149.                        (concat "^" (regexp-quote event))
  10150.                        (prin1-to-string arg))
  10151.                       arg))) recog)))))
  10152.       (cond
  10153.     ((and (string= "" event) off)
  10154.      (setq irc-signals (mapcar 'list recog)))
  10155.     ((string= "" event)
  10156.      (setq irc-signals (mapcar
  10157.                 (function (lambda (arg) (list arg t))) recog)))
  10158.     ((null sym)
  10159.      (irc-insert "%%Signal: Unknown argument %s."
  10160.              irc-msg-info-pre
  10161.              event
  10162.              irc-msg-info-post))
  10163.     (t (if off (setcdr (assoc sym irc-signals) nil)
  10164.            (setcdr (assoc sym irc-signals) '(t))))))
  10165.     (setq on (delq nil
  10166.            (mapcar        ; test against t because I have plans
  10167.             (function     ; to couple users and events
  10168.              (lambda (arg)
  10169.               (if (eq (nth 1 (assoc arg irc-signals)) t)
  10170.               arg))) recog)))
  10171.     (if on
  10172.     (irc-insert "%sSignalling is enabled for %s%s"
  10173.             irc-msg-info-pre
  10174.             (irc-subst-comma
  10175.              (mapconcat 'prin1-to-string on ", ") "and")
  10176.             irc-msg-info-post)
  10177.     (irc-insert "%sAll signalling is currently disabled%s"
  10178.             irc-msg-info-pre
  10179.             irc-msg-info-post)))
  10180.   (setq irc-idle-last-sent (irc-current-time)))
  10181.  
  10182.  
  10183. (defun irc-execute-stamp (stamp)
  10184.   "Usage: /STAMP [ + | - | [+]event | -event | interval ] [...]
  10185.  
  10186. Set time-stamping for IRC.  + means to turn it on for all messages from users
  10187. and - means to turn it off for them.  +event or just event will turn it on for
  10188. that class of message and -event means to disable it for those messages.  An
  10189. integer interval means to insert a message indicating the time every N minutes,
  10190. where N is the interval.  With no arguments simply insert a message indicating
  10191. the current time-stamps.
  10192.  
  10193. The current time in HH:MM format can appear two different ways in IRC.  One is
  10194. to have it associate with 'event'; two events, 'private' and 'public' messages,
  10195. are supported this way.  The other is to have it as a stand-alone message
  10196. indicating the current time.  Both can be very useful in noting when someone
  10197. actually sent you a message or when another event happened if you happen to be
  10198. away for a while.  The accuracy of the interval timer is currently limited to
  10199. 0-2 minutes beyond the interval if display-time is not running; accuracy is
  10200. greatly improved if it is.  It can be turned off by setting the interval
  10201. to 0."
  10202.   (interactive "sSet time-stamp: ")
  10203.   ;; whee.  napalm would feel particularly good here.
  10204.   (setq stamp (irc-nuke-whitespace stamp))
  10205.   (let (str sym event off)
  10206.     (while (string< "" stamp)
  10207.       ;; as the args go marching one by one the last one stopped ... <ahem>
  10208.       (setq str   (substring stamp 0 (string-match " +\\|$" stamp))
  10209.         stamp (substring stamp (match-end 0)))
  10210.       (string-match "^\\([---+]?\\)" str)
  10211.       (setq off (string= "-" (substring str (match-beginning 1) (match-end 1)))
  10212.         event (substring str (match-end 1))
  10213.         sym (cond ((string= "" event) nil)
  10214.               ((string-match (concat "^" (regexp-quote event))
  10215.                      "private") 'private)
  10216.               ((string-match (concat "^" (regexp-quote event))
  10217.                      "public")  'public)
  10218.               ((natnump (car (read-from-string event)))
  10219.                (car (read-from-string event)))))
  10220.       ;; the following cond is really what sets eveything
  10221.       (cond ((and (string= "" event) off) (setq irc-message-stamp nil))
  10222.         ((string= "" event) (setq irc-message-stamp t))
  10223.         ((null sym) (irc-insert "%%Stamp: Unknown argument %s."
  10224.                     irc-msg-info-pre
  10225.                     event
  10226.                     irc-msg-info-post))
  10227.         ((natnump sym) (setq irc-time-stamp sym))
  10228.         (off (setq irc-message-stamp
  10229.                (car (delq sym (if (eq irc-message-stamp t)
  10230.                       '(private public)
  10231.                       (list irc-message-stamp))))))
  10232.         (t (setq irc-message-stamp
  10233.              (cond ((null irc-message-stamp) sym)
  10234.                ((or (eq irc-message-stamp t)
  10235.                 (eq irc-message-stamp sym)) irc-message-stamp)
  10236.                (t t)))))))
  10237.   (irc-insert "%s%s messages get time-stamps.%s%s"
  10238.           irc-msg-info-pre
  10239.           (cond ((eq irc-message-stamp t) "Private and public")
  10240.             ((null irc-message-stamp) "No")
  10241.             (t (capitalize (prin1-to-string irc-message-stamp))))
  10242.           (if (zerop irc-time-stamp) ""
  10243.           (format "  The time interval is %d minutes."
  10244.               irc-time-stamp))
  10245.           irc-msg-info-post)
  10246.   (setq irc-idle-last-sent (irc-current-time)))
  10247.  
  10248.  
  10249. (defun irc-execute-alias (alias)
  10250.   "Usage: /ALIAS alias [command] [args for command]]]
  10251.  
  10252. Allow 'alias' to be equivalent to 'command'.
  10253. For example, \"/ALIAS tf time tut.fi\" will make typing \"/tf\" be equivalent
  10254. to having issued the command \"/time tut.fi\".  Aliases can only be made
  10255. to existing commands, not other aliases.  They are also only recognized when
  10256. in the command name position of a line.  If given with no arguments then
  10257. all aliases are displayed; if given with just an alias name then the alias
  10258. with that name will be shown.  Aliases can be removed with /UNALIAS."
  10259.   (interactive "sWhat name should the new alias have? (RET to view all) ")
  10260.   (if (and (interactive-p) (string-match "[^: ]+" alias))
  10261.       (setq alias (concat
  10262.            alias
  10263.            " "
  10264.            (irc-read-object
  10265.             (format (concat "Alias \"%s\" to which command? "
  10266.                     "(Including optional arguments) ")
  10267.                 alias)
  10268.             ""
  10269.             (mapcar (function (lambda (pair)
  10270.                   (upcase (cdr pair))))
  10271.                 (append irc-alias-alist
  10272.                     (append irc-command-alist
  10273.                         irc-operator-alist)))))))
  10274.   (setq alias (irc-nuke-whitespace alias))
  10275.   (string-match "^/?\\([^: ]*\\) */?\\([^: ]*\\) *" alias)
  10276.   (let ((new (upcase (subfield alias 1)))
  10277.     (cmd (upcase (subfield alias 2)))
  10278.     (arg (irc-nuke-whitespace (substring alias (match-end 2))))
  10279.     match)
  10280.     (cond
  10281.       ((string= "" new)
  10282.        (let ((aliases irc-alias-alist))
  10283.      (cond ((> (length aliases) 0)
  10284.         (while aliases
  10285.           (irc-insert "%s/%s is aliased to mean \"/%s\"%s"
  10286.                   irc-msg-info-pre
  10287.                   (car (car aliases))
  10288.                   (cdr (car aliases))
  10289.                   irc-msg-info-post)
  10290.           (setq aliases (cdr aliases)))
  10291.         (irc-insert "%sListed all aliases%s"
  10292.                 irc-msg-info-pre
  10293.                 irc-msg-info-post))
  10294.            (t (irc-insert "%sYou don't have any aliases%s"
  10295.                   irc-msg-info-pre
  10296.                   irc-msg-info-post)))))
  10297.       ((string= "" cmd)
  10298.        (let ((alias (assoc new irc-alias-alist)))
  10299.      (if alias
  10300.          (irc-insert "%s/%s is aliased to mean \"/%s\"%s"
  10301.              irc-msg-info-pre
  10302.              (car alias)
  10303.              (cdr alias)
  10304.              irc-msg-info-post)
  10305.          ;; this could possibly have done some matching to see whether
  10306.          ;; just an abbrev was being given, but we'll just take it as given
  10307.          (irc-insert "%s\"/%s\" is not aliased%s"
  10308.              irc-msg-info-pre
  10309.              new
  10310.              irc-msg-info-post))))
  10311.       (t
  10312.        ;; Okay, we've got at least a command.  let's try and make this as
  10313.        ;; painless as possible. 
  10314.        (setq match (irc-check-list
  10315.             (mapcar 'car (append irc-command-alist
  10316.                      irc-operator-alist))
  10317.             cmd
  10318.             'start-only))
  10319.        (if (/= (length match) 1)
  10320.        (if match
  10321.            (irc-insert "%%Ambiguous command /%s; could be %s."
  10322.                cmd
  10323.                (irc-subst-comma
  10324.                 (mapconcat (function (lambda (arg)
  10325.                      (concat "\"" arg "\"")))
  10326.                        match
  10327.                        ", ")
  10328.                 "or"))
  10329.            (irc-insert "%%Command not found: /%s." cmd))
  10330.        (irc-change-alias new
  10331.                  (concat (downcase (car match))
  10332.                      ;; no trailing space if no arg
  10333.                      (if (string= "" arg)
  10334.                      ""
  10335.                      " ")
  10336.                      arg)
  10337.                  'add)
  10338.        (irc-insert "%s\"/%s\" has been aliased to mean \"/%s\"%s"
  10339.                irc-msg-info-pre
  10340.                new 
  10341.                (cdr (assoc new irc-alias-alist))
  10342.                irc-msg-info-post)))))
  10343.   (setq irc-idle-last-sent (irc-current-time)))
  10344.  
  10345.  
  10346. (defun irc-execute-unalias (alias)
  10347.   "Usage: /UNALIAS alias
  10348.  
  10349. Remove the 'alias' for a command."
  10350.   (interactive '(""))
  10351.   (let* ((tmpalias (if (and (string= "" alias) (not irc-called-from-buffer))
  10352.                (irc-read-object "Remove which alias? "
  10353.                     ""
  10354.                     (mapcar (function (lambda (p)
  10355.                           (upcase (car p))))
  10356.                         (irc-recall-all
  10357.                          'irc-alias-alist)))
  10358.                alias))
  10359.      (a (irc-nuke-whitespace tmpalias)) 
  10360.      (match (irc-check-list (mapcar 'car irc-alias-alist) a t)))
  10361.     (if (/= (length match) 1)
  10362.     (if match (irc-insert "%%%s is an ambiguous alias. Could be %s."
  10363.                   (upcase alias)
  10364.                   (irc-subst-comma
  10365.                    (mapconcat (function (lambda (arg)
  10366.                         (concat "\"" arg "\"")))
  10367.                       match
  10368.                       ", ")
  10369.                    "or"))
  10370.         (irc-insert "%%No alias found to match %s." (upcase alias)))
  10371.     (irc-change-alias (car match) nil 'remove)
  10372.     (irc-insert "%s\"%s\" is no longer aliased%s"
  10373.             irc-msg-info-pre (car match) irc-msg-info-post)))
  10374.   (setq irc-idle-last-sent (irc-current-time)))
  10375.  
  10376.  
  10377. ;;START of code by Per StarbΣck (starback@Student.DoCS.UU.SE)
  10378. (defun irc-execute-help (topic)
  10379.   "Usage: /HELP topic
  10380.  
  10381. Get the documentation for \"command\".  If no command is given then a list
  10382. of the possible topics is shown.  Note that commands for IRC Operators will
  10383. not appear in the help topics when not an IRC Operator."
  10384.   (interactive '(""))
  10385.   (let* ((normal-commands (mapcar (function car) irc-command-alist))
  10386.      (oper-commands (mapcar (function car) irc-operator-alist))
  10387.      (alias-commands (mapcar (function car) irc-alias-alist))
  10388.      (help-topics (mapcar (function car) irc-help-topic-alist))
  10389.      (top (irc-nuke-whitespace
  10390.            (if (and (string= "" topic) (not irc-called-from-buffer))
  10391.            (irc-read-object
  10392.             "Help for which command or topic? "
  10393.             ""
  10394.             (append normal-commands
  10395.                 (if irc-operator oper-commands '())
  10396.                 alias-commands
  10397.                 help-topics))
  10398.          topic))))
  10399.     (if (not irc-called-from-buffer)
  10400.     (progn (irc-insert "")
  10401.            (irc-insert "/HELP %s" top)))
  10402.     (if (string= top "")
  10403.     (let* ((str (concat "Help is available for the following IRC-mode"
  10404.                 " commands:\n"))
  10405.            (topics (sort (append normal-commands
  10406.                      (if irc-operator oper-commands nil)
  10407.                      alias-commands
  10408.                      help-topics)
  10409.                  (function string<))))
  10410.       (while topics
  10411.         (setq str (concat str
  10412.                   (format "\n%14s%14s%14s%14s%14s"
  10413.                       (nth 0 topics)
  10414.                       (or (nth 1 topics) "")
  10415.                       (or (nth 2 topics) "")
  10416.                       (or (nth 3 topics) "")
  10417.                       (or (nth 4 topics) "")))
  10418.           topics (nthcdr 5 topics)))
  10419.       (with-output-to-temp-buffer "*Help*" (princ str)))
  10420.       (let* ((matches (irc-check-list
  10421.                (append normal-commands
  10422.                    (if irc-operator oper-commands '())
  10423.                    alias-commands
  10424.                    help-topics)
  10425.                top t))
  10426.          ;;(matches-normal (irc-common-element matches normal-commands))
  10427.          (matches-oper (irc-common-element matches oper-commands))
  10428.          (matches-alias (irc-common-element matches alias-commands))
  10429.          (matches-topic (irc-common-element matches help-topics))
  10430.          (shadowingalias nil))
  10431.     ;; If there is an alias with the same name as a command,
  10432.     ;; the alias is preferred.  Other collisions shouldn't be possible.
  10433.     (if (and (cdr matches)        ;== (> (length matches) 1)
  10434.          (irc-all-true (mapcar (function (lambda (x)
  10435.                            (string= x (car matches))))
  10436.                        (cdr matches))))
  10437.         (if matches-alias
  10438.         (setq matches (list (car matches))
  10439.               shadowingalias (concat
  10440.                       "\n\nThis shadows the "
  10441.                       (cond (matches-topic
  10442.                          "general help on the topic")
  10443.                         (matches-oper "operator command")
  10444.                         (t "command"))
  10445.                       " with the same name."))
  10446.           (with-output-to-temp-buffer "*Help*"
  10447.         (princ (format (concat "There are several things called %s, "
  10448.                        "and no way to know \nwhich one you "
  10449.                        "want help on.  This is a bug--please "
  10450.                        "contact \n%s.")
  10451.                    (car matches) irc-hacker)))))
  10452.     ;; If nothing else matches even a non-oper gets to see
  10453.     ;; help on oper commands.
  10454.     (if (and (null matches) (not irc-operator))
  10455.         (setq matches (irc-check-list oper-commands top t)
  10456.           matches-oper matches))
  10457.     (cond ((null matches)
  10458.            (irc-insert "%%No help is available for \"%s\"."
  10459.                (upcase top)))
  10460.           ((cdr matches)        ;== (> (length matches) 1)
  10461.            (irc-insert "%%Ambiguous help topic %s; could be %s."
  10462.                (upcase top)
  10463.                (irc-subst-comma
  10464.                 (mapconcat (function (lambda (arg)
  10465.                            (concat "\"" arg "\"")))
  10466.                        matches
  10467.                        ", ")
  10468.                 "or")))
  10469.           (t ;;Exactly one match:
  10470.            (let ((match (car matches)))
  10471.          (with-output-to-temp-buffer "*Help*"
  10472.            (cond (matches-alias
  10473.               (let ((aliasfor (cdr (assoc match irc-alias-alist))))
  10474.                 (princ (format "%s is an alias for \"/%s\"."
  10475.                        match aliasfor))
  10476.                 (if shadowingalias (princ shadowingalias))
  10477.                 (princ (format "\n\n%s"
  10478.                        (irc-help-for-command
  10479.                         (upcase
  10480.                          (substring 
  10481.                           aliasfor 0
  10482.                           (string-match " "
  10483.                                 aliasfor))))))))
  10484.              (matches-topic
  10485.               (princ (cdr (assoc match irc-help-topic-alist))))
  10486.              (t (princ (irc-help-for-command match))))))))))))
  10487.  
  10488.  
  10489. (defun irc-help-for-command (command)
  10490.   "Returns the documentation string for the irc command COMMAND."
  10491.   (documentation
  10492.    (or (intern-soft (concat "irc-execute-"
  10493.                 (or (cdr (assoc command irc-command-alist))
  10494.                 (cdr (assoc command irc-operator-alist)))))
  10495.        'irc-internal-error-dummy)))
  10496.  
  10497.  
  10498. (defun irc-common-element (list1 list2)
  10499.   "True if two lists have at least one common element.
  10500. The predicate eq is used for the comparisions."
  10501.   (cond ((null list1) nil)
  10502.     ((memq (car list1) list2) t)
  10503.     (t (irc-common-element (cdr list1) list2))))
  10504.  
  10505.  
  10506. (defun irc-all-true (list)
  10507.   "Is true if all args in LIST are true."
  10508.   ;; This is needed as special forms (like AND) can't be given to FUNCALL.
  10509.   (if (null list) t (and (car list) (irc-all-true (cdr list)))))
  10510. ;;;END of code by Per StarbΣck.
  10511.  
  10512.  
  10513. (defun irc-later-execute-lusers ()
  10514.   "Dummy function. Used when it's desired to do a irc-execute-lusers in a
  10515. little while. Not implemented yet."
  10516.   nil)
  10517.  
  10518.  
  10519. (defun irc-internal-error-dummy ()
  10520.   "Internal error.
  10521.  
  10522. No internal function associated with this command. This should never happen.
  10523. Please report this to the person mentioned in variable irc-hacker."
  10524.   nil)
  10525.  
  10526.  
  10527.  
  10528. ;; miscellaneous irc-* commands
  10529. (defun irc-truncate-buffer (max min)
  10530.   "Remove as many lines from the beginning of the buffer as is
  10531. necessary to get it under MAX number of characters, downto MIN number
  10532. of characters. This function is used by irc-mode to prevent an
  10533. irc-session from consuming gross amounts of space.
  10534.  
  10535. See irc-filter about not truncating the Kiwi buffer at all."
  10536.   (if (>= (buffer-size) max)
  10537.       (save-excursion
  10538.     ;; first go to the lowest point posssible that would do it
  10539.     (goto-char min)
  10540.     ;; get to the end of this line
  10541.     (end-of-line)
  10542.     (if (< (point) irc-mark)
  10543.         ;; just to make sure we don't toast pending input
  10544.         (delete-region 1 (1+ (point)))
  10545.         (message "Warning: %s exceeding %s characters.  Couldn't truncate."
  10546.              (buffer-name (current-buffer)) max)))))
  10547.  
  10548.  
  10549. (defun irc-read-passwd (&optional prompt)
  10550.   "Allow user to type a string without it showing.  Returns string.
  10551. If optional PROMPT non-nil, use it as the prompt string in the minibuffer."
  10552.   ;; this is based on a similar function in telnet.el
  10553.   ;; the major drawback is that while being prompted for a password
  10554.   ;; it stays in this routine until C-g, RET or LFD is typed.
  10555.   (let ((passwd "") (echo-keystrokes 0) char)
  10556.     (if prompt (message prompt))
  10557.     (while (not (or (= (setq char (read-char)) 13) (= char 10)))
  10558.       ;; naughty bit.  take C-h to mean DEL.
  10559.       (if (or (= char 8) (= char 127))
  10560.       (if (> (length passwd) 0)
  10561.           (setq passwd (substring passwd 0 (1- (length passwd)))))
  10562.       (setq passwd (concat passwd (char-to-string char))))
  10563.       (if prompt (message (concat prompt (make-string (length passwd) ?*)))))
  10564.     (if prompt (message ""))
  10565.     passwd))
  10566.  
  10567.  
  10568. (defun irc-read-object (prompt object list)
  10569.   "Prompting with PROMPT, read an IRC objects name from the minibuffer.
  10570. Second argument OBJECT is a string which is checked for a non-ambiguous match
  10571. before the minibuffer read is done.  Optional third argument LIST is a
  10572. list to use for checking rather than the irc-nicknames.
  10573.  
  10574. It returns either the name of a object or an empty string (\"\")."
  10575.   (if (not (string-match "^ *\\([^: ]*\\)" object)) ; just want one name
  10576.       "" 
  10577.       (let ((completion-ignore-case t)
  10578.         (object (substring object (match-beginning 1) (match-end 1)))
  10579.         (match nil))
  10580.     (if (or (string= "" object)
  10581.         (/= (length (setq match (irc-check-list list object))) 1))
  10582.         (completing-read (format "%s%s"
  10583.                      (if (string= "" object)
  10584.                      ""
  10585.                      (format (if (zerop (length match))
  10586.                              "No names match %s.  "
  10587.                              "\"%s\" is ambiguous.  ")
  10588.                          object))
  10589.                      prompt)
  10590.                  ;; build the list for completing-read.  a
  10591.                  ;; null string is there so that it can exit
  10592.                  ;; without anything, since we require matches
  10593.                  (mapcar 'list (cons "" list))
  10594.                  nil
  10595.                  nil        ;Also non exact matches are OK.
  10596.                  object)
  10597.         (car match)))))
  10598.  
  10599. (defun irc-nuke-whitespace (str)
  10600.   "One string argument.  Returns it with surrounding whitespace removed."
  10601.   (let* ((tmp (and (string-match "^ *" str)
  10602.            (substring str (match-end 0)))))
  10603.     (if (not tmp)
  10604.     str
  10605.     (and (string-match " *$" tmp)
  10606.          (substring tmp 0 (match-beginning 0))))))
  10607.  
  10608.  
  10609. (defun irc-stringlist-to-string (list &optional sep)
  10610.   "Take a LIST of strings and concate all string into one single string.
  10611. Optionally takes as a second argument a string to use as a seperator."
  10612.   (mapconcat (function (lambda (arg) arg)) list sep))
  10613.  
  10614.  
  10615. (defun irc-subst-comma (str newsep)
  10616.   "Return the string formed by substituting for the last \", \" in STR
  10617. the string NEWSEP followed by a space.  For example:
  10618.   (irc-subst-comma \"1, 2, 3\" \"or\") => \"1, 2 or 3\"
  10619.  
  10620. This function is especially designed for making message from irc-mode
  10621. more grammatically correct and the strings which it operates on should
  10622. be carefully chosen so as to avoid possibly blowing away a comma that
  10623. really wasn't separating elements in a list."
  10624.   ;; did you know that example up there can't appear starting in column 0
  10625.   ;; without screwing up lisp-indent-line?
  10626.   (if (string-match ", [^,]*$" str)
  10627.       (concat (substring str 0 (match-beginning 0)) " " newsep
  10628.           (substring str (1+ (match-beginning 0))))
  10629.       str))
  10630.  
  10631.  
  10632. (defun irc-listify (list sep conn)
  10633.   "Take a LIST of strings, and put them together into one single string, using
  10634. the SEPerator string between every pair of string, except the last pair where
  10635. the CONNector is used.
  10636. Example: (irc-listify '(\"a\" \"b\" \"c\") \", \" \"and\") returns
  10637. \"a, b and c\"."
  10638.   (irc-subst-comma (irc-stringlist-to-string list sep) conn))
  10639.  
  10640.  
  10641. (defun irc-get-time ()
  10642.   "Return the hour and minutes of the current time in the form \"HH:MM\"."
  10643.   (let ((time (current-time-string)))
  10644.     (substring time
  10645.            (string-match "[0-2][0-9]:[0-5][0-9]" time)
  10646.            (match-end 0))))
  10647.  
  10648.  
  10649. ;;;(defun irc-current-time ()
  10650. ;;;  "Return current time as number of seconds since 1-jan-1970 0:00:00.
  10651. ;;;As this is a 32 bit number but GNU Emacs only handles 16 bit numbers, split
  10652. ;;;it up in a cons with the car being the high order 16 bit numer and th cdr
  10653. ;;;the low order 16 bit number."
  10654. ;;;  (if (= 0 (buffer-size))
  10655. ;;;      (irc-insert ""))
  10656. ;;;  (write-region (point-max) (1- (point-max)) irc-idle-scratch-file nil 'silent)
  10657. ;;;  (nth 6 (file-attributes irc-idle-scratch-file)))
  10658.  
  10659.  
  10660. (defun irc-current-time ()
  10661.   "Return current time as number of seconds since 1-jan-1970 0:00:00.
  10662. As this is a 32 bit number but GNU Emacs only handles 16 bit numbers, split
  10663. it up in a cons with the car being the high order 16 bit numer and the cdr
  10664. the low order 16 bit number.
  10665.  
  10666. Written by Stephen Ma <ma_s@maths.su.oz.au>"
  10667.   (irc-time-to-int (current-time-string)))
  10668.  
  10669.  
  10670. (defun irc-time-to-int (timestr)
  10671.   "Convert from time in string format as returned by current-time-string
  10672. to a double integer format, as returned by file-attributes.
  10673.  
  10674. Written by Stephen Ma <ma_s@maths.su.oz.au>"
  10675.   (let* ((norm+ '(lambda (num1 num2)
  10676.           (let ((sumh (+ (car num1) (car num2)))
  10677.             (suml (+ (car (cdr num1)) (car (cdr num2)))))
  10678.             (list (+ sumh (/ suml 65536)) (% suml 65536)))))
  10679.      (norm* '(lambda (num1 num2)
  10680.           (let ((prodh (* num1 (car num2)))
  10681.             (prodl (* num1 (car (cdr num2)))))
  10682.             (list (+ prodh (/ prodl 65536)) (% prodl 65536)))))
  10683.      (seconds (string-to-int (substring timestr 17 19)))
  10684.      (minutes (string-to-int (substring timestr 14 16)))
  10685.      (hours (string-to-int (substring timestr 11 13)))
  10686.      (partdays (1- (string-to-int (substring timestr 8 10))))
  10687.      (years (string-to-int (substring timestr 20 24)))
  10688.      (days (+ partdays
  10689.           (cond ((and (= (% years 4) 0)
  10690.                   (/= (% years 100) 0))
  10691.              (cdr (assoc (substring timestr 4 7)
  10692.                      '(("Jan" . 0)
  10693.                        ("Feb" . 31)
  10694.                        ("Mar" . 60)
  10695.                        ("Apr" . 91)
  10696.                        ("May" . 121)
  10697.                        ("Jun" . 152)
  10698.                        ("Jul" . 182)
  10699.                        ("Aug" . 213)
  10700.                        ("Sep" . 244)
  10701.                        ("Oct" . 274)
  10702.                        ("Nov" . 305)
  10703.                        ("Dec" . 335)))))
  10704.             (t (cdr (assoc (substring timestr 4 7)
  10705.                        '(("Jan" . 0)
  10706.                      ("Feb" . 31)
  10707.                      ("Mar" . 59)
  10708.                      ("Apr" . 90)
  10709.                      ("May" . 120)
  10710.                      ("Jun" . 151)
  10711.                      ("Jul" . 181)
  10712.                      ("Aug" . 212)
  10713.                      ("Sep" . 243)
  10714.                      ("Oct" . 273)
  10715.                      ("Nov" . 304)
  10716.                      ("Dec" . 334))))))
  10717.           (* (- years 1970) 365)
  10718.           (/ (- years 1969) 4)
  10719.           (- (/ (- years 1901) 100)))))
  10720.     (funcall norm+
  10721.          (funcall norm*
  10722.               60
  10723.               (funcall norm+
  10724.                    (funcall norm*
  10725.                     60
  10726.                     (funcall norm+
  10727.                          (funcall norm*
  10728.                               24
  10729.                               (list 0 days))
  10730.                          (list 0 hours)))
  10731.                    (list 0 minutes)))
  10732.          (list 0 seconds))))
  10733.  
  10734.  
  10735. (defun irc-time= (a b)
  10736.   "Compare two time, return true if they're equal."
  10737.   (and (= (nth 0 a) (nth 0 b))
  10738.        (= (nth 1 a) (nth 1 b))))
  10739.  
  10740.  
  10741. (defun irc-time< (a b)
  10742.   "Compare two times, return t if the first is earlier than the second."
  10743.   (or (< (nth 0 a) (nth 0 b))
  10744.       (and (= (nth 0 a) (nth 0 b))
  10745.        (< (nth 1 a) (nth 1 b)))))
  10746.  
  10747.  
  10748. (defun irc-time-diff (a b)
  10749.   "Return the difference between two times. This functions requires
  10750. the first argument to be later in time than the second argument."
  10751.   (cond ((= (nth 0 a) (nth 0 b)) (list 0 (- (nth 1 a) (nth 1  b))))
  10752.     ((> (nth 1 b) (nth 1 a)) (list (- (nth 0 a) (nth 0 b) 1)
  10753.                        (- (+ 65536 (nth 1 a)) (nth 1 b))))
  10754.     (t (list (- (nth 0 a) (nth 0 b))
  10755.          (- (nth 1 a) (nth 1 b))))))
  10756.  
  10757.  
  10758. (defun irc-idle-time ()
  10759.   "Return a approximation of the idle time. The time is the number of seconds
  10760. which have passed since the last write to the server. If a valid idle-time
  10761. can't be returned, -1 is returned instead."
  10762.   (let ((now (irc-current-time))
  10763.     (then irc-idle-last-sent))
  10764.     (if (or (numberp irc-idle-last-sent)
  10765.         (not (= (car now) (car then))))
  10766.     -1
  10767.     (- (car (cdr now))
  10768.        (car (cdr then))))))
  10769.  
  10770.  
  10771. (defun irc-internal-time ()
  10772.   "Return a new value every time irc-internal-time is called. The new value is
  10773. larger than the latest returned, starting at 0."
  10774.   (if (not (boundp 'irc-internal-time))
  10775.       (set (make-local-variable 'irc-internal-time) nil))
  10776.   (if (not (integerp irc-internal-time))
  10777.       (setq irc-internal-time 0)
  10778.       (setq irc-internal-time (1+ irc-internal-time))))
  10779.  
  10780.  
  10781. (defun irc-check-time ()
  10782.   "Check to see whether it is time to insert a current-time message into
  10783. the *IRC* buffer."
  10784.   (if (null irc-last-time)
  10785.       (setq irc-last-time 0))
  10786.   (let* ((time (irc-get-time))
  10787.      (last (if (and (boundp 'irc-last-time) (stringp irc-last-time))
  10788.            irc-last-time
  10789.            time))
  10790.       (old-minute (string-to-int (substring last 3)))
  10791.       (new-minute (string-to-int (substring time 3)))
  10792.       (total-time (if (numberp irc-total-time) irc-total-time 0)))
  10793.     (if (and (zerop irc-time-stamp) (zerop irc-notify-interval))
  10794.      ()
  10795.     ;; check the time sentinel
  10796.     (if (string= irc-last-time time)
  10797.         ()
  10798.         ;; time has gone stomping on by ...
  10799.         (setq new-minute (+ new-minute (if (< new-minute old-minute) 60 0))
  10800.           irc-last-time time
  10801.           irc-total-time (+ total-time (- new-minute old-minute)))
  10802.         (if (not (zerop irc-time-stamp))
  10803.         (if (not (< (- irc-total-time irc-last-stamp) irc-time-stamp))
  10804.             (progn (irc-wrap-display-time)
  10805.                (irc-send "TIME")
  10806.                (setq irc-last-stamp irc-total-time))))
  10807.         (if (not (zerop irc-notify-interval))
  10808.         (if (not (< (- irc-total-time irc-last-notify)
  10809.                 irc-notify-interval))
  10810.             (progn (irc-wrap-display-time)
  10811.                (irc-who-is-on
  10812.                 (irc-recall-all 'irc-notify-looked-for))
  10813.                (setq irc-last-notify irc-total-time))))))))
  10814.  
  10815.  
  10816. (defun irc-wrap-display-time ()
  10817.   "Set up a wrapper around the display-time-filter to hopefully provide a
  10818. little better accuracy for the time stamps."
  10819.   (if (and (fboundp 'display-time-filter)
  10820.            (not (fboundp 'original-display-time-filter)))
  10821.       (progn
  10822.         (fset 'original-display-time-filter
  10823.               (symbol-function 'display-time-filter))
  10824.         ;; a nested defun seems to do funny things to the byte-compiler, so
  10825.         ;; instead we find a way around it.
  10826.         (fset 'display-time-filter
  10827.               (function
  10828.                (lambda (proc str)
  10829.         "
  10830. The filter for the display-time-process.  This function has been modified
  10831. for IRC-mode to call irc-check-time before calling the original
  10832. display-time-filter."
  10833.         (save-excursion
  10834.           (let ((procs (irc-active-servers)))
  10835.             (while procs
  10836.               (let ((buf (buffer-name (process-buffer (car procs)))))
  10837.             (if buf (progn (set-buffer buf) (irc-check-time)))
  10838.             (setq procs (cdr procs))))))
  10839.         (original-display-time-filter proc str)))))))
  10840.  
  10841.  
  10842. (defun irc-who-is-on (&optional list)
  10843.   (if (or (not (boundp 'irc-last-who-is-on))
  10844.       (not (and (listp irc-last-who-is-on)
  10845.             (numberp (nth 0 irc-last-who-is-on))
  10846.             (numberp (nth 1 irc-last-who-is-on)))))
  10847.       (set (make-local-variable 'irc-last-who-is-on) '(0 0)))
  10848.   (let* ((now (irc-current-time))
  10849.      (diff (irc-time-diff now irc-last-who-is-on)))
  10850.     (cond ((or (not (= 0 (nth 0 diff)))
  10851.            (> (nth 1 diff) 60))
  10852.        (setq irc-last-who-is-on (irc-current-time))
  10853.        (let ((str "")
  10854.          (namelist (if (null list)
  10855.                    (irc-recall-all 'irc-notify-looked-for)
  10856.                    list)))
  10857.          (while (not (null namelist))
  10858.            (setq str (concat str " " (car namelist))
  10859.              namelist (cdr namelist)))
  10860.          (irc-send (format "ISON :%s" str)))))))
  10861.  
  10862.  
  10863. (defun irc-change-alias (alias cmd add)
  10864.   "Modify ALIAS for CMD in the irc-alias-alist.  ADD non-nil means to put the
  10865. alias in the list, nil (or the symbol \"remove\") means to clear it.  This
  10866. function does no hand-holding like /ALIAS; its intended use is in
  10867. irc-mode-hook."
  10868.   (let ((entry (assoc (upcase alias) irc-alias-alist)))
  10869.     (if (or (null add) (eq add 'remove))
  10870.         (setq irc-alias-alist (delq entry irc-alias-alist))
  10871.     (if entry (setcdr entry cmd)
  10872.         (setq irc-alias-alist
  10873.           (cons (cons (upcase alias) cmd) irc-alias-alist))))))
  10874.  
  10875.  
  10876. (defun irc-signal (user event)
  10877.   "Return t if a ding should be issued for a USER/EVENT pair.
  10878. Currently only the event part of things is supported by /SIGNAL."
  10879.   (let ((signal (cdr (assoc event irc-signals))))
  10880.     (or (memq t signal)
  10881.     (irc-member-general user signal 'string=)
  10882.         (irc-member-general user
  10883.                 (cdr (assoc 'user irc-signals))
  10884.                 'string=))))
  10885.  
  10886.  
  10887. (defun irc-check-list (list item &optional start-only)
  10888.   "See if LIST has string ITEM.  Returns a list of possible matches.  The list
  10889. returned is based on the following precedence rules:  if there is an exact
  10890. match, it is returned.  If there are any strings in the list whose beginning
  10891. match the item, they are returned.  If that fails and optional argument
  10892. START-ONLY is missing or nil, strings which have the item match anywhere are
  10893. returned.  As a last resort, nil is returned.
  10894. This function is not case-sensitive."
  10895.   (let ((return nil)
  10896.     (case-fold-search t)
  10897.     (item (regexp-quote item)))
  10898.     (if (setq return
  10899.               (delq nil                         ; whole words
  10900.                     (mapcar (function   
  10901.                              (lambda (arg)
  10902.                   (if (string-match (concat "^" item "$") arg)
  10903.                   arg))) list)))
  10904.         return
  10905.     (if (setq return
  10906.           (delq nil                       ; beginnings
  10907.             (mapcar (function
  10908.                  (lambda (arg)
  10909.                   (if (string-match (concat "^" item) arg)
  10910.                       arg))) list)))
  10911.         return
  10912.         (if start-only
  10913.         nil
  10914.         (delq nil
  10915.               (mapcar (function               ; anywhere
  10916.                    (lambda (arg)        
  10917.                 (if (string-match (concat "." item) arg) arg)))
  10918.                   list)))))))
  10919.  
  10920.  
  10921. (defun irc-list-remember (item list)
  10922.   "Add string ITEM to ordered LIST destructivly, returning the new list in
  10923. reversed order. The intended way to call this is like:
  10924.   (setq lst (irc-list-remember \"foo\" lst)).
  10925.  
  10926. This function is case insensitive."
  10927.   (let ((ui (upcase item)))
  10928.     (cond ((null list) (cons item nil))
  10929.       ((string< (upcase (car list)) ui) (cons item list))
  10930.       ((string= (upcase (car list)) ui)
  10931.        (rplaca list item)
  10932.        list)
  10933.       (t (let ((ptr list))
  10934.            (while (and (not (null (cdr ptr)))
  10935.                (string< ui (upcase (car (cdr ptr)))))
  10936.          (setq ptr (cdr ptr)))
  10937.            (cond ((null (cdr ptr)) (rplacd ptr (cons item nil)))
  10938.              ((string= (upcase (car (cdr ptr))) ui)
  10939.               (rplaca (cdr ptr) item))
  10940.              ((string< (upcase (car (cdr ptr))) ui)
  10941.               (rplacd ptr (cons item (cdr ptr))))
  10942.              (t (error
  10943.              (format "NOT possible! item=%s, list=%s, ptr=%s."
  10944.                  item list ptr)))))
  10945.          list))))
  10946.          
  10947.          
  10948. (defun irc-hash-value (str tbl-size)
  10949.   "Return a hash value (index into a hash table) for string ITEM according to
  10950. a table of size SIZE."
  10951.   (let ((h 0)
  10952.     (i 0)
  10953.     (l (min 4 (length str))))
  10954.     (while (< i l)
  10955.       (setq h (% (+ (* h 256) (upcase (aref str i))) tbl-size)
  10956.         i (1+ i)))
  10957.     h))
  10958.  
  10959.  
  10960. (defconst irc-hash-index-size 0
  10961.   "Index of size field in a Kiwi hash table.")
  10962. (defconst irc-hash-index-timestamp 1
  10963.   "Index of timestamp field in a Kiwi hash table.")
  10964. (defconst irc-hash-index-cleanflag 2
  10965.   "Index of cleanstamp in a Kiwi hash table. Either a symbol or a list.")
  10966. (defconst irc-hash-index-bucketarray 3
  10967.   "Index of bucketarray in a Kiwi hash table.")
  10968.  
  10969.  
  10970. (defun irc-create-new-hash-table (size)
  10971.   "Create a empty hash table of size SIZE." 
  10972.   ;; [size write-date cleanflag bucketarray]
  10973.   ;; cleanflag is a list = non-dirty, valid sorted list representation of
  10974.   ;; the hashed data. Else only data to be found is in the hashtable. The hash
  10975.   ;; table is always clean.
  10976.   (let ((htbl (make-vector 4 nil)))
  10977.     (aset htbl irc-hash-index-size size)
  10978.     (aset htbl irc-hash-index-timestamp (irc-internal-time))
  10979.     (aset htbl irc-hash-index-cleanflag 'empty)
  10980.     (aset htbl irc-hash-index-bucketarray (make-vector size nil))
  10981.     htbl))
  10982.  
  10983.  
  10984. (defun irc-nothing-remembered-p (bag)
  10985.   "True if the BAG is empty."
  10986.   (let* ((htbl (symbol-value bag))
  10987.      (flg (aref htbl irc-hash-index-cleanflag)))
  10988.     (cond ((and (symbolp flg) (eq 'empty flg)) flg)
  10989.       (t (let* ((a (aref htbl irc-hash-index-bucketarray))
  10990.             (size (aref htbl irc-hash-index-size))
  10991.             (i size)
  10992.             (empty t))
  10993.            (while (and empty (> i 0))
  10994.          (setq i (1- i)
  10995.                empty (null (aref a i))))
  10996.            (if empty
  10997.            (irc-forget-all bag))
  10998.            empty)))))
  10999.  
  11000.  
  11001. (defun irc-remember (item bag)
  11002.   "Store a string ITEM in the named BAG."
  11003.   (let* ((htbl (symbol-value bag))
  11004.      (a (aref htbl irc-hash-index-bucketarray))
  11005.      (fixed (cond ((eq bag 'irc-servernames)
  11006.                (let ((i (irc-extract-hostname (upcase item))))
  11007.              (cond ((not i) nil)
  11008.                    ((string-match "^ *$" i)
  11009.                 (irc-insert (concat "%%Function irc-remember"
  11010.                             " found a space in"
  11011.                             " a hostname %s).")
  11012.                         item)
  11013.                 (if debug-on-error
  11014.                     (error "SPC in hostname"))
  11015.                 nil)
  11016.                    (t i))))
  11017.               ((or (eq bag 'irc-linksinfo)
  11018.                (eq bag 'irc-namtree)
  11019.                (eq bag 'irc-whotree)
  11020.                (eq bag 'irc-listtree))
  11021.                item)
  11022.               ((or (eq bag 'irc-nicknames)
  11023.                (eq bag 'irc-notify-detected)
  11024.                (eq bag 'irc-notify-looked-for))
  11025.                (cond ((string= "" item)
  11026.                   (irc-insert "%%Skipped \"\" in irc-nicknames.")
  11027.                   nil)
  11028.                  ((= ?@ (aref item 0))
  11029.                   (substring item 1))
  11030.                  ((string-match " " item)
  11031.                   (irc-insert (concat "%%Function irc-remember"
  11032.                           " found a space in a"
  11033.                           " nickname (%s).")
  11034.                       item)
  11035.                   (if debug-on-error
  11036.                   (error "SPC in nickname"))
  11037.                   nil)
  11038.                  ((string-match "\\." item)
  11039.                   (irc-insert (concat "%%Function irc-remember"
  11040.                           " found a dot in a"
  11041.                           " nickname (%s).")
  11042.                       item)
  11043.                   (if debug-on-error
  11044.                   (error "Dot in nickname"))
  11045.                   nil)
  11046.                  (t item)))
  11047.               ((string-match " " item)
  11048.                (irc-insert (concat "%%Function irc-remember"
  11049.                        " found a space in an item"
  11050.                        " (%s).")
  11051.                    item)
  11052.                (if debug-on-error
  11053.                (error "SPC in item"))
  11054.                nil)
  11055.               (t item))))
  11056.     (cond (fixed
  11057.        (let* ((idx (irc-hash-value fixed (aref htbl irc-hash-index-size)))
  11058.           (oldlen (length (aref a idx))))
  11059.          (aset a idx (irc-list-remember fixed (aref a idx)))
  11060.          (cond ((not (= oldlen (length (aref a idx))))
  11061.             (aset htbl irc-hash-index-timestamp (irc-internal-time))
  11062.             (aset htbl irc-hash-index-cleanflag 'dirty)))
  11063.          (if (and (eq bag 'irc-nicknames)
  11064.               (not (irc-recall fixed 'irc-notify-detected))
  11065.               (irc-recall fixed 'irc-notify-looked-for))
  11066.          (irc-who-is-on (irc-recall-all 'irc-notify-looked-for))))))))
  11067.  
  11068.  
  11069. (defun irc-debug-check-all-hashtables ()
  11070.   ""
  11071.   (let ((n (irc-internal-time)))
  11072.     (setq irc-userinfo (format "DEBUGGING CLIENT -- %s." n))
  11073.     (mapcar (function (lambda (p)
  11074.           (irc-debug-check-hashtable (car p) (cdr p) n)))
  11075.         '((irc-nicknames . irc-is-nickname)
  11076.           (irc-ignored-ppl . irc-is-nickname)
  11077.           (irc-linksinfo . nil)
  11078.           (irc-listtree . nil)
  11079.           (irc-notify-looked-for . irc-is-nickname)
  11080.           (irc-notify-detected . irc-is-nickname)
  11081.           (irc-namtree . nil)
  11082.           (irc-servernames . irc-is-hostname)
  11083.           (irc-subscribed-channels . irc-is-channelname)
  11084.           (irc-services . irc-is-nickname)
  11085.           (irc-whotree . nil)))))
  11086.  
  11087.  
  11088. (defun irc-debug-check-hashtable (bag chkfcn &optional mark)
  11089.   ""
  11090.   (let* ((data (irc-recall-all bag))
  11091.      (lst data)
  11092.      (id (if (null mark) "" mark))
  11093.      (consistent t)
  11094.      (doublettes nil))
  11095.     (sit-for 0)
  11096.     (irc-insert "DEBUG: %s checking if hashtable %s is consistent using %s."
  11097.         id bag chkfcn)
  11098.     (irc-insert "DEBUG: %s = %s." bag data)
  11099.     (while (not (null lst))
  11100.       (let* ((matches (irc-check-list data (car lst)))
  11101.          (l (length matches)))
  11102.     (cond ((= 1 l) (irc-insert "DEBUG: %s  OK, \"%s\" found once."
  11103.                    id (car lst)))
  11104.           ((= 0 l)
  11105.            (irc-insert "DEBUG: %s Huh? \"%s\" not found."
  11106.                id (car lst))
  11107.            (setq doublettes t))
  11108.           (t (irc-insert "DEBUG: %s ERROR \"%s\" FOUND %d TIMES."
  11109.                  id (car lst) l)
  11110.          (setq doublettes t)))
  11111.     (setq lst (cdr lst))))
  11112.     (irc-insert "DEBUG: %s checked for doublettes, done." id)
  11113.     (sit-for 0)
  11114.     (if (not (null chkfcn))
  11115.     (let ((lst data))
  11116.       (while (not (null lst))
  11117.         (cond ((funcall chkfcn (car lst))
  11118.            (irc-insert "DEBUG: %s item \"%s\" of %s -- OK."
  11119.                    id (car lst) bag))
  11120.           (t (irc-insert "DEBUG: %s item \"%s\" of %s FAILED CHECK."
  11121.                  id (car lst) bag)
  11122.              (setq consistent nil)))
  11123.         (setq lst (cdr lst)))))
  11124.     (irc-insert "DEBUG: %s done checking: doublettes %s, consistent %s"
  11125.         id (if doublettes "FAILED" "OK") (if consistent "OK" "FAILED"))
  11126.     (irc-insert "DEBUG: %s --------------" id)
  11127.     (sit-for 0)))
  11128.  
  11129.  
  11130. (defun irc-list-recall (item list)
  11131.   "Check if a string ITEM is in the LIST. The comparsion is not case
  11132. sensitive. If the item is found, return the stored spelling, else nil."
  11133.   (let ((ui (upcase item)))
  11134.     (while (and (not (null list))
  11135.         (string< ui (upcase (car list))))
  11136.       (setq list (cdr list)))
  11137.     (if (and (not (null list)) (string= (upcase (car list)) ui))
  11138.     (car list)
  11139.     nil)))
  11140.  
  11141.  
  11142. (defun irc-recall (item bag)
  11143.   "Check if a string ITEM is in the BAG. If so, return the stored spelling,
  11144. else ni. All checking is done without being case sensitive."
  11145.   (let* ((htbl (symbol-value bag))
  11146.      (idx (irc-hash-value item (aref htbl irc-hash-index-size))))
  11147.     (irc-list-recall item (aref (aref htbl irc-hash-index-bucketarray)
  11148.         (irc-hash-value item (aref htbl irc-hash-index-size))))))
  11149.  
  11150.  
  11151. (defun irc-recall-all (bag)
  11152.   "Return a sorted list representation of all strings in the BAG."
  11153.   ;; [size write-date cleanflag bucketarray]
  11154.   (let* ((htbl (symbol-value bag))
  11155.      (cached-data (aref htbl irc-hash-index-cleanflag))
  11156.      (is-clean (listp cached-data))
  11157.      (buckets (aref htbl irc-hash-index-bucketarray))
  11158.      (size (aref htbl irc-hash-index-size)))
  11159.     (cond ((not (= size (length buckets)))
  11160.        (irc-insert "%%Bad hash list %s, size != length bucketarray." bag)))
  11161.     (cond (is-clean cached-data)
  11162.       (t (let ((r nil)
  11163.            (i size)
  11164.            (a nil))
  11165.            (while (> i 0)
  11166.          (setq i (1- i)
  11167.                a (aref buckets i))
  11168.          (while (not (null a))
  11169.            (setq r (cons (car a) r)
  11170.              a (cdr a))))
  11171.            (let ((s (sort r '(lambda (a b)
  11172.                   (string< (upcase a) (upcase b))))))
  11173.          (aset htbl irc-hash-index-cleanflag s)
  11174.          s))))))
  11175.  
  11176.  
  11177. (defun irc-recall-all-and-display (bag ind &optional plur sing)
  11178.   "Enter the nodes in the BAG as seperate lines in the irc buffer. Entries
  11179. longer than 1 line are continued with an indentation of IND, a number.
  11180.  
  11181. If you supply the optional arguments PLUR and SING, then after the lines
  11182. a short message of the form \"[%d %s]\" is printed. If only PLUR is supplied,
  11183. it is always used. If both PLUS and SING is supplied, then SING is used if
  11184. exactly one line was printed, else PLUR is used."
  11185.   (let ((lst (irc-recall-all bag))
  11186.     (n 0)
  11187.     (irc-msg-cont-used (make-string ind ? )))
  11188.     (while lst
  11189.       (irc-insert "%s" (car lst))
  11190.       (setq n (1+ n)
  11191.         lst (cdr lst)))
  11192.     (if (stringp plur)
  11193.     (if (zerop n)            ;List empty?
  11194.         (if (irc-terminal-is-slow) ;When on a slow terminal, no list
  11195.         (irc-insert "%%No %s." plur) ; is kept.
  11196.         (irc-insert "%sEnd of (unsorted) %s list%s"
  11197.                 irc-msg-info-pre
  11198.                 plur
  11199.                 irc-msg-info-post))
  11200.         (irc-insert "%s%d %s%s"
  11201.             irc-msg-info-pre
  11202.             n
  11203.             (if (= n 1)
  11204.                 (if (stringp sing) sing plur)
  11205.                 plur)
  11206.             irc-msg-info-post))
  11207.     (irc-insert "%sEnd of (unsorted) list%s"
  11208.             irc-msg-info-pre
  11209.             irc-msg-info-post)))
  11210.   (irc-insert ""))
  11211.  
  11212.  
  11213. (defun irc-list-forget (item list)
  11214.   "Remove a string ITEM from a LIST of string, if it's found. The comparsions
  11215. are not case sensitive."
  11216.   (let ((ui (upcase item)))
  11217.     (cond ((null list) list)
  11218.       ((string< (upcase (car list)) ui) list)
  11219.       ((string= (upcase (car list)) ui) (cdr list))
  11220.       (t (let ((ptr list))
  11221.            (while (and (not (null (cdr ptr)))
  11222.                (string< ui (upcase (car (cdr ptr)))))
  11223.          (setq ptr (cdr ptr)))
  11224.            (cond ((null (cdr ptr)) nil)
  11225.              ((string< (upcase (car (cdr ptr))) ui) nil)
  11226.              ((string= (upcase (car (cdr ptr))) ui)
  11227.               (rplacd ptr (cdr (cdr ptr))))
  11228.              (t (error (concat  "irc-list-forget: NOT possible!"
  11229.                     " item=%s, list=%s, ptr=%s.")
  11230.                    item list ptr))))
  11231.          list))))
  11232.  
  11233.  
  11234. (defun irc-forget (item bag)
  11235.   "Remove a string ITEM from the BAG, if the item was there. Not case
  11236. sensitive."
  11237.   (let* ((htbl (symbol-value bag))
  11238.      (idx (irc-hash-value item (aref htbl irc-hash-index-size)))
  11239.      (a (aref htbl irc-hash-index-bucketarray))
  11240.      (oldlen (length (aref a idx))))
  11241.     (aset a idx (irc-list-forget item (aref a idx)))
  11242.     (if (and (eq bag 'irc-nicknames)
  11243.          (irc-recall item 'irc-notify-detected)
  11244.          (irc-recall item 'irc-notify-looked-for))
  11245.     (irc-who-is-on (irc-recall-all 'irc-notify-looked-for)))
  11246.     (cond ((not (= oldlen (length (aref a idx))))
  11247.        (aset htbl irc-hash-index-timestamp (irc-internal-time))
  11248.        (aset htbl irc-hash-index-cleanflag 'dirty)))))
  11249.  
  11250.  
  11251. (defun irc-forget-all (bag)
  11252.   "Empty BAG."
  11253.   (let* ((htbl (symbol-value bag))
  11254.      (size (aref htbl irc-hash-index-size))
  11255.      (a (aref htbl irc-hash-index-bucketarray))
  11256.      (i 0))
  11257.     (while (< i size)
  11258.       (aset a i nil)
  11259.       (setq i (1+ i)))
  11260.     (aset htbl irc-hash-index-timestamp (irc-internal-time))
  11261.     (aset htbl irc-hash-index-cleanflag 'empty)))
  11262.  
  11263.  
  11264. (defun irc-get-names-and-servers ()
  11265.   "Return a alphabetically sorted list of all the nick- and servernames which
  11266. are known by the client."
  11267.   (if (not (boundp 'irc-cache-n+s))
  11268.       (set (make-local-variable 'irc-cache-n+s) nil))
  11269.   (if (or (null irc-cache-n+s)        ;No data yet?
  11270.       (< (car irc-cache-n+s)    ;Nicknames updated?
  11271.          (aref irc-nicknames irc-hash-index-timestamp))
  11272.       (< (car irc-cache-n+s)    ;Servernames updated?
  11273.          (aref irc-servernames irc-hash-index-timestamp)))
  11274.       (let* ((servers (irc-recall-all 'irc-servernames))
  11275.          (names (irc-recall-all 'irc-nicknames))
  11276.          (data nil))
  11277.     (while (not (null servers))
  11278.       (setq data (cons (car servers) data)
  11279.         servers (cdr servers)))
  11280.     (while (not (null names))
  11281.       (setq data (cons (car names) data)
  11282.         names (cdr names)))
  11283.     (let ((s (sort data '(lambda (a b) (string< (upcase a) (upcase b))))))
  11284.       (setq irc-cache-n+s (cons (irc-internal-time) s)))))
  11285.   (cdr irc-cache-n+s))
  11286.  
  11287.  
  11288. (defun irc-get-channels-and-nicks-and-servers ()
  11289.   "Return a alphabetically sorted list of all the channel-, nick- and server-
  11290. names which are known by the client."
  11291.   (if (not (boundp 'irc-cache-c+n+s))
  11292.       (set (make-local-variable 'irc-cache-c+n+s) nil))
  11293.   (if (or (null irc-cache-c+n+s)
  11294.       (< (car irc-cache-c+n+s)
  11295.          (aref irc-subscribed-channels irc-hash-index-timestamp))
  11296.       (< (car irc-cache-c+n+s)
  11297.          (aref irc-nicknames irc-hash-index-timestamp))
  11298.       (< (car irc-cache-c+n+s)
  11299.          (aref irc-servernames irc-hash-index-timestamp)))
  11300.       (let* ((channels (irc-recall-all 'irc-subscribed-channels))
  11301.          (nicks (irc-recall-all 'irc-nicknames))
  11302.          (servers (irc-recall-all 'irc-servernames))
  11303.          (data nil))
  11304.     (while (not (null channels))
  11305.       (setq data (cons (car channels) data)
  11306.         channels (cdr channels)))
  11307.     (while (not (null nicks))
  11308.       (setq data (cons (car nicks) data)
  11309.         nicks (cdr nicks)))
  11310.     (while (not (null servers))
  11311.       (setq data (cons (car servers) data)
  11312.         servers (cdr servers)))
  11313.     (let ((s (sort data '(lambda (a b) (string< (upcase a) (upcase b))))))
  11314.       (setq irc-cache-c+n+s (cons (irc-internal-time) s)))))
  11315.   (cdr irc-cache-c+n+s))
  11316.  
  11317.  
  11318. (defun irc-sec-to-time (n)
  11319.   "Convert number of SECONDS into a time string of one of the following
  11320. formats \"SS seconds\" or \"MM minutes and SS seconds\"
  11321. or \"HH hours, MM minutes and SS seconds\"
  11322. or \"DD days, HH hourse, MM minutes and SS seconds\"."
  11323.   (let* ((one-minute 60)
  11324.      (one-hour (* 60 one-minute))
  11325.      (one-day (* 24 one-hour))
  11326.      (days (/ n one-day))
  11327.      (day-string (cond ((= 0 days) "")
  11328.                ((= 1 days) "1 day")
  11329.                (t (format "%d days" days))))
  11330.      (m (% n one-day))
  11331.      (hours (/ m one-hour))
  11332.      (hour-string (cond ((= 0 hours) "")
  11333.                 ((= 1 hours) "1 hour")
  11334.                 (t (format "%d hours" hours))))
  11335.      (l (% m one-hour))
  11336.      (minutes (/ l one-minute))
  11337.      (min-string (cond ((= 0 minutes) "")
  11338.                ((= 1 minutes) "1 minute")
  11339.                (t (format "%d minutes" minutes))))
  11340.      (seconds (% l one-minute))
  11341.      (sec-string (cond ((= 0 seconds) "")
  11342.                ((= 1 seconds) "1 second")
  11343.                (t (format "%d seconds" seconds)))))
  11344.     ;; Possible combinations:
  11345.     ;; D H M S
  11346.     ;; 0 0 0 0 = none
  11347.     ;; 0 0 0 1 = S
  11348.     ;; 0 0 1 0 = M
  11349.     ;; 0 0 1 1 = MS
  11350.     ;; 0 1 0 0 = H
  11351.     ;; 0 1 0 1 = HS
  11352.     ;; 0 1 1 0 = HM
  11353.     ;; 0 1 1 1 = HMS
  11354.     ;; 1 0 0 0 = D
  11355.     ;; 1 0 0 1 = DS
  11356.     ;; 1 0 1 0 = DM
  11357.     (let ((acc nil))
  11358.       (if (not (string= "" sec-string)) (setq acc (cons sec-string acc)))
  11359.       (if (not (string= "" min-string)) (setq acc (cons min-string acc)))
  11360.       (if (not (string= "" hour-string)) (setq acc (cons hour-string acc)))
  11361.       (if (not (string= "" day-string)) (setq acc (cons day-string acc)))
  11362.       (cond ((= 0 (length acc)) "0 seconds")
  11363.         ((= 1 (length acc)) (car acc))
  11364.         ((= 2 (length acc)) (format "%s and %s" (nth 0 acc) (nth 1 acc)))
  11365.         ((= 3 (length acc))
  11366.          (format "%s, %s and %s" (nth 0 acc) (nth 1 acc) (nth 2 acc)))
  11367.         (t (format "%s, %s, %s and %s"
  11368.                (nth 0 acc) (nth 1 acc) (nth 2 acc) (nth 3 acc)))))))
  11369.  
  11370.  
  11371. (defun irc-burst-comma (str)
  11372.   "Take a comma or space separated STR and turn it into a list of its elements.
  11373. Example: \"1, 2,3,4,  6  7\" becomes the list
  11374. (\"7\" \"6\" \"4\" \"3\" \"2\" \"1\")."
  11375.   (let (list sub (beg 0))
  11376.     (string-match "" str)
  11377.     (while (string-match ",+\\| +\\|,+ +" str beg)
  11378.       (if (not (string= (setq sub (substring str beg (match-beginning 0))) ""))
  11379.           (setq list (cons sub list)))
  11380.       (setq beg (match-end 0)))
  11381.     (if (/= (length str) beg) (cons (substring str beg) list) list)))
  11382.  
  11383.  
  11384.  
  11385. ;; miscellaneous other commands (usually from other sources)
  11386.  
  11387. ;; this makes up for not being able to provide a :test to memq.
  11388. ;; irc-member-general by Bard Bloom <bard@theory.lcs.mit.com>
  11389. (defun irc-member-general (x l comparison)
  11390.   "Is X a member of L under COMPARISON?"
  11391.   (let ((not-found t))
  11392.     (while (and l not-found)
  11393.       (setq not-found (not (funcall comparison x (car l)))
  11394.             l         (cdr-safe l)))
  11395.     (not not-found)))
  11396.  
  11397.  
  11398. ;; wish i could remember who I got this from; I had to patch it to work
  11399. ;; with the minibuffer correctly but it is mostly untouched.
  11400. (defun irc-walk-windows (proc &optional no-mini)
  11401.   "Applies PROC to each visible window (after selecting it, for convenience).
  11402. Optional arg NO-MINI non-nil means don't apply PROC to the minibuffer
  11403. even if it is active."
  11404.   (let* ((real-start (selected-window))
  11405.      (start (next-window real-start no-mini))
  11406.      (current start) done)
  11407.     (while (not done)
  11408.       (select-window current)
  11409.       (funcall proc)
  11410.       (setq current (next-window current no-mini))
  11411.       (setq done (eq current start)))
  11412.     (select-window real-start)))
  11413.  
  11414.  
  11415. (defun irc-count-windows (&optional no-mini)
  11416.   "Returns the number of visible windows.
  11417. Optional arg NO-MINI non-nil means don't count the minibuffer
  11418. even if it is active."
  11419.   (let ((count 0))
  11420.     (irc-walk-windows (function (lambda () (setq count (1+ count)))) no-mini)
  11421.     count))
  11422.  
  11423.  
  11424. ;; swiped from minibuf.el, but made exclusive to * Minibuf-n*.
  11425. (defun irc-minibuffer-message (format &rest args)
  11426.   "Print a temporary message at the end of the Minibuffer.
  11427. After 2 seconds or when a key is typed, erase it."
  11428.   (if (zerop (minibuffer-depth)) (apply 'message format args)
  11429.       (let (p)
  11430.     (save-excursion
  11431.       (set-buffer (concat " *Minibuf-" (1- (minibuffer-depth)) "*"))
  11432.       (unwind-protect
  11433.            (progn
  11434.          (setq p (goto-char (point-max)))
  11435.          (insert (apply 'format format args))
  11436.          (sit-for 2))
  11437.         (delete-region p (point-max)))))))
  11438.  
  11439.  
  11440. (defun irc-find-to (str &optional explicit)
  11441.   "Find the part of STRING that IRC-mode will interpret as the sendlist.
  11442. If no explicit list is found, irc-default-to is returned.  The string returned
  11443. is either : or ; terminated.
  11444.  
  11445. If optional EXPLICIT is non-nil, then return t if a sendlist was explicitly
  11446. specified, nil if the sendlist was implicit."
  11447.   (let* ((part (if (string-match "^ *\\([^;:]*\\) *\\([:;]\\)" str)
  11448.            (subfield str 1)
  11449.            nil))
  11450.      (retval (if (not part)
  11451.              ""
  11452.              (concat part (subfield str 2))))
  11453.      (matched (and part
  11454.                (or (string= "" part)
  11455.                (let ((s part))
  11456.                  (while (string-match (concat "^ *\\([^ ,]+\\)"
  11457.                               " *, *")
  11458.                           s)
  11459.                    (let ((b1 (match-beginning 1))
  11460.                      (e0 (match-end 0))
  11461.                      (e1 (match-end 1)))
  11462.                  (if (irc-is-receiver (substring s b1 e1))
  11463.                      (setq s (substring s e0))
  11464.                      (setq s ":"))))
  11465.                  (irc-is-receiver s))))))
  11466.     (if explicit matched (if matched retval irc-default-to))))
  11467.  
  11468.  
  11469. (defun irc-find-message (string)
  11470.   "Find the message that IRC will see if STR were sent.  For messages
  11471. sent with explicit lists, this is everything following the colon or
  11472. semi-colon.  For everything else, it is just the string."
  11473.   (substring string (length (irc-find-to string))))
  11474.  
  11475.  
  11476.  
  11477. ;; functions for the irc-history list
  11478. (defun irc-add-to-hist (str)
  11479.   "Put STRING at the head of the irc-history list."
  11480.   (if (string-match "^[;:]" str)
  11481.       (setq str
  11482.             (concat irc-last-explicit (substring str 1 (length str)))))
  11483.   (setq irc-history (append (list str) irc-history))
  11484.   (and (> (length irc-history) irc-max-history)
  11485.        (setq irc-history (reverse (cdr (reverse irc-history))))))
  11486.  
  11487.  
  11488. (defun irc-yank-prev-command ()
  11489.   "Put the last IRC /command in the input-region."
  11490.   (interactive)
  11491.   (delete-region irc-mark (goto-char (point-max)))
  11492.   (insert "/" irc-last-command)
  11493.   (goto-char (1+ irc-mark)))
  11494.  
  11495.  
  11496. (defun irc-history-prev (arg)
  11497.   "Select the previous message in the IRC history list.  ARG means
  11498. select that message out of the list (0 is the first)."
  11499.   (interactive "P")
  11500.   (let ((str (nth (or arg (1+ (or irc-history-index 0))) irc-history)))
  11501.     (if (not str)
  11502.         (message "No message %d in history." (or arg (1+ irc-history-index)))
  11503.     (delete-region irc-mark (goto-char (point-max)))
  11504.     (insert str)
  11505.     (goto-char irc-mark)
  11506.     (setq irc-history-index (or arg (1+ irc-history-index))))))
  11507.  
  11508.  
  11509. (defun irc-history-next (arg)
  11510.   "Select the next message in the IRC history list.  With prefix ARG
  11511. select that message out of the list (same as irc-history-prev if
  11512. called with a prefix arg)."
  11513.   (interactive "P")
  11514.   (if arg (irc-history-prev arg)
  11515.       (if (= irc-history-index -1)
  11516.       (message "No next message in history.")
  11517.       (delete-region irc-mark (goto-char (point-max)))
  11518.       (insert (if (zerop irc-history-index) ""
  11519.               (nth (1- irc-history-index) irc-history)))
  11520.       (setq irc-history-index (1- irc-history-index)))))
  11521.  
  11522.  
  11523. (defun irc-kill-input ()
  11524.   "Delete the input region and start out fresh.  This function is recommended
  11525. over any other way of killing the input-region interactively because it
  11526. also resets the index for the history list."
  11527.   (interactive)
  11528.   (delete-region irc-mark (goto-char (point-max)))
  11529.   (setq irc-history-index -1))
  11530.  
  11531.  
  11532. (defun irc-complete-name ()
  11533.   "Not completed yet."
  11534.   (interactive)
  11535.   (let* ((end (point))
  11536.      (beg (save-excursion
  11537.         (while
  11538.             (and (not (= (point) (point-min)))
  11539.              (irc-is-receiver (buffer-substring (1- (point)) end)))
  11540.           (backward-char 1))
  11541.         (point)))
  11542.      (pattern (downcase (buffer-substring beg end)))
  11543.      (alist (mapcar (function (lambda (s)
  11544.               (list (downcase s))))
  11545.             (irc-get-names-and-servers)))
  11546.      (completion (try-completion pattern alist)))
  11547.     (cond ((eq completion t))        ;Exact match.
  11548.       ((null completion)        ;No match at all.
  11549.        (ding)
  11550.        (message "Can't find completion for \"%s\"" pattern))
  11551.       ((not (string= pattern completion)) ;Complete (but maybe not unique).
  11552.        (delete-region beg end)
  11553.        (insert completion)) 
  11554.       (t (let* ((name (irc-nuke-whitespace
  11555.                (completing-read "Who? "
  11556.                         alist
  11557.                         nil
  11558.                         nil
  11559.                         pattern))))
  11560.            (delete-region beg end)
  11561.            (insert name))))))
  11562.  
  11563.  
  11564. (defun irc-line-count (buf)
  11565.   "Returns the size of the buffer BUF."
  11566.   (save-excursion (set-buffer buf)
  11567.           (goto-line 1)
  11568.           (count-lines (point-min) (1+ (buffer-size)))))
  11569.  
  11570.  
  11571. (defun irc-log-in-debug-buffer (line)
  11572.   "Append a LINE to the debug buffer associated with a session, appending a
  11573. newline to the line. If the debug buffer doesn't exist, do nothing."
  11574.   (let ((debug-buffer (concat (buffer-name (current-buffer))
  11575.                   "-*debug*")))
  11576.     (if (get-buffer debug-buffer)
  11577.     (irc-append-string-to-buffer line (get-buffer debug-buffer)))))
  11578.  
  11579.  
  11580. (defun irc-append-string-to-buffer (str buf)
  11581.   "Append the string STR to the buffer BUF as a line."
  11582.   (save-excursion (set-buffer buf)
  11583.           (goto-char (1+ (buffer-size)))
  11584.           (insert str "\n")))
  11585.  
  11586.  
  11587. (defun irc-get-buffers-nth-line (n buf)
  11588.   "Returns the line number N in the buffer BUF as a string.
  11589. The first line inb the buffer is line number 1.
  11590. If the buffer is empty, returns \"\"."
  11591.   (if (>= (irc-line-count buf) n)
  11592.       (save-excursion (set-buffer buf)
  11593.               (goto-line n)
  11594.               (let ((p (point)))
  11595.             (search-forward "\n" (1+ (buffer-size)) 'non-nil-non-t)
  11596.             (buffer-substring p (1- (point)))))
  11597.     ""))
  11598.  
  11599.  
  11600. (defun irc-sort-lines-in-buffer (buf &optional reverse)
  11601.   "Sort the lines in buffer BUF.
  11602. An optional argument REVERSE can be supplied as non-nil to sort the buffer
  11603. in reversed order."
  11604.   (save-excursion (set-buffer buf)
  11605.           (sort-lines reverse (point-min) (1+ (buffer-size)))))
  11606.  
  11607.  
  11608. (defun irc-history-menu ()
  11609.   "List the history of messages kept by irc-mode in another buffer."
  11610.   (interactive)
  11611.   (let ((pop-up-windows t) (hist irc-history) (line 0))
  11612.     (save-excursion
  11613.       (set-buffer (get-buffer-create "*IRC History*"))
  11614.       (fundamental-mode)
  11615.       (erase-buffer)
  11616.       (while hist
  11617.         (insert (format "%2d: %s\n" line (car hist)))
  11618.         (setq hist (cdr hist))
  11619.         (setq line (1+ line)))
  11620.       (if (zerop line)
  11621.           (insert "No messages have been sent to IRC yet."))
  11622.       (set-buffer-modified-p nil)
  11623.       (goto-char (point-min)))
  11624.     (display-buffer "*IRC History*")))
  11625.  
  11626.  
  11627.  
  11628. ;; stuff about irc-mode
  11629. (defun irc-version (&optional arg)
  11630.   "Print the current version of irc.el in the minibuffer.  With optional
  11631. ARG, insert it in the current buffer."
  11632.   (interactive "P")
  11633.   (if arg
  11634.       (insert irc-version)
  11635.       (princ irc-version)))
  11636.  
  11637.  
  11638. (defun irc-fatal (msg item)
  11639.   (irc-insert "FATAL ERROR: \"%s\" \"%s\"." msg item))
  11640.  
  11641.  
  11642. ;;; Force GC to prevent GC bug in older (pre 18.57) GNU Emacs'es.
  11643. (garbage-collect)
  11644.  
  11645. (defun irc-execute-news (dummy)
  11646.   "Shows news about latest changes to this GNU Emacs client.
  11647. Even shows news about old changes -- what a wonderous function indeed.
  11648.  
  11649. Latest changes to IRC mode, oldest at bottom, newest at top:
  11650.  
  11651. *** NEEDS TO BE UPDATED ***"
  11652.   (interactive '(""))
  11653.   (save-excursion
  11654.     (set-buffer (get-buffer-create "*IRC-mode News*"))
  11655.     (erase-buffer)
  11656.     (insert (documentation 'irc-execute-news))
  11657.     (goto-char (point-min)))
  11658.   (display-buffer "*IRC-mode News*"))
  11659.  
  11660.  
  11661. (defun irc-report-bug (client-message server-message type)
  11662.   ""
  11663.   (irc-insert "%%%s" client-message)
  11664.   (irc-insert "%% \"%s\" (%s)." server-message type)
  11665.   (irc-insert "%% Please tell %s, it might be a bug." irc-hacker)
  11666.   (irc-insert "%% (Client \"%s\", server %s version %d.%d)."
  11667.           irc-version irc-major-version irc-minor-version))
  11668.  
  11669.  
  11670. ;; We're done defining an irc mode, so let's provide it.
  11671. (provide 'irc)
  11672.