1
0
mirror of https://github.com/GeorgeMcMullen/rxIRC.git synced 2026-01-27 04:33:01 +00:00
Files
GeorgeMcMullen.rxIRC/rxirc.exec
2013-06-08 16:30:31 -07:00

1227 lines
36 KiB
Plaintext

/* rxIRC
* Internet Relay Chat client program for VM/CMS systems
* written by Carl 'LynX' v. Loesch (loesch@informatik.uni-oldenburg.de)
* created by Lynx (244661 at DOLUNI1) on Thursday, 14 Feb 1991
* Credits for suggestions, code contribution, miscellaneous help go to:
* Jose Maria Blasco, Doug Sewell, Martin Ahlborn, Jim McMaster,
* Scott Maxell, Juan Courcoul, Rob Blais, Mike Letourneau, Grant Pair
* (in historical order mostly). Thank y'all very much!
*
* Extras (Pluses) written by George McMullen
* Thanks to Carl 'LynX' v. Loesch for his suggestions, ideas, and
* explanations of code, which made much of the additions possible.
*
* requires RXSOCKET MODULE version 2 by Arty Ecock (eckcu@cunyvm.bitnet)
*
* Copyright (C)1991,2,3,4 by LynX & CvO University Oldenburg, Germany
* You may freely use this software at your own risk.
*
* Warning: Changing the code to display fake user information is
* considered an offense by many IRC administrators!
*
*/ progname='rxIRC'; vers='2.2 (GM Branch)'; trace 'O'
address "COMMAND"; signal on HALT; "VMFCLEAR"
cmds='AWAY AWAIT ADMIN CHANNEL CONNECT DEOP DIE HASH INFO ISON JOIN KICK',
'KILL LIST LINKS LUSERS MODE MAIL MOTD NAMES NICK NOTICE NOTE OPER PASS',
'PART REHASH RESTART QUIT SERVICE SQUIT SUMMON STATS TIME TRACE',
'USERS USERHOST VOICE WHOWAS WALLOPS WALL XTRA'
log=0; query=; ignore=; omit=; lastjoin=; lastsender=; lastorigin=;
export=; onoff.1="on"; onoff.0="off"
invitation=; away=; ll.=; curll=1; logevent=0; target=time('R')
v.=; al.=; varnames=; aliasnames=; cmdchar=; userinfo=; sourcing=0
have_rxwt=0; who_empty=0; catmode=0; catlist=; abortsource=0; skiplines=0
nflist=; nfhere=; nfcatch=0
jumpcoms=0;sourcenum=0;numons=0;display='display'
call SET 'display On'
"EXECIO * CP (STEM PF. STRING QUERY PF"
do i=1 to pf.0
a=word(pf.i,2)
if a/='UNDEFINED' & a/='RETRIEVE' then,
"CP SET" subword(pf.i,1,2) '!'subword(pf.i,3)
end
"EXECIO * CP (STEM QT. STRING QUERY TERM"
"CP TERM LINEND OFF"
"CP TERM CHARDEL OFF"
"CP TERM LINESIZE 130"
sock=; buffer=; alphalo=xrange('a','z'); alphahi=xrange('A','Z')
lf='25'x; cr='0d'x; msa='01'x; rev='02'x; beep='2fx; undl='32'x
bold='1f'x; hi='1de8'x; lo='1d60'x; yo='1d44'x
nice.=; u@n.=; via.=;
realname=; servername=;
ignore_reply = "Your messages are not being received."
"IDENTIFY (LIFO"; pull me . mynode . rscs a .
logfile=translate(a,'_','/') "IRCLOG A0"
writelog="EXECIO 1 DISKW" logfile "(STRI"
'STATE RXSOCKET MODULE *'
if rc=0 then do
parse value SOCKET('version') with . . rc .
if rc >= 2.0 then rc=0
else rc=28
end
if rc/=0 then call BYE "RXSOCKET version 2 required"
do 3
parse value SOCKET('INITIALIZE', "rxIRC", 7) with rc . etc
if rc=2004 then do
say '<cleaning up a zombie rxsocket nucext>'
'NUCXDROP RXSOCKET'
end
else leave
end
if rc/=0 then call BYE "socket init error:" etc
parse value SOCKET('GETHOSTNAME') with . hostname
parse value SOCKET('GETDOMAINNAME') with . domain
'REXXWAIT TEST'
select
when rc=0 then nop
when rc=1 then do
'REXXWAIT LOAD'
if rc/=0 then call BYE "REXXWAIT can't be loaded"
end
otherwise call BYE "REXXWAIT MODULE required"
end
have_rxwt=1
'IMMCMD SET HI'
"NAMEF :NICK RXIRC :SERVER :PORT :LOGGING :QUIET_IGNORE :SHOW_TIME ",
":BOLD_CHAR :BEEP_CHAR :LOUD_BEEPS :SHOW_NUMBERS :LIST_ALL :BROWSER",
":PASS (LIFO FILE RXIRC"
if rc/=0 then call BYE "missing or unreadable RXIRC NAMES file"
parse pull server_pass
pull viewcmd; pull def_listall; pull def_numb; pull def_loud
parse pull beepch; parse pull boldch; parse pull showtime; pull def_quiet
pull def_log; parse pull def_port; parse pull def_server
if viewcmd='' then call BYE 'no ":browser" tag defined in RXIRC NAMES'
if beepch='' then beepch=d2c(0)
if boldch='' then boldch=d2c(0)
"GLOBALV SELECT CENV GET IRCNICK IRCSERVER IRCNAME IRCPORT"
"NAMEFIND :USERID" me ":NICK :NAME :MOTTO :CMDCHAR :IRCNICK :IRCNAME ",
":WWWPORT (LIFO"
if rc=0 then do
parse pull wwwport; if wwwport/='' & ^datatype(wwwport,'W') then do
wwwport=; call BYE "WWW port must be numeric"; end
parse pull name; parse pull nick
if ircnick="" then ircnick=nick
if ircname="" then ircname=name
parse pull cmdchar; parse pull userinfo
parse pull realname; parse pull nick
if ircnick="" then ircnick=nick
if ircname="" then ircname=realname
end
parse arg nick server name '('o; upper o
if nick/='' then ircnick = nick
if ircnick='' then ircnick=me
capnick = translate(ircnick)
if server/='' then ircserver=server
else if ircserver='' then ircserver=def_server
if name/='' then ircname = name
if ircname='' then ircname=me "at" mynode".bitnet"
if cmdchar="" then cmdchar="/"
do while o/=""
parse var o opt o
select
when abbrev("PORT", opt, 1) then parse var o ircport o
when abbrev("LIST_ALL", opt, 2) then parse var o def_listall o
when abbrev("LOGGING", opt, 1) then parse var o def_log o
when abbrev("LOUD_BEEPS", opt, 3) then parse var o def_loud o
when abbrev("NUMBERS", opt, 1) then parse var o def_numb o
when abbrev("QUIET_IGNORE", opt, 1) then parse var o def_quiet o
otherwise call BYE "unknown option" opt
end
end
if ircport='' then ircport=def_port
if def_listall="ON" then listall=1; else listall=0
if def_log="ON" then log=1; else log=0
if def_loud="ON" then loud=1; else loud=0
if def_numb="ON" then numb=1; else numb=0
if def_quiet="ON" then quiet=1; else quiet=0
if log then writelog "IRC Session started on" date() "at" time()
if datatype(left(ircnick,1))='NUM' then ircnick='u'ircnick
if ^datatype(showtime,'w') then showtime=80
if userinfo="" then userinfo="- no info given by user -"
parse value RESETVALUE('ALL') with rc .
if rc/=0 then call BYE "problem w/RESETVALUE"
parse value SETVALUE('TIME ==:==:00') with rc .
if rc/=0 then call BYE "problem w/SETVALUE TIME"
parse value SETVALUE('MSG IUCV') with rc .
if rc/=0 then call BYE "problem w/SETVALUE MSG IUCV"
if wwwport<1024 then wwwport=''
else do
parse value SOCKET('SOCKET') with rc www etc
if rc/=0 then call BYE "socket:" etc
parse value SOCKET('SETSOCKOPT',www,'SOL_SOCKET','SO_ASCII','ON'),
with rc . etc
if rc/=0 then call BYE "setsockopt:" etc
parse value SOCKET('BIND', www, 'AF_INET' wwwport SOCKET('GETHOSTID')),
with rc . etc
if rc/=0 then call BYE "bind:" etc
parse value SOCKET('LISTEN', www, 9) with rc . etc
if rc/=0 then call BYE "listen:" etc
parse value SOCKET('IOCTL', www, 'FIONBIO', 1) with rc . etc
if rc/=0 then call BYE "nonblocking i/o:" etc
myurl="http://"hostname"."domain":"wwwport"/"
end
call S progname||hi||vers||yo"- You are" ircnick "("ircname")"
call S "Logging is" onoff.log"; Audible bells are",
onoff.loud"; Quiet ignore is" onoff.quiet
if www/='' then call S "Builtin httpd active as"hi||myurl||yo
call CONNECT ircserver
call SOURCE "PROFILE", 1
if nflist/='' then do; nfcatch=1; call SEND "ISON" nflist; end
call S copies("-",79)lo
do forever
"IMMCMD STATUS HI"
if rc/=0 then call S,
'Sorry, "hi" is a system reserved word. Try an other operating system.'
parse value WAIT('TIME','CONS','MSG','SOCKET READ *') with rc type data
select
when rc/=0 then call BYE "REXXWAIT returning" rc
when type='SOCKET' & data='READ' sock then do
parse value SOCKET('READ', sock) with rc . data
if rc=54 then call BYE
if rc/=0 then call BYE 'socket read error' rc
buffer = buffer || data
do forever
if index(buffer, lf)=0 then leave
parse var buffer in (lf) buffer
see=PARSE(strip(in,,cr))
parse var see com sndr' ### 'eye
call OUT eye
if sndr/='' & sndr/=servername & pos(sndr,v.0)^=0 then
call SET 0 sndr
see=com
do i= 0 to 9
see=see v.i
end
upper see
if numons>0 then do test=1 to numons
parse var on.test look '::' com
upper look
do exam=1 to words(look)
single=word(look,exam)
if single=word(see,exam)|single="*" then iterate
if right(single,1)="*" then
if pos(left(single,length(single)-1),word(see,exam))=1 then
iterate
if left(single,1)="*" then
if right(single,1)="*" then
if pos(substr(single,2,length(single)-2),word(see,exam)),
>=1 then iterate
else nop
else
if lastpos(right(single,length(single)-1),word(see,exam)),
= length(word(see,exam))-(length(single)-2)&,
length(word(see,exam))-(length(single)-2)^=0 then iterate
leave
end
if exam=words(look)+1 then call SHELL com
end
end
end
when type = 'CONS' then if data/='' then do
rc=time('R')
call EDIT data
curll=curll+1; ll.curll=hi||data||lo; k=curll-50; ll.k=;
if log then writelog ' 'data
end
when type = 'MSG' then do
parse var data . . no'('id'): 'data
if id='' then id='RSCS'
origin=id'@'no
ni=NICE(origin)
if FINDM(ignore,origin) | FINDM(ignore,ni) then do
if ^quiet & left(data,1)/='*' then call TELL origin '*' ignore_reply
end; else do
call OUT hi||ni':'lo||data
if away/='' & left(data,1)/='*' & origin/=lastorigin then do
call TELL origin '* away:' away
lastorigin = origin
end
end
end
when type = 'TIME' then do
parse var data . hh':'mm':' .
if datatype(mm/showtime,'w') then call S 'It is now' hh':'mm
if nflist/='' then do; nfcatch=1; call SEND "ISON" nflist; end
'EXECIO 1 CP(VAR A STR Q' me
parse var a . '-' a .
if a='DSC' then do
data='virtual machine runs disconnected'
call SEND 'QUIT :'data
call BYE data
end
end
when type='SOCKET' then do
parse var data . gsock
if gsock=www then do
parse value SOCKET('ACCEPT', www) with rc gsock . gport gipnum
end; else do
parse value SOCKET('READ', gsock) with rc . data
if rc=54 then iterate
if rc/=0 then call S 'Read error on http connection' gsock '('rc')'
else do
if data='' then do; SOCKET('CLOSE', gsock); iterate; end
parse var data cmd url .
parse var url URL(lf) .
if url='/' then url='/index.html'
parse var url '/'fn'.'ft'/' x; upper fn ft
if x='' & fn/='' & fn/='*' & ft/='' & ft/='*' &,
(cmd='GET'|cmd='HEAD') & FINDM(export,fn'.'ft) then do
call S 'httpd: request from' gipnum':' cmd url
/* 'MAKEBUF'; 'LISTFILE' fn ft '(STACK'; t=rc; 'DROPBUF' */
'STATE' fn ft
if rc=0 then do
call WRITE gsock "HTTP/1.0 200 Sure"
call WRITE gsock "Server:" progname"/"vers
if ft='HTML' then ct='html'; else ct='plain'
call WRITE gsock "Content-type: text/"ct
call WRITE gsock ''
if cmd='GET' then call WRITEFILE gsock fn ft pubmode
end
end; else call S 'httpd: invalid request ('cmd url') from' gipnum
SOCKET('SHUTDOWN', gsock)
end
end
end
otherwise call S 'Unexpected event:' type data
end
end
PARSE:
parse arg a
if loud & pos(beep,a)/=0 then "BEEP"
tu=; a=translate(a,"%"||beepch||"_",rev||beep||undl); bm=;
i=1; j=0; do forever; i=index(a,bold,i)
if i=0 then leave
if j=0 then a=insert(hi,a,i)
else a=insert(lo,a,i)
a=delstr(a,i,1)
j=1-j
end
if j=1 then a=a||lo
if left(a,1)=':' then do
parse var a ':'s m e f ':'g
parse var s s"!"sad
end
else do; s=''; parse var a m e f ':'g; end
f=strip(f)
logevent = 1
select
when m='CHANNEL' then if e="0"
then tu='***' s 'leaves this channel'
else tu='***' s 'joins this channel'
when m='INVITE' then do
f=strip(word(f g,1))
invitation = f
lastsender = s
tu='***' s '('sad') invites you to channel' f g; end
when m='JOIN' then do
e=strip(word(e g,1))
tu='***' s '('sad') joins channel' e
if s=ircnick then target=translate(e)
else lastjoin=s
end
when m='KICK' then tu='***' s 'kicks' f 'off channel' e '('g')'
when m='KILL' then tu='You were killed by' s subword(g,2)
when m='MODE' then tu='Mode change:' s 'sets' f 'on' e||g
when m='MSG' then do
tu='<'s'>' g
m='PUBLIC'
end
when m='NICK' then tu='***' s 'is now known as' e||g
when m='NOTICE' then select
when s='' | s=servername then do
if word(g,1)="***" then tu=subword(g,2)
else tu=g
a=; parse var tu 'Your host is 'g'['a .
if a/='' then servername=g
end
when translate(e)=capnick then do
if ^FINDM(ignore,s) & ^FINDM(ignore,sad) then do
tu='-'s'-' g; lastsender=s
end
end
otherwise if ^FINDM(omit,s) & ^FINDM(omit,sad) then tu='-'s':'e'-' g
end
when m='PART' then tu='***' s 'leaves channel' e
when m='PING' then call SEND("PONG :"ircnick)
when m='PRIVMSG' then do
if translate(e)=capnick then do
if FINDM(ignore,s) | FINDM(ignore,sad) then do
if ^quiet then call SEND('NOTICE' s ':'ignore_reply)
return ''; end
else do
if CTCP(1 g) then do
tu='*'s'*' g
m='MSG'
end
else do
m='CTCP'
parse var g . (msa) bm g (msa) .
bm=s bm g
end
lastsender=s
end
end
else if ^FINDM(omit,s) & ^FINDM(omit,sad) then do
if CTCP(0 g) then do
m='CTCP'
parse var g . (msa) bm g (msa) .
bm=s bm g
end
if translate(e)=target then then if CTCP(0 g) then do
yu='<'s'>' g
m='PUBLIC'
end
otherwise if CTCP(0 g) then do
tu='<'s':'e'>' g
m='PUBLIC'
end
end
end
when m='QUIT' then tu='Signoff by' s '('g')'
when m='TOPIC' then tu='***' s 'sets the topic to:' g
when m='WALLOPS' then tu='Wallops from' s':' g
when m='WALL' then tu='Broadcast from' s':' g
when m='221' then tu='Your mode is' g
when m='301' then tu=f 'is away:' g
when m='302' then do
parse var g ni'='uh
if left(uh,1)='+' then aw='here'
else aw='away'
tu=ni 'is' aw '('substr(uh,2)')'
end
when m='303' & nfcatch then call ISON g
when m='311' then do
parse var f ni ui no .
tu=ni 'is' ui'@'no '('g')'
end
when m='314' then do; parse var f ni ui no .
tu=ni 'was' ui'@'no '('g')'; end
when m='312' then tu='via' word(f,2) '('g')'
when m='315' then if who_empty then do
bm='No matches for /who'
call S bm
end
when m='319' then tu='on channels:' g
when m='317' then tu='apparently idle' word(f,2)/60 'minutes'
when m='322' then do
parse var f ch n .
if ch/='*' & substr(ch,2,1)/='27'x then do
if catmode then do; if n>4 then catlist=ch catlist; end
else if listall | n>7 then do
bm=left(ch,13) left(n,4)g
call OUT left(ch,13) left(n,4)g
end
end; end
when m='323' then do
if catmode then do
call OUT 'Channels:' catlist; catlist=; catmode=0; end; end
when m='324' then tu='The mode on channel' word(f,1) 'is' word(f,2)
when m='332' then tu='The topic is:' g
when m='341' then tu='Inviting' word(f,1) 'to channel' word(f,2)
when m='352' then do
parse var f ch us no . ni st .
if st="S" then return ''
who_empty=0; n=subword(g,2)
do forever; a=64-(length(n)+length(us)+length(no))
if (length(no)+a > 13) then leave
n=subword(n, 1, words(n)-1)'..'; end
if (a < 0) then k=hi||n||lo||us"@*"right(no,length(no)+a-1)
else if (ch/='*' & a>length(ch)) then
k=lo||ch||hi||n||lo||copies(' ',a-length(ch)-1)us"@"no
else k=hi||n||lo||copies(' ',a)us"@"no
bm=st ni ch us no n
call S left(st,3)yo||left(ni,9)k
end
when m='353' then do; ch=word(f,2); a=words(g)
if ch/='*' & (a>6 | translate(ch)=target) then do
bm=left(ch,15)||g
call OUT hi||left(ch,15)yo||g
end
end
when m='313'|m='364' then tu=f g
when m='004'|m='318'|m='321'|m='365'|m='366'|m='406' then nop
when m='001' then do; servername=s; tu=subword(g,1,words(g)-1); end
when m='376' then call SOURCE "CONNECT", 1
when m='252'|m='254' then tu=f g
otherwise select
when g="" then tu=f
when f=""|f=s then tu=g
otherwise tu=f":" g
end
if s/="" & s/=servername then tu='('s')' tu
if numb then tu='{'m'}' tu
end
if bm=''&b/='' then bm=tu
do jjj=1 to 10
if word(bm,jjj)^='' then call SET jjj-1 word(bm,jjj)
else call UNSET jjj-1
if jjj>=10 then leave
end
return m s '###' translate(tu,"@",msa)
VAR:
parse arg x
select
when datatype(x,'w') then return '$'||x
when x=',' then return lastsender
when x=':' then return lastjoin
when x='A' then return away
when x='C' then return target
when x='H' then return m
when x='I' then return invitation
when x='K' then return cmdchar
when x='N' then return ircnick
when x='Q' then return query
when x='S' then return servername
when x='T' then do
if query='' then return target
else return query
end
when x='U' then return myurl
when x='V' then return vers
when x='Z' then return left(time(),5)
when x='$' then return '$'
otherwise return v.x
end
return '<error>'
SET:
parse arg z
if z='' then do i=1 to words(varnames)
z=word(varnames,i); call S '$('z') is "'v.z'"'
end
else do
parse var z vn vv
if b='' then call S 'Variable' vn 'has the value "'v.vv'"'
else do; v.vn=vv; if find(varnames,vn)=0 then varnames=vn varnames; end
end
return
UNSET:
parse arg z etc
if z='' then do;call S "Deleting all set variables..."
do i=1 to words(varnames)
z=word(varnames,i); v.z=;
end;varnames=;end
else do
nvn=' '
do i=1 to words(varnames)
if z=word(varnames,i) then nop
else nvn=nvn word(varnames,i);end
v.z=;varnames=nvn
end
return
EDIT:
parse arg in
if left(in,1)="!" then call EXECUTE substr(in,2)
else if left(in,1)/=cmdchar then do
if query/='' then call SEND 'PRIVMSG' query ':'in
else if target/=0 then call SEND 'PRIVMSG' target ':'in
else call S 'You should join a channel or query a user first'
end
else if left(in,2)=cmdchar' ' then call SEND 'PRIVMSG' target ':'substr(in,3)
else call SHELL substr(in,2)
return
SHELL:
parse arg lin
if abbrev('ALIAS', translate(word(lin,1)), 2) then do
lin=strip(lin)
parse var lin . name lin
if name='' then do i=1 to words(aliasnames)
name=word(aliasnames,i); call S name': "'al.name'"'
end
else do
upper name
if lin='' then call S name': "'al.name'"'
else do; al.name=lin
if find(aliasnames,name)=0 then aliasnames=name aliasnames; end
end
return
end
if abbrev('ON', translate(word(lin,1)), 2) then do
lin=strip(lin)
parse var lin . lin
if lin=''&numons>0 then do i=1 to numons
call S i'- ON: "'on.i'"'
end
else if lin\='' then do
numons=numons+1
on.numons=lin
end
return
end
do while lin/=''
if left(lin,1)='*' then return
parse var lin one '15'x lin
par=; lc=; com='$'; al.com = one
do while al.com/=''; sa=al.com
do while left(sa,1)='%'
parse var sa '%'var sa
parse var par sb par
v.var=sb
end
if par/='' then do; sa=sa par; par=''; end
sb=; do while sa/=''
parse var sa k'$'y sa
if y='' then do; sb=sb||k; leave; end
if left(y,1)='(' then do; parse var y 2 x')'y; sa=y sa; end
else do; x=left(y,1); sa=substr(y,2) sa; end
sb=sb||k||VAR(x)
end
parse var sb com par '::' next
do while jumpcoms>0 & next ^=''
parse var next com par '::' next
jumpcoms = jumpcoms-1
end
jumpcoms=0
upper com
if next/='' then lin=next||'15'x||lin
if find(lc, com)=0 then lc=com lc
else do; call S 'Alias loop of "'com'" encountered'; return; end
end
call COMMAND com par
end
return
COMMAND:
parse arg q r; out=; upper q
if abbrev('LEAVE',q,2) then q='PART'
select
when abbrev('ABORT',q,2) then call BYE "your abort request"
when abbrev('AWAY',q,2) then do; lastorigin=; away=r; out="AWAY :"r; end
when abbrev('BYE',q,1)|abbrev('SIGNOFF',q,6)|abbrev('QUIT',q,3) then do
call SEND('QUIT' r); call BYE; end
when abbrev('CATALOG',q,2) then do; catmode=1; out='LIST' r; end
when abbrev('CHANNEL',q,1) then do
if r="" then do; call S "Talking to" target; return; end
if target/="" & target/=0 then call SEND("PART" target);
out="JOIN" r
end
when abbrev('CLEAR',q,2) then "VMFCLEAR"
when abbrev('CMDCHARACTER',q,2) then cmdchar=left(r,1)
when q='ECHO' then call OUT r
when abbrev('EXECUTE',q,1) then call EXECUTE r
when abbrev('EXPORT',q,4) then call EXPORT r
when abbrev('EXPRESSION',q,4) then call SET word(r,1) EXPR(subword(r,2))
when abbrev('FOLLOW',q,1) then out='JOIN' invitation
when abbrev('HELP',q,1) then do
address 'CMS' "HELP RXIRC"; say; end
when q='IF' then do
parse var r cond a r
if translate(a)/='THEN' then call S "IF" cond": THEN is missing"
else do
rc = INTERP("if ("cond") then rc=0; else rc=1")
if rc=0 then call COMMAND r
end
end
when abbrev('INTERPRET',q,3) then call INTERP r
when abbrev('ASSIGN',q,3) then call ASSIGN r
when abbrev('INVITE',q,1) then do
if words(r)=1 & target/=0 then out='INVITE' r target
else out='INVITE' r
end
when abbrev('LASTLOG',q,2) then call LASTLOG r
when abbrev('LOGGING',q,2) then call LOGGING r
when abbrev('NICKNAME',q,1) then if r='' then out='WHOIS' ircnick
else do; out='NICK' r; ircnick=r; capnick=translate(r); end
when q='NF'|abbrev('NOTIFY',q,4) then call NOTIFY r
when abbrev('SEND',q,4) then if r='' then do
call S "Send what?"
end
else do
call S "Sent command ("r")."
call SEND(r)
end
when abbrev('QUOTE',q,4) then if r='' then do
call S "Quote what?"
end
else do
call SEND(r)
end
when left(q,2)='PF' then 'CP SET' q r
when abbrev('REPLY',q,1) then call QUERY lastsender
when abbrev('SERVER',q,1) then call CONNECT r
when q='SET' then call SET r
when abbrev('UNSET',q,3) then call UNSET r
when q='SKIP' & sourcing then if datatype(r,'w') then skiplines=r
when q='JUMP' then if datatype(r,'w') then jumpcoms=r
when abbrev('SOURCE',q,2) then call SOURCE r
when abbrev('STATUS',q,1) then do; out='WHOIS' ircnick
call OUT 'Target:' target'; Query:' query'; Invitation:' invitation'; Last sender:' lastsender'; Last joined:' lastjoin
end
when q='STOP' & sourcing then abortsource=1
when abbrev('TALKTO',q,2) then do
if r/="" then target=translate(word(r,1))
call S 'Now talking to' target
end
when abbrev('TELL',q,2) then call TELL r
when abbrev('TOGGLE',q,3) then call TOGGLE r
when abbrev('VERSION',q,3) then do; out='VERSION' r
if r='' then call S progname vers
end
when abbrev('VIEWLOG',q,2) & viewcmd/='' then do
address 'CMS' viewcmd logfile; say; end
when abbrev('XAMINE',q,1) then out='WHOIS' lastsender
when abbrev('YELL',q,1) then call TELL word(r,1) '<'ircnick'>' subword(r,2)
when q='CHOP' then out="MODE" target "+ooo" r
when abbrev('DATE',q,1) then out="TIME" r
when abbrev('DESCRIBE',q,2) then do; parse var r whom desc
out='PRIVMSG' whom ':'msa'ACTION' desc||msa; end
when abbrev('IGNORE',q,2) then call IGNORE r
when q='K' then out="KICK" target r
when abbrev('LOCALWHO',q,1)|q="LCL" then do
who_empty=1; out="WHO *"right(domain,trunc(length(domain)/2)); end
when q='M'|q='MSG'|abbrev('MESSAGE',q,3) then do
parse var r ni r; out='PRIVMSG' ni ':'r; end
when abbrev('OMIT',q,2) then call OMIT r
when abbrev('QUERY',q,1) then call QUERY r
when abbrev('REQUEST',q,3)|q='CTCP' then do
parse var r ni rq .; upper rq
if ni="" then ni=capnick
if rq="" then rq="VERSION"
out='PRIVMSG' ni ':'msa||rq||msa
end
when q='SAY' then out='PRIVMSG' target ':'r
when q='SWHO' then out='NAMES'
when q='T' then out='TOPIC' target ':'r
when abbrev('TOPIC',q,2) then out='TOPIC' word(r,1) ':'subword(r,2)
when q='WHO' then do
who_empty=1
if r="" then out='WHO' target
else out='WHO' r
end
when abbrev('TCPIPSTATUS',q,3) then do
parse value SOCKET('SOCKETSETSTATUS') with rc . q etc
call S 'Status' q '('rc');' etc'; Input buffer length is' length(buffer)
end
when abbrev('WHOIS',q,1) then if r="" then out='WHOIS' ircnick
else out='WHOIS' r
when abbrev('UMODE',q,1) then out='MODE' ircnick r
when q='UNCHOP' then out="MODE" target "-ooo" r
otherwise if ACTION(q r) then do
call OUT '*' ircnick r
if query="" then out='PRIVMSG' target ':'msa'ACTION' r||msa
else out='PRIVMSG' query ':'msa'ACTION' r||msa
end
else do
li=cmds; out=q r
do while li/=''; parse var li el li
if abbrev(el,q,1) then do; out=el r; leave; end
end; end; end
call SEND out
out=; return
IGNORE:
arg a
do words(a)
parse var a x a
z=find(ignore,x); if z/=0 then
ignore=strip(delword(ignore,z,1))
else ignore=x ignore
end
call OUT 'You are ignoring:' ignore
if quiet then call S "And you don't send notices about it (quiet ignore)."
return
EXPORT:
arg a
do words(a)
parse var a x a
z=find(export,x); if z/=0 then
export=strip(delword(export,z,1))
else export=x export
end
call OUT 'You are exporting:' export
return
OMIT:
arg a
do words(a)
parse var a x a
z=find(omit,x); if z/=0 then
omit=strip(delword(omit,z,1))
else omit=x omit
end
call OUT 'You are omitting:' omit
return
QUERY:
parse arg qq
if query/='' then call S 'Terminating query with' query
query=qq
if qq/='' then call S 'Starting a query with' qq
else call S 'Talking to' target
return
LASTLOG:
arg a
if ^datatype(a,"W") | a<1 | a>80 then a=20
else a=a-1
'VMFCLEAR'; call S lo'Messages received last:'
do i=curll-a to curll; if ll.i/='' then call OUT hi'|'yo||ll.i; end
return
LOGGING:
arg a
if a='ON' & log=0 then do
writelog "<--> IRC log started on" date() "at" time()
say 'Logging started.'; log=1; end
else if a='OFF' & log=1 then do
writelog "<--> IRC log ended on" date() "at" time()
say 'Logging ended.'; log=0; end
else call S 'Logging is' onoff.log
return
S:
parse arg k
if translate(v.display)/='OFF' then say k
if logevent/=0 then do
curll=curll+1; ll.curll=k; logevent=0; k=curll-50; ll.k=; end
if log then writelog k
return
OUT:
parse arg x; if x="" then return
if length(x) < 81 then y=0
else do 1
y=pos(word(x,2),x)-1; if y>30 | y<0 then y=3
z=lastpos(" ",x,80)
if z<30 then do; y=3; z=77; end
call S left(x,z); x=substr(x,z+1)
do while length(x)+y > 80
z=lastpos(" ",x,80-y); if z<30 then do; y=3; z=77; end
call S copies(" ",y)left(x,z); x=substr(x,z+1)
end
end
call S copies(" ",y)x
return
CONNECT:
parse arg ircserver port .
if ircserver="" then do
call S "Tell me the internet address of an IRC server"
return
end
if datatype(port)="NUM" then ircport = port
if sock/='' then do; call SEND("QUIT"); call SHUT; "CP SLEEP 3 SEC"; end
in.2=me x2c('4b404b') ':'ircname
parse value SOCKET('SOCKET', 'AF_INET', 'SOCK_STREAM') with rc sock etc
if rc/=0 then do; sock=; call BYE "socket error:" etc; end
parse value SOCKET('SETSOCKOPT',sock,'SOL_SOCKET','SO_ASCII','ON') with rc . etc
if rc/=0 then call BYE "setsockopt:" etc
call S "Connecting to" ircserver "on port" ircport"." etc
parse value SOCKET('CONNECT', sock, 'AF_INET' ircport ircserver) with rc . etc
if rc/=0 then call BYE "connect:" etc
parse value SOCKET('IOCTL', sock, 'FIONBIO', 1) with rc . etc
if rc/=0 then call BYE "nonblocking i/o:" etc
if server_pass/='' then do; call SEND("PASS" server_pass); server_pass=; end
call SEND(x2c('D5C9C3D2') ircnick)
call SEND(x2c('E4E2C5D9') in.2)
return
CTCP:
parse arg fla bla
if pos(msa,bla)=0 then return 1
parse var bla . (msa) ctcp bla (msa) .
select
when ctcp="ACTION" then call OUT '*' s bla
when ctcp="CLIENTINFO" then
call MSAREPLY "CLIENTINFO ACTION CLIENTINFO FINGER TIME URL USERINFO VERSION"
when ctcp="FINGER" then
call MSAREPLY "FINGER" realname '('me'@'hostname'.'domain',',
me'@'mynode') - Idle' trunc(time('E'),2) 'seconds'
when ctcp="TIME" then call MSAREPLY "TIME" left(time(),5)
when ctcp="URL" then do
if wwwport='' then call MSAREPLY "ERRMSG No http port set up by user"
else call MSAREPLY "URL" myurl
end
when ctcp="USERINFO" then call MSAREPLY "USERINFO" userinfo
when ctcp="VERSION" then
call MSAREPLY "VERSION" progname vers "VM/CMS",
":Beta Version of Improved rxIRC - The Survival package for VM-struck humans"
otherwise if fla=1 then call MSAREPLY "ERRMSG Huh? Can't do" ctcp
end
return 0
MSAREPLY:
parse arg lyrics
call SEND("NOTICE" s ":"msa||lyrics||msa)
return
SYNTAX:
say errortext(rc)
return 0
HALT:
call BYE "halt request"
BYE:
parse arg reason
save_rc = rc
if reason/="" then call S "Terminating because of" reason '('rc')'
if log then do
writelog "<--> IRC session ended on" date() "at" time()
"FINIS * * *"
end
do i=1 to pf.0
a=word(pf.i,2)
if a='RETRIEVE' then iterate
if a='UNDEFINED' then "CP SET" word(pf.i,1)
else "CP SET" pf.i
end
i=1; parse var qt.i 'LINEND' a',' . 'CHARDEL' k',' .
'CP TERM LINEND' a 'CHARDEL' k
i=2; parse var qt.i 'LINESIZE' a',' .
'CP TERM LINESIZE' a
if www/='' then do
SOCKET('SHUTDOWN',www); SOCKET('CLOSE',www); www=; end
if sock/='' then do
call SHUT
parse value SOCKET('TERMINATE') with .
"NUCXDROP RXSOCKET"
end
if have_rxwt then RESETVALUE('ALL')
exit save_rc
ACTION:
parse arg q r
select
when abbrev("APPLAUD",q,3) then a="applauds wholeheartedly"
when q="BOW" then a="bows gracefully"
when abbrev("COMFORT",q,3) then a="comforts you"
when abbrev("CUDDLE",q,3) then a="cuddles you"
when abbrev("DANCE",q,3) then a="dances a waltz with you"
when abbrev("GIGGLE",q,3) then a="giggles inanely"
when abbrev("GRIN",q,2) then a="grins"
when q="HUG" then a="hugs you"
when abbrev("LAUGH",q,2) then a="laughs wholeheartedly"
when q="ME"|abbrev("EMOTE",q,1) then return 1
when q="NOD" then a="nods solemnly"
when abbrev("SHRUG",q,2) then a="shrugs"
when abbrev("SIGH",q,2) then a="sighs deeply"
when abbrev("SMILE",q,2) then a="smiles"
when abbrev("THANK",q,2) then a="thanks you from the bottom of the heart"
when abbrev("WAVE",q,2) then a="waves goodbye to you"
when abbrev("WINK",q,2) then a="winks suggestively"
when abbrev("YAWN",q,2) then a="yawns tiredly"
otherwise return 0; end
if r="" then r=a'.'
else r=word(a,1) r'.'
return 1
FINDM: procedure
arg patlist, token
do words(patlist)
parse var patlist a patlist
if MATCH(a,token) then return 1
end
return 0
MATCH: procedure
arg pattern, token
do i = 1 by 1 while i < length(pattern)
ss = substr(pattern,i,2)
select
when ss = '**' then do
pattern = delstr(pattern,i,1)
i = i - 1
end
when ss = '*?' then pattern = overlay('?*',pattern,i,2)
otherwise nop
end
end
return MATCHINT(pattern,token)
MATCHINT: procedure
arg pattern, token
if pattern == token then return 1
if pattern == '*' then return 1
if verify(pattern,'*?','M') = 0 then return 0
ptrp = 1
ptrt = 1
lenp = length(pattern)
lent = length(token)
do search = 1 by 1
select
when ptrp > lenp & ptrt > lent
then return 1
when ptrp > lenp then return 0
when ptrt > lent then return 0
otherwise nop
end
pchar = substr(pattern,ptrp,1)
tchar = substr(token,ptrt,1)
select
when pchar = tchar | pchar = '?'
then do
ptrp = ptrp + 1
ptrt = ptrt + 1
iterate search
end
when pchar = '*' & ptrp = lenp
then return 1
when pchar = '*' then do
ptrp = ptrp + 1
pchar = substr(pattern,ptrp,1)
do ptrt = ptrt to lent
tchar = substr(token,ptrt,1)
if pchar = tchar then do
if ptrp = lenp & ptrt = lent
then return 1
if MATCHINT(substr(pattern,ptrp+1),substr(token,ptrt+1)) then return 1
end
end
return 0
end
otherwise return 0
end
end
call BYE 'a mistake'
SEND:
parse arg qp
if qp='' then return
if left(qp, 9)='PRIVMSG +' then do
parse var qp . '+'ni' :'tx
call TELL ni tx
end
else do
qp=translate(qp,beep||bold,beepch||boldch)
parse value SOCKET('WRITE', sock, qp||cr||lf) with rc . etc
if rc/=0 then call BYE "socket write error:" etc
end
return
SHUT:
a=sock; sock=; servername=;
parse value SOCKET('SHUTDOWN', a,'BOTH') with rc . etc
if rc/=0 then call BYE "socket shut error:" etc
parse value SOCKET('CLOSE', a) with rc . etc
if rc/=0 then call BYE "socket close error:" etc
return
NICE:
arg u'@'v;if v='' then v=mynode
if nice.u.v/='' then return nice.u.v
'NAMEF :userid' u ':node' v ':nick (LIFO'
if rc=0 then parse pull nice.u.v .
else if v=mynode then do
'NAMEF :userid' u ':node :nick (LIFO'
if rc=0 then do
parse pull nice.u.v .
pull ln .
if ln='' then return nice.u.v
end
nice.u.v=u
end
else if u='RSCS' then nice.u.v=v
else nice.u.v=u'@'v
return nice.u.v
U@N:
parse arg x z; if q='' then return 0 'missing args'
upper x; parse var x x'@'y
if y/='' then return x y z
if word(z,1)='AT' then do
parse var z . y z; upper y
if y='' then return 0 'missing node'
return x y z;end
if u@n.x/='' then return u@n.x z
'NAMEF :nick' x ':userid :node :via (LIFO'
if rc=0 then do 1
pull k; pull y; pull a
if a='' then leave
if y='' then y=mynode
u@n.q=a y; if via.a.y='' then via.a.y=k
return a y z
end
u@n.x = x mynode
return x mynode z
TELL:
parse arg tea
parse value U@N(tea) with xid xnod tea
if xid=0 then do
call OUT xnod tea
return
end
err=; if translate(left(tea,4))='VIA ' then do
parse var tea . via tea
upper via
if via='NONE' then via=;
via.xid.xnod = via
end
else via=via.xid.xnod
select
when via='SMSG'|via='SEND' then do
if xnod/=mynode then err='SEND & SMSG only local'
else do
if via='SMSG' then parse value diagrc(8,'SMSG' xid tea) with rc . err
else do
parse var tea cp? tea?
if translate(cp?)='CP' then
parse value diagrc(8,'SEND CP' xid translate(tea?)) with rc . err
else parse value diagrc(8,'SEND' xid tea) with rc . err
end; end; end
when via=''|left(via,1)/="'" then do
if via='RSCS' then do;viar=1;via='';end;else viar=0
if via/='' then via='CMD' via
if xid='RSCS'|(xid=rscs&xnod=mynode) then do
if xnod=mynode&^viar then parse value diagrc(8,'SM' rscs tea) with rc . err
else parse value diagrc(8,'SM' rscs via 'CMD' xnod tea) with rc . err
end
else do
if xnod=mynode&^viar then parse value diagrc(8,'M' xid tea) with rc . err
else parse value diagrc(8,'SM' rscs via 'MSG' xnod xid tea) with rc . err
end
end
otherwise
parse var via "'"via"'"
if word(via,1)='CP' then do
parse value diagrc(8,subword(via,2) tea) with rc . err
if rc=1 then err=via "unknown."
end
else do
if xnod=mynode|xnod='' then address cms via xid tea
else address cms via NICE(xid'@'xnod) tea
if rc>0 then err='Rc' rc 'from' via'.'
if rc<0 then do;rc=24;err='Invalid VIA'; end
end; end
if err/='' then call OUT strip(translate(err,' ','15'x))
return
SOURCE:
arg sfn, sfl
sourcenum=sourcenum+1
if sfn='' then do
call S "You must specify a file to /source"
return -1
end
sfn = sfn 'RXIRC *'
"STATE" sfn
if rc/=0 then do
if sfl/=1 then call S 'Could not access' sfn
end
else do
'MAKEBUF'; 'EXECIO * DISKR' sfn '(FIFO FINIS'; skiplines=0;
do queued(); sourcing=1
parse pull l; if abortsource then iterate
if right(strip(l),2)='::' then
ll=ll||l
else do
ll=ll||l
call SHELL strip(ll)
ll=''
end
if skiplines=0 then call SHELL strip(l)
else skiplines=skiplines-1
end
abortsource=0; sourcing=0; 'DROPBUF'
end
return
TOGGLE:
parse arg n o
if ^datatype(n,'W')|n<1|n>24 then do
call S 'Invalid PF key "'n'".'; return; end
o = strip(o); sep = left(o,1)
parse var o (sep) com (sep) o
'CP SET PF'n 'IMM /TOGGLE' n sep||o||sep||com
call SHELL strip(com)
drop sep
return
EXPR:
procedure
parse arg expr
signal on SYNTAX
INTERPRET("expr = ("expr")")
signal off SYNTAX
return expr
INTERP:
procedure
arg statement
signal on SYNTAX; INTERPRET(statement); signal off SYNTAX
return rc
ASSIGN:
parse arg asto asfrom
signal on SYNTAX; INTERPRET(statement); signal off SYNTAX
return rc
NOTIFY:
arg a
do i=1 to words(a)
x=word(a,i); y=find(nflist,x); z=find(translate(nfhere),a)
if z/=0 then nfhere=strip(delword(nfhere,z,1))
if y/=0 then nflist=strip(delword(nflist,y,1))
else nflist=nflist x
end
call OUT 'Observing:' nflist
if a='' then call OUT 'Present:' nfhere
return
ISON:
parse arg g
i=1; do words(nfhere)
a=word(nfhere,i)
if find(g,a)=0 then do
nfhere = strip(delword(nfhere,i,1))
call OUT a "has gone"
end
else i=i+1
end
do i=1 to words(g)
a=word(g,i)
if find(nfhere,a)=0 then do
nfhere = a nfhere
call SEND "USERHOST" a
end
end
nfcatch=0
return
EXECUTE:
parse arg a
if a='' then do
say 'Suspending rxIRC; Enter "return" to return'
a='SUBSET'
end
address 'CMS' a
if rc=0 then say "rxIRC ready"
else say "rxIRC ready("rc")"
return
WRITE:
parse arg qp tx
parse value SOCKET('WRITE', qp, tx||cr||lf) with rc . etc
if rc/=0 then call S "Socket write error:" etc
return
WRITEFILE:
parse arg qp fn ft .
'MAKEBUF'
'EXECIO * DISKR' fn ft '(FINIS FIFO'
if rc=0 then do
do queued()
parse pull l
call WRITE qp l
if rc/=0 then do
call S 'httpd: File transmission interrupted (by caller probably)'
signal DROPIT
end
end
call S 'httpd: Sent' fn ft
end
DROPIT:
'DROPBUF'
return