The QBasic / QB64 Discussion Forum      Other Subforums, Links and Downloads
 
 

 Return to Index  

chat bas no tested

November 17 2011 at 9:46 PM
Anonymous  (no login)

 
DECLARE SUB SendInfo (BYVAL towho%)
DECLARE FUNCTION MatchMask% (check$, against$)
DECLARE SUB AddUserChanMode (BYVAL nickval%, BYVAL chanval%, char$)
DECLARE SUB DelUserChanMode (BYVAL nicknum%, BYVAL chanval%, char$)
DECLARE FUNCTION IsChanMode% (BYVAL chanval%, modechars$)
DECLARE SUB AddChanMode (BYVAL whoset%, BYVAL chanval%, modeval$)
DECLARE FUNCTION IsUserChanMode% (BYVAL userval%, BYVAL chanval%, modeval$)
DECLARE FUNCTION ChanPrefix$ (BYVAL userval%, BYVAL chanval%)
DECLARE SUB ExtendedHelp (helptopic$)
DECLARE SUB SystemPM (BYVAL nickval%, msgline$)
DECLARE FUNCTION IsUserMode% (BYVAL checkwho%, checkmodes$)
DECLARE SUB AddUserMode (BYVAL towho%, BYVAL fromwho%, addmodes$)
DECLARE SUB ShowWhois (BYVAL fromwho%, BYVAL aboutwho%)
DECLARE FUNCTION tcpGetAddr$ (BYVAL tcpHandle AS INTEGER)
DECLARE SUB SendList (BYVAL whichuser%)
DECLARE SUB KillChan (BYVAL whichchan%)
DECLARE SUB SendTopic (BYVAL whichuser%, BYVAL chanval%)
DECLARE SUB SendNames (BYVAL whichuser%, BYVAL chanval%)
DECLARE SUB QuitChan (BYVAL whoparts%, BYVAL chanval%, quitmsg$)
DECLARE SUB PartChan (BYVAL whoparts%, BYVAL chanval%)
DECLARE SUB JoinChan (BYVAL whojoins%, BYVAL chanval%)
DECLARE FUNCTION CreateChan% (newchan$)
DECLARE FUNCTION NormalizeChan$ (oldchan$)
DECLARE SUB ChanBroadcast (BYVAL nosend%, BYVAL chanval%, textmsg$)
DECLARE FUNCTION ChanExists% (testchan$)
DECLARE SUB tcpFlush (BYVAL whichuser%)
DECLARE SUB SendMOTD (BYVAL whichuser%)
DECLARE SUB tcpClose (BYVAL tcpHandle AS INTEGER)
DECLARE SUB QuitUser (BYVAL whichuser%, quitmsg$)
DECLARE SUB ChangeNick (BYVAL whichuser%, newnick$)
DECLARE SUB SendError (BYVAL whichsock%, BYVAL errnum%, addto$)
DECLARE FUNCTION NickExists% (testnick$)
DECLARE FUNCTION NormalizeNick$ (oldnick$)
DECLARE FUNCTION TrimFirstColon$ (thedata$)
DECLARE SUB GetArgs (thedata$, BYVAL howmanyargs%)
DECLARE FUNCTION UnixTimeEnc& (dateval AS STRING, BYVAL timeval AS LONG)
DECLARE FUNCTION FullHostMask$ (BYVAL whichuser%)
DECLARE FUNCTION strReplace$ (origstr$, findthis$, repwith$)
DECLARE SUB tcpReleaseAll ()
DECLARE FUNCTION tcpSetAsyncHandler% (BYVAL tcpHandle AS INTEGER, BYVAL Events AS INTEGER)
DECLARE FUNCTION tcpGetOption% (BYVAL tcpHandle AS INTEGER, BYVAL OptName AS INTEGER)
DECLARE FUNCTION tcpSetOption% (BYVAL tcpHandle AS INTEGER, BYVAL OptName AS INTEGER, BYVAL OptVal AS INTEGER)
DECLARE SUB tcpRelease (BYVAL tcpHandle AS INTEGER)
DECLARE FUNCTION tcpAllocate% ()
DECLARE FUNCTION tcpListen% (BYVAL NewListenPort%)
DECLARE SUB tcpSendData (BYVAL tcpHandle AS INTEGER, Data2Send AS STRING)
DECLARE FUNCTION tcpStatus% (BYVAL tcpHandle AS INTEGER)
DECLARE FUNCTION MakeIP$ (tmpipval$)
DECLARE FUNCTION tcpGetData$ (BYVAL tcpHandle AS INTEGER)
DECLARE FUNCTION tcpAbort% (BYVAL tcpHandle AS INTEGER)
DECLARE FUNCTION CarrySet% ()
DECLARE FUNCTION tcpConnect% (tmpip$, BYVAL tmpport%)
DECLARE FUNCTION tcpResolveHost$ (tmpname AS STRING)
DECLARE FUNCTION tcpGetConfig% ()
DECLARE FUNCTION LowByte% (BYVAL Word AS INTEGER)
DECLARE FUNCTION HighByte% (BYVAL Word AS INTEGER)
DECLARE FUNCTION MakeReg% (BYVAL h AS INTEGER, BYVAL L AS INTEGER)
DECLARE FUNCTION tcpInit% (BYVAL intvector%)
TYPE Registers
ax AS INTEGER
bx AS INTEGER
cx AS INTEGER
dx AS INTEGER
bp AS INTEGER
si AS INTEGER
di AS INTEGER
flags AS INTEGER
ds AS INTEGER
es AS INTEGER
END TYPE

TYPE PCTCP
IntVec AS INTEGER
Version AS INTEGER
ErrorVal AS INTEGER
SubError AS INTEGER
FirstSock AS INTEGER
LastSock AS INTEGER
END TYPE

TYPE TCPaddr
IPaddr AS STRING * 4
RemPort AS INTEGER
LocPort AS INTEGER
Protocol AS STRING * 1
END TYPE

CONST protNet = 1
CONST protIP = 2
CONST protUDP = 3
CONST protTCP = 4
CONST protICMP = 5

CONST sckAlarm = 0
CONST sckOpen = 1
CONST sckReceive = 2
CONST sckTransmit = 3
CONST sckTransmitFlush = 4
CONST sckRemoteClose = 5
CONST sckClose = 6
CONST sckError = 7

DIM SHARED tcpCall AS Registers
DIM SHARED tcpReturn AS Registers
DIM SHARED dTCP AS PCTCP
DIM SHARED L AS INTEGER
DIM SHARED Sockets(50) AS TCPaddr

DIM SHARED crlf AS STRING
DIM SHARED IP(1 TO 30) AS STRING
DIM SHARED buffer(1 TO 30) AS STRING
DIM SHARED client(1 TO 30, 1 TO 2) AS INTEGER
DIM SHARED state(1 TO 30) AS INTEGER
DIM SHARED onsince(1 TO 30) AS LONG
DIM SHARED idlesince(1 TO 30) AS LONG
DIM SHARED user(1 TO 30, 1 TO 5) AS STRING
DIM SHARED chan(1 TO 30, 1 TO 3) AS STRING
DIM SHARED userchan(1 TO 30, 1 TO 30) AS STRING
DIM SHARED chanlimit(1 TO 30) AS INTEGER
DIM SHARED chancreated(1 TO 30) AS LONG
DIM SHARED mychans(1 TO 30) AS STRING
DIM SHARED away(1 TO 30) AS STRING
DIM SHARED topic(1 TO 30, 1 TO 2) AS STRING
DIM SHARED topictime(1 TO 30) AS LONG
DIM SHARED ban(1 TO 30, 1 TO 30) AS STRING
DIM SHARED gracequit(1 TO 30) AS INTEGER
DIM SHARED nextping(1 TO 30) AS LONG
DIM SHARED lastping(1 TO 30) AS LONG
DIM SHARED gotpong(1 TO 30) AS INTEGER
DIM SHARED flood(1 TO 30) AS INTEGER
DIM SHARED pingtimeout&, pinginterval&, timezone%
DIM SHARED nicklen%, chanlen%, topiclen%, awaylen%
DIM SHARED maxchan%, maxconn%, hostname$, network$
DIM SHARED nickchars$, chanchars$
DIM SHARED creation$, build$, motd$
DIM SHARED args(1 TO 20) AS STRING
DIM SHARED realval%, viewmode%
DIM SHARED LocalIP AS STRING
DIM SHARED silent AS INTEGER

build$ = "RockIRCd-1.0.0-testing"
nickchars$ = "abcdefghijklmnopqrstuvwxyz1234567890-_[]|"
chanchars$ = "#abcdefghijklmnopqrstuvwxyz1234567890-_[]"
dTCP.IntVec = &H61
crlf = CHR$(13) + CHR$(10)
maxconn% = 30
maxchan% = 30
floodlimit% = 20
nicklen% = 32: chanlen% = 50: awaylen% = 160: topiclen% = 350

IF INSTR(COMMAND$, "/50") > 0 THEN WIDTH 80, 50 ELSE WIDTH 80, 25
COLOR 7, 0: CLS : COLOR 15, 1: LOCATE 1, 1
titlebar$ = LEFT$(" RockIRCD for DOS v1.0.0 (test build)" + SPACE$(60), 80)
PRINT titlebar$; : COLOR 7, 0
PRINT build$
PRINT "(c)2009 Mike Chambers"
PRINT "http://www.rubbermallet.org"
PRINT
PRINT "Loading RockIRCd configuration file..."
OPEN "conf\ircd.ini" FOR INPUT AS #1
DO UNTIL EOF(1)
LINE INPUT #1, cfgline$
IF LEN(cfgline$) > 0 THEN
xp = INSTR(cfgline$, " "): IF xp < 1 THEN xp = LEN(cfgline$) + 1
directive$ = LEFT$(cfgline$, xp - 1)
argument$ = MID$(cfgline$, xp + 1)
SELECT CASE LCASE$(directive$)
CASE "timezone"
timezone% = VAL(argument$)
CASE "port"
lport% = VAL(argument$)
CASE "maxusers"
maxcon% = VAL(argument$)
CASE "hostname"
hostname$ = strReplace(argument$, " ", "")
CASE "network"
network$ = strReplace(argument$, " ", "")
CASE "pinginterval"
pinginterval& = VAL(argument$)
CASE "pingtimeout"
pingtimeout& = VAL(argument$)
CASE "flood"
floodlimit% = VAL(argument$)
END SELECT
END IF
LOOP
CLOSE #1
PRINT
PRINT "Max connections:" + STR$(maxconn%)
PRINT "Port:" + STR$(lport%)
PRINT "Hostname: " + hostname$
PRINT "Network name: " + network$
PRINT "Ping interval:" + STR$(pinginterval&) + " seconds"
PRINT "Ping timeout:" + STR$(pingtimeout&) + " seconds"
PRINT
PRINT "Caching MOTD to RAM... ";
OPEN "conf\motd.txt" FOR BINARY AS #1: CLOSE #1
OPEN "conf\motd.txt" FOR INPUT AS #1
DO UNTIL EOF(1)
LINE INPUT #1, tmpmotd$
IF LEN(tmpmotd$) = 0 THEN tmpmotd$ = " "
motd$ = motd$ + tmpmotd$ + CHR$(13)
LOOP
CLOSE #1: tmpmotd$ = ""
motd$ = strReplace(motd$, CHR$(10), CHR$(13))
motd$ = strReplace(motd$, CHR$(13) + CHR$(13), CHR$(13))
PRINT "OK! (" + MID$(STR$(LEN(motd$)), 2) + " bytes)"
PRINT
PRINT "Initializing server... ";
tcpReleaseAll
creation$ = DATE$ + " at " + TIME$
spinner = 1
checkto% = 1
PRINT "OK!"
PRINT "RockIRCd is listening for connections on port" + STR$(lport%); "."
PRINT
PRINT "Ready."
DO
LOCATE , , 0
oldcur% = CSRLIN
title2$ = STR$(onlinecount%) + " clients online ³ " + TIME$ + " "
titlebar$ = LEFT$(" RockIRCd for DOS v1.0.0 (test build)" + SPACE$(60), 80 - LEN(title2$))'+ SPACE$(80 - LEN(title2$)) + title2$, 80)
IF TIME$ <> lasttime$ THEN LOCATE 1, 1: COLOR 15, 1: PRINT titlebar$ + title2$; : COLOR 7, 0
lasttime$ = TIME$

listening% = 0
firstfree% = 0
onlinecount% = 0
service$ = ""
curunixtime& = UnixTimeEnc(DATE$, TIMER)
LOCATE oldcur%, 1, 0
IF monitor% = 0 THEN
PRINT LEFT$(">" + localin$ + SPACE$(79), 80);
LOCATE oldcur%, LEN(localin$) + 2, 1
END IF
lastused% = 0
FOR n = 1 TO checkto%
stat% = tcpStatus(client(n, 1))
SELECT CASE stat%
CASE 1 'listening
listening% = listening% + 1
GOSUB doflush
IF n > lastused% = lastused% THEN lastused% = n

CASE 2, 3
IF n > lastused% THEN lastused% = n
IF client(n, 2) <> stat% AND gracequit(n) = 0 THEN
gracequit(n) = 1 'makes QuitUser sub not modify socket when called.
QuitUser n, "Connection reset by peer. [" + build$ + "]"
END IF
buffer(n) = ""
clearval = n
GOSUB clearslot
GOSUB realloc
IF firstfree% = 0 THEN firstfree% = n
GOSUB doflush
tcpClose client(n, 1)

CASE 4
onlinecount% = onlinecount% + 1
IF client(n, 2) = 1 THEN
clearval = n
GOSUB clearslot
GOSUB makenewlisten
onsince(n) = UnixTimeEnc(DATE$, TIMER)
gotpong(n) = 1
nextping(n) = curunixtime& + pinginterval&
lastping(n) = curunixtime&
END IF
service$ = service$ + CHR$(n)
IF n > lastused% THEN lastused% = n

CASE ELSE
IF client(n, 2) <> stat% AND gracequit(n) = 0 THEN
gracequit(n) = 1 'makes QuitUser sub not modify socket when called.
QuitUser n, "Client exited. [" + build$ + "]"
END IF
IF firstfree% = 0 THEN firstfree% = n
END SELECT
client(n, 2) = stat%

NEXT n
checkto% = lastused% + 1: IF checkto% > maxconn% THEN checkto% = maxconn%
GOSUB keyboardhandler

IF listening% = 0 THEN
rc2% = tcpAbort(client(firstfree%, 1))
buffer(firstfree%) = ""
GOSUB dorelease

client(firstfree%, 1) = tcpListen(lport%)
client(firstfree%, 2) = 1: state(firstfree%) = 0
END IF

FOR curconn% = 1 TO LEN(service$)
n = ASC(MID$(service$, curconn%, 1))
GOSUB service
NEXT curconn%
LOOP UNTIL doquit% = 1
IF onlinecount% > 0 THEN
PRINT "Please enter a message below explaining why the server is shutting down, or"
PRINT "leave it blank for the default shutdown message."
LINE INPUT ">", shutdownmsg$
PRINT
IF LEN(shutdownmsg$) = 0 THEN shutdownmsg$ = "Administrator manually shut down this server, you are being disconnected."
PRINT "Please wait, sending server shutdown message to" + STR$(onlinecount%) + " connected users... ";
FOR n = 1 TO maxconn%
IF client(n, 2) = 4 THEN
tcpSendData client(n, 1), ":System!RockIRCd@" + hostname$ + " NOTICE " + user(n, 1) + " :" + shutdownmsg$ + crlf
FOR nu = 1 TO LEN(mychans(n))
num = ASC(MID$(mychans(n), nu, 1))
tcpSendData client(n, 1), ":System!RockIRCd@" + hostname$ + " NOTICE " + chan(num, 1) + " :" + shutdownmsg$ + crlf
NEXT nu
tcpFlush client(n, 1)
END IF
NEXT n
PRINT "done!"
END IF
PRINT "Releasing all socket handles... ";
tcpReleaseAll
PRINT "done!"
PRINT
PRINT "Thank you for using " + build$ + "."
PRINT "You are now back in the mundane world of DOS."
END

service:
IF LEN(buffer(n)) < 512 THEN buffer(n) = buffer(n) + strReplace(tcpGetData(n), CHR$(10), CHR$(13))
buffer(n) = strReplace(buffer(n), CHR$(13) + CHR$(13), CHR$(13))
GOSUB processinput

IF gotpong(n) = 0 AND curunixtime& > lastping(n) + pingtimeout& THEN
QuitUser n, "Ping timeout:" + STR$(pingtimeout&) + " seconds"
RETURN
END IF
IF curunixtime& > nextping(n) THEN
tcpSendData client(n, 1), "PING :" + MID$(STR$(TIMER), 2) + crlf
gotpong(n) = 0
nextping(n) = curunixtime& + pinginterval&
lastping(n) = curunixtime&
END IF

SELECT CASE state(n)
CASE 0 'brand new connection.
snd$ = ":" + hostname$ + " NOTICE AUTH :*** Looking up your hostname..." + crlf
snd$ = snd$ + ":" + hostname$ + " NOTICE AUTH :*** Not checking Ident" + crlf
snd$ = snd$ + ":" + hostname$ + " NOTICE AUTH :*** Couldn't look up your hostname" + crlf
'snd$ = snd$ + ":" + hostname$ + " NOTICE AUTH :*** I have" + STR$(CloneCount(n)) + " connections from your IP." + crlf
snd$ = snd$ + ":" + hostname$ + " NOTICE AUTH :*** If it hangs here, type " + CHR$(2) + "/NICK NICKNAME" + CHR$(2) + " and it should continue." + crlf
tcpSendData client(n, 1), snd$: snd$ = ""
state(n) = 1
CASE 1 'waiting for log in.
IF LEN(user(n, 1)) > 0 AND LEN(user(n, 2)) > 0 THEN
snd$ = ":" + hostname$ + " 001 " + user(n, 1) + " :Welcome to the " + CHR$(2) + network$ + CHR$(2) + " Internet Relay Chat Network " + user(n, 1) + crlf
snd$ = snd$ + ":" + hostname$ + " 002 " + user(n, 1) + " :Your host is " + hostname$ + "[127.0.0.1/" + MID$(STR$(lport%), 2) + "], running " + build$ + " for x86-based DOS" + crlf
snd$ = snd$ + ":" + hostname$ + " 003 " + user(n, 1) + " :This server was created " + creation$ + crlf
snd$ = snd$ + ":" + hostname$ + " 004 " + user(n, 1) + " " + hostname$ + " " + build$ + crlf
snd$ = snd$ + ":" + hostname$ + " 005 " + user(n, 1) + " NICKLEN=32 PREFIX=(qov)~@+ STATUSMSG=~@+ TOPICLEN=350 NETWORK=" + network$ + " MAXTARGETS=1 CHANTYPES=# :are supported by this server" + crlf
snd$ = snd$ + ":" + hostname$ + " 005 " + user(n, 1) + " CHANLIMIT=#:50 CHANMODES=bklmt AWAYLEN=160 :are supported by this server" + crlf
snd$ = snd$ + ":" + hostname$ + " 251 " + user(n, 1) + " :There are" + STR$(onlinecount%) + " users and 0 invisible on 1 server" + crlf
snd$ = snd$ + ":" + hostname$ + " 254 " + user(n, 1) + STR$(ChanCount) + " :channels formed" + crlf
snd$ = snd$ + ":" + hostname$ + " 255 " + user(n, 1) + " :I have" + STR$(onlinecount%) + " clients and 1 servers" + crlf
snd$ = snd$ + ":" + hostname$ + " 265 " + user(n, 1) + " :Current local users:" + STR$(onlinecount%) + " Max:" + STR$(maxconn%) + crlf
tcpSendData client(n, 1), snd$: snd$ = ""
SendMOTD n
AddUserMode n, 0, "x"
FOR genvh = 1 TO LEN(IP(n))
user(n, 4) = user(n, 4) + HEX$(ASC(MID$(IP(n), genvh, 1)) XOR 128)
NEXT genvh
state(n) = 2
END IF
CASE 2 'logged in. normal stuff here.
END SELECT
RETURN


makenewlisten:
FOR newl = 1 TO maxconn%
SELECT CASE tcpStatus(client(newl, 1))
CASE 1, 2, 3, 4
CASE ELSE
client(newl, 1) = tcpListen(lport%)
client(newl, 2) = 1
clearval = newl
buffer(newl) = ""
GOSUB clearslot
RETURN
END SELECT
NEXT newl
RETURN

clearslot:
state(clearval) = 0
user(clearval, 1) = "" 'nick
user(clearval, 2) = "" 'username
user(clearval, 3) = "" 'realname
user(clearval, 4) = "" 'vhost
user(clearval, 5) = "" 'user modes
FOR chanclear = 1 TO 50
userchan(clearval, chanclear) = "" 'user's modes for channels
NEXT chanclear
away(clearval) = ""
mychans(clearval) = ""
gracequit(clearval) = 0
IP(clearval) = ""
RETURN

processinput:
xpl = INSTR(buffer(n), CHR$(13)): IF xpl < 1 THEN flood(n) = 0: RETURN
flood(n) = flood(n) + 1
IF flood(n) > floodlimit% THEN QuitUser n, "User has been killed by the server for flooding. [" + build$ + "]": RETURN

curline$ = LEFT$(buffer(n), xpl - 1): buffer(n) = MID$(buffer(n), xpl + 1)
curline$ = LEFT$(curline$, 510) 'RFC spec says each line max 512 incl. CRLF

'PRINT curline$

xps = INSTR(curline$, " "): IF xps < 1 THEN xps = LEN(curline$) + 1
cmd$ = UCASE$(LEFT$(curline$, xps - 1)): curline$ = MID$(curline$, xps + 1)
cmd$ = LTRIM$(RTRIM$(cmd$))

FOR clearargs = 1 TO 20
args(clearargs) = ""
NEXT clearargs

IF cmd$ <> "PING" AND cmd$ <> "PONG" THEN idlesince(n) = curunixtime&

'common commands for all connection states here:
SELECT CASE cmd$
CASE "NICK"
GetArgs curline$, 1
fixednick$ = NormalizeNick(args(1))
IF fixednick$ = " " THEN 'if normalize sub made it a space, it was illegal
fixednick$ = ""
tcpSendData client(n, 1), ":System!RockIRCd@" + hostname$ + " NOTICE " + user(n, 1) + " :The nickname you requested, " + CHR$(2) + args(1) + CHR$(2) + " is marked as illegal. You cannot use it, please use something else." + crlf
END IF
IF LEN(fixednick$) > 0 THEN
IF NickExists(fixednick$) <> 0 THEN
SendError n, 436, fixednick$
ELSE
ChangeNick n, fixednick$
IF LEN(user(n, 2)) = 0 THEN user(n, 2) = fixednick$
END IF
ELSE
SendError n, 431, ""
END IF
RETURN

CASE "QUIT"
IF LEN(curline$) = 0 THEN curline$ = "No reason given. [" + build$ + "]"
QuitUser n, curline$
RETURN

CASE "PING"
tcpSendData client(n, 1), ":" + hostname$ + " PONG " + hostname$ + " " + curline$ + crlf
RETURN

CASE "PONG"
gotpong(n) = 1
RETURN
END SELECT
'end common

IF state(n) < 2 THEN
SELECT CASE cmd$
CASE "USER"
GetArgs curline$, 3: curline$ = LTRIM$(curline$)
curline$ = TrimFirstColon(curline$)
user(n, 2) = args(1) 'parse username
user(n, 3) = curline$ 'parse real name
RETURN

CASE ELSE
SendError n, 451, cmd$
RETURN
END SELECT
RETURN
END IF

SELECT CASE cmd$
CASE "INFO"
SendInfo n

CASE "VERSION"
IF strReplace(LCASE$(curline$), " ", "") <> LCASE$(hostname$) THEN
SendError n, 402, curline$
ELSE
tcpSendData client(n, 1), ":" + hostname$ + " 351 " + user(n, 1) + " " + build$ + ". " + hostname$ + " :RockIRCd is an IRC server designed to run only in pure DOS." + crlf
END IF

CASE "WHO"
GetArgs curline$, 1
IF LEN(args(1)) > 0 THEN
tcpSendData client(n, 1), ":" + hostname$ + " 315 " + user(n, 1) + " " + args(1) + " :End of /WHO list" + crlf
ELSE
SendError n, 461, "WHO"
END IF

CASE "ISON"
IF LEN(curline$) > 0 THEN
snd$ = ":" + hostname$ + " 303 " + user(n, 1) + " :"
DO UNTIL LEN(curline$) = 0
xps = INSTR(curline$, " "): IF xps < 1 THEN xps = LEN(curline$) + 1
curname$ = LTRIM$(RTRIM$(LEFT$(curline$, xps - 1))): curline$ = MID$(curline$, xps + 1)
IF NickExists(curname$) > 0 THEN snd$ = snd$ + curname$ + " "
LOOP
tcpSendData client(n, 1), RTRIM$(snd$) + crlf
ELSE
SendError n, 461, "ISON"
END IF

CASE "INVITE"
GetArgs curline$, 2
IF LEN(args(2)) = 0 THEN
SendError n, 461, "INVITE"
ELSE
nicknum% = NickExists(args(1))
IF nicknum% < 1 THEN
SendError n, 401, args(1)
ELSE
channum% = ChanExists(args(2))
IF channum% > 0 AND INSTR(mychans(nicknum%), CHR$(channum%)) THEN
SendError n, 443, user(nicknum%, 1) + " " + chan(channum%, 1)
ELSE
IF channum% > 0 THEN
realchanname$ = chan(channum%, 1)
IF IsChanMode(channum%, "i") AND IsUserChanMode(nicknum%, channum%, "qo") < 1 THEN
allowinvite% = 0
ELSE
allowinvite% = 1
END IF
ELSE
realchanname$ = args(2)
allowinvite% = 1
END IF
IF allowinvite% = 1 THEN
tcpSendData client(n, 1), ":" + hostname$ + " 341 " + user(n, 1) + " " + user(nicknum%, 1) + " " + args(2) + crlf
tcpSendData client(nicknum%, 1), ":" + FullHostMask(n) + " INVITE " + user(nicknum%, 1) + " " + realchanname$
ELSE
SendError n, 482, realchanname$
END IF
END IF
END IF
END IF

CASE "AWAY"
curline$ = TrimFirstColon(curline$)
away(n) = curline$
IF LEN(away(n)) > 0 THEN
tcpSendData client(n, 1), ":" + hostname$ + " 306 " + user(n, 1) + " :You are now marked as being away" + crlf
ELSE
tcpSendData client(n, 1), ":" + hostname$ + " 305 " + user(n, 1) + " :You are no longer marked as being away" + crlf
END IF

CASE "OPER"
GetArgs curline$, 2
IF LEN(args(2)) = 0 THEN
SendError n, 461, cmd$
ELSE
ON ERROR RESUME NEXT
OPEN "conf\opers.ini" FOR BINARY AS #1: CLOSE #1
OPEN "conf\opers.ini" FOR INPUT AS #1
Match = 0
DO UNTIL EOF(1)
INPUT #1, opernick$: IF EOF(1) THEN EXIT DO
INPUT #1, operpass$: IF EOF(1) THEN EXIT DO
INPUT #1, opermodes$
IF LCASE$(opernick$) = LCASE$(args(1)) AND operpass$ = args(2) THEN Match = 1: EXIT DO
LOOP
CLOSE #1
IF ERR <> 0 THEN tcpSendData client(n, 1), ":System!RockIRCd@" + hostname$ + " NOTICE " + user(n, 1) + " :Sorry, there was an error accessing the CONF\OPERS.INI file!" + crlf

IF Match = 1 THEN
AddUserMode n, 0, opermodes$
tcpSendData client(n, 1), ":System!RockIRCd@" + hostname$ + " NOTICE " + user(n, 1) + " :You are now an e-god. Play nicely with the other children." + crlf
ELSE
SendError n, 464, ""
END IF
END IF

CASE "MOTD"
SendMOTD n

CASE "WHOIS"
GetArgs curline$, 2
IF LEN(curline$) = 0 THEN
whichserv$ = ""
ELSE
whichserv$ = args(1)
GetArgs curline$, 2
IF LCASE$(whichserv$) = LCASE$(hostname$) THEN whichserv$ = ""
END IF
IF LEN(whichserv$) = 0 THEN 'did not specify a server
IF LEN(args(1)) = 0 THEN 'if they didn't give us any nicks
SendError n, 461, cmd$
ELSE
reps = 0
DO UNTIL LEN(args(1)) = 0 OR reps = 5 'stop after done, or first 5 nicks
xpcomma = INSTR(args(1), ","): IF xpcomma < 1 THEN xpcomma = LEN(args(1)) + 1
cnick$ = LEFT$(args(1), xpcomma - 1): args(1) = MID$(args(1), xpcomma + 1)
nickval% = NickExists(cnick$)
IF nickval% > 0 THEN
ShowWhois n, nickval%
ELSE
SendError n, 401, cnick$
END IF
reps = reps + 1
LOOP
END IF
ELSE 'specified a different server, which is not supported in RockIRCd yet
SendError n, 402, whichserv$
END IF

CASE "USERHOST"
GetArgs curline$, 5
tmp$ = ":" + hostname$ + " 302 " + user(n, 1) + " :"
FOR chkuserhost = 1 TO 5
userval% = NickExists(args(chkuserhost))
IF userval% > 0 THEN
tmp$ = tmp$ + user(chkuserhost, 1) + "=+" + user(chkuserhost, 2) + "@" + user(chkuserhost, 4) + " "
END IF
NEXT chkuserhost
tcpSendData client(n, 1), RTRIM$(tmp$) + crlf

CASE "LIST"
SendList n

CASE "MODE"
GetArgs curline$, 1
IF LEN(args(1)) = 0 THEN
SendError n, 461, cmd$
ELSE
IF LEFT$(args(1), 1) = "#" THEN 'it's for a channel
chanval% = ChanExists(args(1))
IF chanval% > 0 THEN
IF LEN(curline$) = 0 THEN 'just requesting, not trying to set
IF INSTR(chan(chanval%, 3), "l") > 0 THEN additional$ = STR$(chanlimit(chanval%)) ELSE additional$ = ""
tcpSendData client(n, 1), ":" + hostname$ + " 324 " + user(n, 1) + " " + chan(chanval%, 1) + " +" + chan(chanval%, 3) + additional$ + crlf
tcpSendData client(n, 1), ":" + hostname$ + " 329 " + user(n, 1) + " " + chan(chanval%, 1) + STR$(chancreated(chanval%)) + crlf
ELSE 'trying to set/change modes
AddChanMode n, chanval%, curline$
END IF
ELSE
SendError n, 403, args(1)
END IF
ELSE 'it's for a nick
IF LCASE$(args(1)) = LCASE$(user(n, 1)) OR IsUserMode(n, "a") THEN
nickval% = NickExists(args(1))
IF nickval% > 0 THEN
IF LEN(curline$) = 0 THEN 'just querying modes, not setting
tcpSendData client(n, 1), ":" + hostname$ + " 221 " + user(n, 1) + " +" + user(nickval%, 5) + crlf
ELSE 'trying to set modes
op$ = LEFT$(curline$, 1): curline$ = MID$(curline$, 2)
FOR chkmode = 1 TO LEN(curline$)
char$ = MID$(curline$, chkmode, 1)
SELECT CASE char$
CASE "i", "x"
allow% = 1
CASE ELSE
SendError n, 472, char$
allow% = 0
END SELECT
IF allow% = 1 THEN
IF char$ = "x" AND op$ = "+" THEN
FOR genvh = 1 TO LEN(IP(n))
user(n, 4) = user(n, 4) + HEX$(ASC(MID$(IP(n), genvh, 1)) XOR 128)
NEXT genvh
END IF
IF char$ = "x" AND op$ = "-" THEN user(nickval%, 4) = IP(nickval%)
SELECT CASE op$
CASE "+"
AddUserMode n, nickval%, char$
CASE "-"
xpm = INSTR(user(nickval%, 5), char$)
IF xpm > 0 THEN
user(nickval%, 5) = LEFT$(user(nickval%, 5), xpm - 1) + MID$(user(nickval%, 5), xpm + 1)
tcpSendData client(n, 1), ":" + FullHostMask(n) + " MODE " + user(nickval%, 1) + " " + op$ + char$ + crlf
IF n <> nickval% THEN tcpSendData client(nickval%, 1), ":" + FullHostMask(n) + " MODE " + user(nickval%, 1) + " " + op$ + char$ + crlf
END IF
END SELECT
END IF
NEXT chkmode
END IF
ELSE
SendError n, 401, args(1)
END IF
ELSE
SendError n, 502, ""
END IF
END IF
END IF

CASE "KILL"
GetArgs curline$, 1
IF LEN(args(1)) = 0 THEN
SendError n, 461, cmd$
ELSE
IF IsUserMode(n, "ao") = 1 THEN
nickval% = NickExists(args(1))
IF nickval% < 1 THEN
SendError n, 401, args(1)
ELSE
IF IsUserMode(n, "o") AND IsUserMode(nickval%, "a") THEN
tcpSendData client(n, 1), ":System!RockIRCd@" + hostname$ + " NOTICE " + user(n, 1) + " :You are only +o, and can't kill a +a administrator." + crlf
ELSE
IF LEN(curline$) = 0 THEN curline$ = "No reason specified."
QuitUser nickval%, "Local kill by " + user(n, 1) + " - " + curline$
END IF
END IF
ELSE
SendError n, 481, ""
END IF
END IF

CASE "KICK"
GetArgs curline$, 2
IF LEN(curline$) = 0 THEN curline$ = ":No reason given. [" + user(n, 1) + "]"
loopcount = 0
DO
xp = INSTR(args(1), ","): IF xp < 1 THEN xp = LEN(args(1)) + 1
curchan$ = LEFT$(args(1), xp - 1): args(1) = MID$(args(1), xp + 1)
xp = INSTR(args(2), ","): IF xp < 1 THEN xp = LEN(args(2)) + 1
curnick$ = LEFT$(args(2), xp - 1): args(2) = MID$(args(2), xp + 1)
loopcount = loopcount + 1
IF LEN(curnick$) = 0 THEN
SendError n, 461, cmd$
ELSE
channum% = ChanExists(curchan$)
IF channum% < 1 THEN
SendError n, 403, curchan$
ELSE
nicknum% = NickExists(curnick$)
IF nicknum% < 1 THEN
SendError n, 401, curnick$
ELSE
IF INSTR(mychans(nicknum%), CHR$(channum%)) < 1 THEN
SendError n, 401, args(1) + " " + args(2)
ELSE
allowkick% = 0
IF IsUserChanMode(n, channum%, "qo") THEN allowkick% = 1
IF IsUserChanMode(nicknum%, channum%, "q") THEN IF IsUserChanMode(n, channum%, "q") < 1 THEN allowkick% = 0
IF IsUserMode(n, "qo") THEN allowkick% = 1
IF IsUserMode(nicknum%, "q") AND IsUserMode(n, "q") < 1 THEN allowkick% = 0
IF allowkick% = 1 THEN
ChanBroadcast 0, channum%, ":" + FullHostMask(n) + " KICK " + chan(channum%, 1) + " " + user(nicknum%, 1) + " " + curline$ + crlf
xp = INSTR(chan(channum%, 2), CHR$(nicknum%))
IF xp > 0 THEN chan(channum%, 2) = LEFT$(chan(channum%, 2), xp - 1) + MID$(chan(channum%, 2), xp + 1)
xp = INSTR(mychans(nicknum%), CHR$(channum%))
IF xp > 0 THEN mychans(nicknum%) = LEFT$(mychans(nicknum%), xp - 1) + MID$(mychans(nicknum%), xp + 1)
IF LEN(chan(channum%, 2)) = 0 THEN KillChan channum%
END IF
END IF
END IF
END IF
END IF
LOOP UNTIL loopcount = 5 OR LEN(args(1)) = 0

CASE "TOPIC"
GetArgs curline$, 1
IF LEN(args(1)) > 0 THEN
chanval% = ChanExists(args(1))
IF chanval% > 0 THEN
IF INSTR(chan(chanval%, 2), CHR$(n)) < 1 THEN
SendError n, 442, args(1)
ELSE
IF LEN(curline$) > 0 THEN
IF IsChanMode(chanval%, "t") = 1 AND IsUserChanMode(n, chanval%, "qo") = 0 THEN
allowset% = 0
SendError n, 482, chan(chanval%, 1)
ELSE
allowset% = 1
END IF
IF allowset% = 1 THEN
curline$ = TrimFirstColon(curline$)
topic(chanval%, 1) = LEFT$(curline$, topiclen%)
topic(chanval%, 2) = user(n, 1)
topictime(chanval%) = curunixtime&
FOR chknick = 1 TO LEN(chan(chanval%, 2))
cn% = ASC(MID$(chan(chanval%, 2), chknick, 1))
tcpSendData client(cn%, 1), ":" + FullHostMask(n) + " TOPIC " + chan(chanval%, 1) + " :" + curline$ + crlf
NEXT chknick
END IF
ELSE
SendTopic n, chanval%
END IF
END IF
ELSE
SendError n, 403, args(1)
END IF
ELSE
SendError n, 461, cmd$
END IF

CASE "NAMES"
GetArgs curline$, 1
IF LEN(args(1)) = 0 THEN
SendError n, 461, cmd$ 'not true to RFC.. fix this later!
ELSE
DO UNTIL LEN(args(1)) = 0
xpcomma = INSTR(args(1), ","): IF xpcomma < 1 THEN xpcomma = LEN(args(1)) + 1
curarg$ = LEFT$(args(1), xpcomma - 1): args(1) = MID$(args(1), xpcomma + 1)
curarg$ = NormalizeChan(curarg$)
IF LEN(curarg$) > 0 THEN
chanval% = ChanExists(curarg$)
IF chanval% > 0 THEN SendNames n, chanval%
END IF
LOOP
END IF

CASE "JOIN"
GetArgs curline$, 2
IF LEN(args(1)) = 0 THEN
SendError n, 461, cmd$
ELSE
hasjoined = 0
DO UNTIL LEN(args(1)) = 0 OR hasjoined = 4
xpcomma = INSTR(args(1), ","): IF xpcomma < 1 THEN xpcomma = LEN(args(1)) + 1
curarg$ = LEFT$(args(1), xpcomma - 1): args(1) = MID$(args(1), xpcomma + 1)
curarg$ = NormalizeChan(curarg$)
IF LEN(curarg$) > 0 THEN
hasjoined = hasjoined + 1
chanval% = ChanExists(curarg$)
IF chanval% = 0 THEN chanval% = CreateChan(curarg$): isnew = 1 ELSE isnew = 0
IF chanval% > 0 THEN
banned% = 0
IF IsUserMode(n, "ao") = 0 THEN
FOR checkban = 1 TO 30
IF LEN(ban(chanval%, checkban)) > 0 THEN IF MatchMask(LCASE$(FullHostMask(n)), LCASE$(ban(chanval%, checkban))) = 1 THEN banned% = 1: EXIT FOR
NEXT checkban
END IF
IF banned% = 0 THEN
JoinChan n, chanval%
IF isnew = 1 THEN AddChanMode 0, chanval%, "n"
ELSE
SendError n, 474, chan(chanval%, 1)
END IF
ELSE
SendError n, 405, curarg$
END IF
END IF
LOOP
END IF

CASE "PART"
GetArgs curline$, 1
IF LEN(args(1)) = 0 THEN
SendError n, 461, cmd$
ELSE
DO UNTIL LEN(args(1)) = 0
xpcomma = INSTR(args(1), ","): IF xpcomma < 1 THEN xpcomma = LEN(args(1)) + 1
curarg$ = LEFT$(args(1), xpcomma - 1): args(1) = MID$(args(1), xpcomma + 1)
curarg$ = NormalizeChan(curarg$)
chanval% = ChanExists(curarg$)
IF chanval% = 0 THEN
SendError n, 403, curarg$
ELSE
IF INSTR(chan(chanval%, 2), CHR$(n)) < 1 THEN
SendError n, 442, curarg$
ELSE
PartChan n, chanval%
END IF
END IF
LOOP
END IF

CASE "PRIVMSG", "NOTICE"
GetArgs curline$, 1
curline$ = TrimFirstColon(curline$)
IF LEFT$(args(1), 1) = "#" THEN 'it's addressed to a channel
towho% = ChanExists(args(1))
IF towho% > 0 THEN
IF LEN(curline$) > 0 THEN
allowmsg% = 1
IF IsUserMode(n, "ao") = 0 THEN
IF IsChanMode(towho%, "m") = 1 AND IsUserChanMode(n, towho%, "voq") = 0 THEN
allowmsg% = 0
SendError n, 404, chan(towho%, 1)
END IF
IF IsChanMode(towho%, "n") = 1 AND INSTR(mychans(n), CHR$(towho%)) < 1 THEN
allowmsg% = 0
SendError n, 404, chan(towho%, 1)
END IF
FOR checkban = 1 TO 30
IF LEN(ban(chanval%, checkban)) > 0 THEN IF MatchMask(LCASE$(FullHostMask(n)), LCASE$(ban(chanval%, checkban))) = 1 THEN allowmsg% = 1: EXIT FOR
NEXT checkban
END IF

IF allowmsg% = 1 THEN
IF towho% = monitor% THEN
PRINT "<" + user(n, 1) + "> " + curline$
END IF
ChanBroadcast n, towho%, ":" + FullHostMask(n) + " " + cmd$ + " " + chan(towho%, 1) + " :" + curline$ + crlf
ELSE
SendError n, 404, chan(towho%, 1)
END IF
ELSE
SendError n, 412, ""
END IF
ELSE
SendError n, 403, args(1)
END IF
ELSE 'it's addressed to a user
SELECT CASE LCASE$(args(1))
CASE "system" 'talking to the system bot
SystemPM n, curline$

CASE ELSE
towho% = NickExists(args(1))
IF towho% > 0 THEN
IF LEN(curline$) > 0 THEN
tcpSendData client(towho%, 1), ":" + FullHostMask(n) + " " + cmd$ + " " + user(towho%, 1) + " :" + curline$ + crlf
IF LEN(away(towho%)) > 0 THEN tcpSendData client(n, 1), ":" + hostname$ + " 301 " + user(n, 1) + " " + user(towho%, 1) + " :" + away(towho%) + crlf
ELSE
SendError n, 412, ""
END IF
ELSE
IF LEN(args(1)) = 0 THEN
SendError n, 411, cmd$
ELSE
SendError n, 401, args(1)
END IF
END IF
END SELECT
END IF

CASE "USER"
SendError n, 462, ""
CASE ELSE
SendError n, 421, cmd$
END SELECT
RETURN

realloc:
tempnewhand% = client(n, 1)

rc% = tcpSetOption(tempnewhand%, 1, 1)

Sockets(tempnewhand%).IPaddr = STRING$(4, 0)
Sockets(tempnewhand%).RemPort = 0
Sockets(tempnewhand%).LocPort = NewListenPort%
Sockets(tempnewhand%).Protocol = CHR$(protTCP)

'DIM tmptcp AS TCPaddr
'tmptcp
tcpCall.bx = tempnewhand%
tcpCall.dx = protTCP
tcpCall.ds = VARSEG(Sockets(tempnewhand%))
tcpCall.si = VARPTR(Sockets(tempnewhand%))
tcpCall.ax = &H2300
CALL interruptx(dTCP.IntVec, tcpCall, tcpReturn)

IF CarrySet = 0 THEN 'no error
'tcpListen% = tcpReturn.ax
dTCP.ErrorVal = 0
ELSE
'tcpListen% = -1
dTCP.ErrorVal = tcpReturn.ax
END IF
RETURN

dorelease:
tcpCall.bx = client(n, 1)
tcpCall.ax = &H800
CALL interruptx(dTCP.IntVec, tcpCall, tcpReturn)
RETURN

doflush:
tcpCall.bx = client(n, 1)
tcpCall.ax = &H1E00
CALL interruptx(dTCP.IntVec, tcpCall, tcpReturn)
RETURN

keyboardhandler:
DO
key$ = INKEY$
IF monitor% > 0 AND key$ = CHR$(27) THEN
PRINT "Live monitor is now turned off."
monitor% = 0
EXIT DO
ELSE
IF monitor% > 0 THEN key$ = "": EXIT DO
END IF
SELECT CASE key$
CASE ""
EXIT DO
CASE CHR$(9), CHR$(10)
CASE CHR$(8)
IF LEN(localin$) > 0 THEN localin$ = LEFT$(localin$, LEN(localin$) - 1)
CASE CHR$(13)
LOCATE CSRLIN, 1, 0
PRINT LEFT$(">" + localin$ + SPACE$(79), 79);
LOCATE CSRLIN, LEN(localin$) + 2, 1
PRINT
xpsp = INSTR(localin$, " "): IF xpsp < 1 THEN xpsp = LEN(localin$) + 1
firstarg$ = LTRIM$(RTRIM$(LCASE$(LEFT$(localin$, xpsp - 1))))
secondarg$ = LTRIM$(RTRIM$(LCASE$(MID$(localin$, xpsp + 1))))

SELECT CASE firstarg$
CASE "quit"
doquit% = 1

CASE "show"
SELECT CASE LCASE$(secondarg$)
CASE "status"
PRINT "Monitoring connections 1 through" + STR$(checkto%) + " of" + STR$(maxconn%) + " max:"
FOR shownode% = 1 TO checkto%
SELECT CASE client(shownode%, 2)
CASE 1
PRINT RIGHT$(" " + STR$(shownode%), 3) + ": Waiting for connection..."
CASE 2, 3
PRINT RIGHT$(" " + STR$(shownode%), 3) + ": Closing connection..."
CASE 4
PRINT RIGHT$(" " + STR$(shownode%), 3) + ": Online (" + FullHostMask(shownode%) + " - True IP: " + IP(shownode%) + ")"
CASE ELSE
PRINT RIGHT$(" " + STR$(shownode%), 3) + ": No connection."
END SELECT
NEXT shownode%

CASE "chan", "channel", "channels"
sch$ = ""
PRINT "Full channel list: ";
FOR showchan% = 1 TO 30
IF LEN(chan(showchan%, 1)) > 0 THEN sch$ = sch$ + chan(showchan%, 1) + " (" + MID$(STR$(LEN(chan(showchan%, 2))), 2) + "), "
NEXT showchan%
IF LEN(sch$) > 0 THEN
sch$ = LEFT$(sch$, LEN(sch$) - 2)
PRINT sch$
ELSE
PRINT "No channels currently exist on the server."
END IF
END SELECT

CASE "kill"
killwho% = VAL(secondarg$)
IF killwho% < 1 OR killwho% > maxconn% THEN
PRINT "You did not supply a valid connection number to kill."
ELSE
IF client(killwho%, 2) <> 4 THEN
PRINT "There is no active client on connection" + STR$(killwho%) + "."
ELSE
LINE INPUT "Enter kill reason: ", curline$
IF LEN(curline$) = 0 THEN curline$ = "No reason specified."
QuitUser killwho%, "Local kill from the admin console - " + curline$
END IF
END IF

CASE ELSE
PRINT "Unrecognized command."
END SELECT
localin$ = ""
PRINT
CASE CHR$(27)
localin$ = ""
CASE ELSE
IF LEN(localin$) < 78 THEN localin$ = localin$ + key$
END SELECT
LOOP

LOCATE CSRLIN, 1, 0
PRINT LEFT$(">" + localin$ + SPACE$(79), 79);
LOCATE CSRLIN, LEN(localin$) + 2, 1
RETURN

SUB AddChanMode (BYVAL whoset%, BYVAL chanval%, modeval$)
modeval$ = LTRIM$(RTRIM$(modeval$))
xpos = INSTR(modeval$, " ")
IF xpos > 0 THEN argument$ = MID$(modeval$, xpos + 1)
IF LEN(modeval$) = 0 THEN
IF whoset% < 1 THEN EXIT SUB
IF chanlimit(chanval%) > 0 THEN addition$ = STR$(chanlimit(chanval%))
'IF LEN(chan(chanval%, 3)) > 0 THEN
tcpSendData client(whoset%, 1), ":" + hostname$ + " 324 " + user(whoset%, 1) + " " + chan(chanval%, 1) + " +" + chan(chanval%, 3) + additional$ + crlf
tcpSendData client(whoset%, 1), ":" + hostname$ + " 329 " + user(whoset%, 1) + " " + chan(chanval%, 1) + STR$(chancreated(chanval%)) + crlf
EXIT SUB
END IF
IF modeval$ = "+b" THEN
IF whoset% < 1 THEN EXIT SUB
FOR checkban = 1 TO 30
IF LEN(ban(chanval%, checkban)) > 0 THEN tcpSendData client(whoset%, 1), ":" + hostname$ + " 367 " + user(whoset%, 1) + " " + chan(chanval%, 1) + " " + ban(chanval%, checkban) + crlf
NEXT checkban
tcpSendData client(whoset%, 1), ":" + hostname$ + " 368 " + user(whoset%, 1) + " " + chan(chanval%, 1) + " :End of Channel Ban List" + crlf
EXIT SUB
END IF

IF whoset% = 0 THEN fromname$ = hostname$ ELSE fromname$ = user(whoset%, 1)
IF whoset% > 0 AND INSTR(mychans(whoset%), CHR$(chanval%)) < 1 THEN
IF whoset% > 0 AND IsUserMode(whoset%, "ao") = 0 THEN
SendError whoset%, 442, chan(chanval%, 1)
EXIT SUB
END IF
END IF

op$ = LEFT$(modeval$, 1): modeval$ = MID$(modeval$, 2)
IF op$ = "+" THEN
xpos = INSTR(modeval$, "-")
IF xpos > 0 THEN modeval$ = LEFT$(modeval$, xpos - 1)
ELSE
IF op$ <> "-" THEN
IF whoset% > 0 THEN SendError whoset%, 461, "MODE"
EXIT SUB
END IF
xpos = INSTR(modeval$, "+")
IF xpos > 0 THEN modeval$ = LEFT$(modeval$, xpos - 1)
END IF
IF LEN(modeval$) = 0 THEN EXIT SUB

added$ = ""
IF whoset% = 0 OR IsUserMode(whoset%, "ao") OR IsUserChanMode(whoset%, chanval%, "qo") THEN allow% = 1 ELSE allow% = 0
IF allow% = 0 THEN SendError whoset%, 482, chan(chanval%, 1): EXIT SUB
xpos = INSTR(modeval$, " ")
IF xpos > 0 THEN
modeargs$ = LTRIM$(RTRIM$(MID$(modeval$, xpos + 1)))
modeval$ = LTRIM$(RTRIM$(LEFT$(modeval$, xpos - 1)))
END IF
xpos = INSTR(modeval$, "l")
IF xpos > 0 THEN
modeval$ = LEFT$(modeval$, xpos - 1) + MID$(modeval$, xpos + 1)
IF op$ = "-" THEN
xpos = INSTR(chan(chanval%, 3), "l")
chan(chanval%, 3) = LEFT$(chan(chanval%, 3), xpos - 1) + MID$(chan(chanval%, 3), xpos + 1)
sendtxt$ = ":" + fromname$ + " MODE " + chan(chanval%, 1) + " -l" + STR$(limitval%) + crlf
ChanBroadcast 0, chanval%, sendtxt$
IF whoval% > 0 THEN IF INSTR(mychans(whoval%), CHR$(chanval%)) < 1 THEN tcpSendData client(whoval%, 1), sendtxt$
ELSE
IF LEN(modeargs$) < 1 THEN
SendError whoset%, 461, "MODE"
EXIT SUB
ELSE
xpos = INSTR(modeargs$, " ")
IF xpos < 1 THEN xpos = LEN(modeargs$) + 1
lv$ = LEFT$(modeargs$, xpos - 1): modeargs$ = MID$(modeargs$, xpos + 1)
limitval% = VAL(RIGHT$(lv$, 2))
'COLOR 15, 1: PRINT limitval%: COLOR 7, 0
IF limitval% < 1 THEN
SendError whoset%, 461, "MODE"
EXIT SUB
ELSE
IF INSTR(chan(chanval%, 3), "l") < 1 THEN chan(chanval%, 3) = chan(chanval%, 3) + "l"
chanlimit(chanval%) = limitval%
sendtxt$ = ":" + fromname$ + " MODE " + chan(chanval%, 1) + " +l" + STR$(limitval%) + crlf
ChanBroadcast 0, chanval%, sendtxt$
IF whoval% > 0 THEN IF INSTR(mychans(whoval%), CHR$(chanval%)) < 1 THEN tcpSendData client(whoval%, 1), sendtxt$
END IF
END IF
END IF
END IF

multi$ = ""
newmodeval$ = ""
FOR nadd = 1 TO LEN(modeval$)
cc$ = MID$(modeval$, nadd, 1)
IF cc$ = "q" OR cc$ = "o" OR cc$ = "b" OR cc$ = "v" THEN
multi$ = multi$ + cc$
ELSE
newmodeval$ = newmodeval$ + cc$
END IF
NEXT nadd
modeval$ = newmodeval$: newmodeval$ = ""

FOR nadd = 1 TO LEN(multi$)
xpos = INSTR(argument$, " "): IF xpos < 1 THEN xpos = LEN(argument$) + 1
curarg$ = LTRIM$(RTRIM$(LEFT$(argument$, xpos - 1))): argument$ = MID$(argument$, xpos + 1)
IF LEN(curarg$) = 0 THEN EXIT FOR
allow% = 0
char$ = MID$(multi$, nadd, 1)
SELECT CASE char$
CASE "q"
IF IsUserChanMode(whoset%, chanval%, "q") OR IsUserMode(whoset%, "ao") THEN allow% = 1
CASE "o"
IF IsUserChanMode(whoset%, chanval%, "qo") OR IsUserMode(whoset%, "ao") THEN allow% = 1
CASE "b"
IF IsUserChanMode(whoset%, chanval%, "qo") OR IsUserMode(whoset%, "ao") THEN allow% = 1
CASE "v"
IF IsUserChanMode(whoset%, chanval%, "qo") OR IsUserMode(whoset%, "ao") THEN allow% = 1
END SELECT
IF allow% = 1 THEN
IF char$ <> "b" THEN
nicknum% = NickExists(curarg$)
IF nicknum% > 0 THEN
IF INSTR(mychans(nicknum%), CHR$(chanval%)) > 0 THEN
allow2% = 0
SELECT CASE op$
CASE "+"
IF IsUserChanMode(nicknum%, chanval%, char$) = 0 THEN allow2% = 1
CASE "-"
IF IsUserChanMode(nicknum%, chanval%, char$) > 0 THEN allow2% = 1
END SELECT
IF allow2% = 1 THEN
ChanBroadcast 0, chanval%, ":" + fromname$ + " MODE " + chan(chanval%, 1) + " " + op$ + char$ + " " + user(nicknum%, 1) + crlf
IF op$ = "+" THEN AddUserChanMode nicknum%, chanval%, char$ ELSE DelUserChanMode nicknum%, chanval%, char$
END IF
ELSE
SendError whoset%, 441, curarg$ + " " + chan(chanval%, 1)
END IF
ELSE
SendError whoset%, 401, curarg$
END IF
ELSE
IF op$ = "+" THEN
dupe% = 0: firstfree% = 0
FOR checkban = 1 TO 30
IF LEN(ban(chanval%, checkban)) = 0 AND firstfree% = 0 THEN firstfree% = checkban
IF LCASE$(ban(chanval%, checkban)) = LCASE$(curarg$) THEN dupe% = 1: EXIT FOR
NEXT checkban
IF dupe% = 0 AND firstfree% > 0 THEN
ban(chanval%, firstfree%) = curarg$
ChanBroadcast 0, chanval%, ":" + FullHostMask(whoset%) + " MODE " + chan(chanval%, 1) + " +b " + curarg$ + crlf
EXIT SUB
END IF
ELSE
FOR checkban = 1 TO 30
IF LCASE$(ban(chanval%, checkban)) = LCASE$(curarg$) THEN ban(chanval%, checkban) = "": EXIT FOR
NEXT checkban
ChanBroadcast 0, chanval%, ":" + FullHostMask(whoset%) + " MODE " + chan(chanval%, 1) + " -b " + curarg$ + crlf
EXIT SUB
END IF
END IF
ELSE
SendError whoset%, 482, curarg$
END IF
NEXT nadd

FOR nadd = 1 TO LEN(modeval$)
cmode$ = MID$(modeval$, nadd, 1)
SELECT CASE cmode$
CASE "m", "n", "t"
IF op$ = "+" AND INSTR(chan(chanval%, 3), cmode$) < 1 THEN
added$ = added$ + cmode$
ELSE
xpos = INSTR(chan(chanval%, 3), cmode$)
IF op$ = "-" AND xpos > 0 THEN
chan(chanval%, 3) = LEFT$(chan(chanval%, 3), xpos - 1) + MID$(chan(chanval%, 3), xpos + 1)
added$ = added$ + cmode$
END IF
END IF

CASE ELSE
IF whoval% > 0 THEN SendError whoval%, 472, cmode$
END SELECT
NEXT nadd
IF LEN(added$) = 0 THEN EXIT SUB

sendtxt$ = ":" + fromname$ + " MODE " + chan(chanval%, 1) + " " + op$ + added$ + crlf
ChanBroadcast 0, chanval%, sendtxt$
IF whoval% > 0 THEN IF INSTR(mychans(whoval%), CHR$(chanval%)) < 1 THEN tcpSendData client(whoval%, 1), sendtxt$
END SUB

SUB AddUserChanMode (BYVAL nickval%, BYVAL chanval%, char$)
xp = INSTR(userchan(nickval%, chanval%), char$)
IF xp > 0 THEN EXIT SUB
userchan(nickval%, chanval%) = userchan(nickval%, chanval%) + char$
END SUB

SUB AddUserMode (BYVAL towho%, BYVAL fromwho%, addmodes$)
added$ = ""
FOR chkmodes = 1 TO LEN(addmodes$)
cm$ = MID$(addmodes$, chkmodes, 1)
IF INSTR(user(towho%, 5), cm$) < 1 THEN added$ = added$ + cm$
NEXT chkmodes
IF LEN(added$) > 0 THEN
user(towho%, 5) = user(towho%, 5) + added$
IF fromwho% = 0 THEN
fromuser$ = hostname$
ELSE
fromuser$ = user(fromwho%, 1)
END IF
tcpSendData client(fromwho%, 1), ":" + fromuser$ + " MODE " + user(towho%, 1) + " :+" + added$ + crlf
IF towho% <> fromwho% THEN tcpSendData client(towho%, 1), ":" + fromuser$ + " MODE " + user(towho%, 1) + " :+" + added$ + crlf
END IF
END SUB

FUNCTION CarrySet%
IF FIX(tcpReturn.flags / 2) <> tcpReturn.flags / 2 THEN CarrySet% = 1 ELSE CarrySet = 0
END FUNCTION

SUB ChanBroadcast (BYVAL nosend%, BYVAL chanval%, textmsg$)
FOR sendto = 1 TO LEN(chan(chanval%, 2))
userval = ASC(MID$(chan(chanval%, 2), sendto, 1))
IF userval <> nosend% THEN tcpSendData client(userval, 1), textmsg$
NEXT sendto
END SUB

FUNCTION ChanExists% (testchan$)
FOR chkchans = 1 TO maxchan%
IF LCASE$(testchan$) = LCASE$(chan(chkchans, 1)) THEN ChanExists% = chkchans: EXIT FUNCTION
NEXT chkchans
END FUNCTION

SUB ChangeNick (BYVAL whichuser%, newnick$)
IF LEN(user(whichuser%, 1)) > 0 THEN tcpSendData client(whichuser%, 1), ":" + FullHostMask(whichuser%) + " NICK " + newnick$ + crlf

senditto$ = ""
FOR chkchan = 1 TO LEN(mychans(whichuser%))
curchan% = ASC(MID$(mychans(whichuser%), chkchan, 1))
FOR chknick = 1 TO LEN(chan(curchan%, 2))
curwho$ = MID$(chan(curchan%, 2), chknick, 1)
IF INSTR(senditto$, curwho$) < 1 THEN senditto$ = senditto$ + curwho$
NEXT chknick
NEXT chkchan

FOR chknick = 1 TO LEN(senditto$)
curval% = ASC(MID$(senditto$, chknick, 1))
IF curval% <> whichuser% THEN tcpSendData client(curval%, 1), ":" + FullHostMask(whichuser%) + " NICK " + newnick$ + crlf
NEXT chknick

user(whichuser%, 1) = newnick$
END SUB

FUNCTION ChanPrefix$ (BYVAL userval%, BYVAL chanval%)
IF IsUserChanMode(userval%, chanval%, "q") THEN ChanPrefix$ = "~": EXIT FUNCTION
IF IsUserChanMode(userval%, chanval%, "o") THEN ChanPrefix$ = "@": EXIT FUNCTION
IF IsUserChanMode(userval%, chanval%, "v") THEN ChanPrefix$ = "+": EXIT FUNCTION
END FUNCTION

FUNCTION CreateChan% (newchan$)
FOR chkchan = 1 TO maxchan%
IF LEN(chan(chkchan, 1)) = 0 THEN
chan(chkchan, 1) = newchan$
chan(chkchan, 2) = ""
chan(chkchan, 3) = "n"
topic(chkchan, 1) = ""
topic(chkchan, 2) = ""
topictime(chkchan) = 0
chancreated(chkchan) = UnixTimeEnc(DATE$, TIMER)
CreateChan% = chkchan
EXIT FUNCTION
END IF
NEXT chkchan
END FUNCTION

SUB DelUserChanMode (BYVAL nicknum%, BYVAL chanval%, char$)
xp = INSTR(userchan(nicknum%, chanval%), char$)
IF xp < 1 THEN EXIT SUB
userchan(nicknum%, chanval%) = LEFT$(userchan(nicknum%, chanval%), xp - 1) + MID$(userchan(nicknum%, chanval%), xp + 1)
END SUB

FUNCTION FullHostMask$ (BYVAL whichuser%)
FullHostMask$ = user(whichuser%, 1) + "!" + user(whichuser%, 2) + "@" + user(whichuser%, 4)
END FUNCTION

SUB GetArgs (thedata$, BYVAL howmanyargs%)
FOR argtrim = 1 TO howmanyargs%
xps = INSTR(thedata$, " "): IF xps < 1 THEN xps = LEN(thedata$) + 1
args(argtrim) = LTRIM$(RTRIM$(LEFT$(thedata$, xps - 1)))
thedata$ = MID$(thedata$, xps + 1)
IF LEN(thedata$) = 0 THEN EXIT SUB
NEXT argtrim
END SUB

FUNCTION HighByte% (BYVAL Word AS INTEGER)
HighByte% = ASC(LEFT$(MKI$(Word), 1))
END FUNCTION

FUNCTION IsChanMode% (BYVAL chanval%, modechars$)
FOR chkmode = 1 TO LEN(modechars$)
IF INSTR(chan(chanval%, 3), MID$(modechars$, chkmode, 1)) > 0 THEN IsChanMode% = 1: EXIT FUNCTION
NEXT chkmode
END FUNCTION

FUNCTION IsUserChanMode% (BYVAL userval%, BYVAL chanval%, modeval$)
FOR nchkmode = 1 TO LEN(modeval$)
IF INSTR(userchan(userval%, chanval%), MID$(modeval$, nchkmode, 1)) THEN IsUserChanMode% = 1: EXIT FUNCTION
NEXT nchkmode
END FUNCTION

FUNCTION IsUserMode% (BYVAL checkwho%, checkmodes$)
FOR chkm = 1 TO LEN(checkmodes$)
IF INSTR(user(checkwho%, 5), MID$(checkmodes$, chkm, 1)) > 0 THEN IsUserMode% = 1: EXIT FUNCTION
NEXT chkm
END FUNCTION

SUB JoinChan (BYVAL whojoins%, BYVAL chanval%)
IF chanval% < 1 OR chanval% > maxchan% THEN EXIT SUB
IF INSTR(chan(chanval%, 2), CHR$(whojoins%)) > 0 THEN EXIT SUB

IF LEN(chan(chanval%, 2)) = 0 THEN
userchan(whojoins%, chanval%) = "o"
ELSE
userchan(whojoins%, chanval%) = ""
END IF
chan(chanval%, 2) = chan(chanval%, 2) + CHR$(whojoins%)
mychans(whojoins%) = mychans(whojoins%) + CHR$(chanval%)
ChanBroadcast 0, chanval%, ":" + FullHostMask(whojoins%) + " JOIN " + chan(chanval%, 1) + crlf
IF chan(chanval%, 2) = CHR$(whojoins%) THEN tcpSendData client(whojoins%, 1), ":" + hostname$ + " MODE " + chan(chanval%, 1) + " +" + chan(chanval%, 3) + crlf

SendNames whojoins%, chanval%
SendTopic whojoins%, chanval%
END SUB

SUB KillChan (BYVAL whichchan%)
IF whichchan% < 1 THEN EXIT SUB

FOR chknick = 1 TO LEN(chan(whichchan%, 2))
cn% = ASC(MID$(chan(whichchan%, 2), chknick, 1))
tcpSendData client(chknick, 1), ":" + FullHostMask(cn%) + " PART " + chan(whichchan%, 1) + " :Channel has been killed by an IRCop." + crlf
NEXT chknick

FOR clearban = 1 TO 30
ban(whichchan%, clearban) = ""
NEXT clearban

chan(whichchan%, 1) = ""
chan(whichchan%, 2) = ""
chan(whichchan%, 3) = ""
topic(whichchan%, 1) = ""
topic(whichchan%, 2) = ""
topictime(whichchan%) = 0
END SUB

FUNCTION LowByte% (BYVAL Word AS INTEGER)
LowByte% = ASC(RIGHT$(MKI$(Word), 1))
END FUNCTION

FUNCTION MakeIP$ (tmpipval$)
tmpwork$ = tmpipval$
tmpnewip$ = ""
dotpos = INSTR(tmpwork$, "."): IF dotpos < 1 THEN tmpipval$ = STRING$(4, 0): EXIT FUNCTION
va% = VAL(LEFT$(tmpwork$, dotpos - 1)): tmpwork$ = MID$(tmpwork$, dotpos + 1)

dotpos = INSTR(tmpwork$, "."): IF dotpos < 1 THEN tmpipval$ = STRING$(4, 0): EXIT FUNCTION
vb% = VAL(LEFT$(tmpwork$, dotpos - 1)): tmpwork$ = MID$(tmpwork$, dotpos + 1)

dotpos = INSTR(tmpwork$, "."): IF dotpos < 1 THEN tmpipval$ = STRING$(4, 0): EXIT FUNCTION
vc% = VAL(LEFT$(tmpwork$, dotpos - 1)): tmpwork$ = MID$(tmpwork$, dotpos + 1)

vd% = VAL(tmpwork$)

MakeIP$ = CHR$(va%) + CHR$(vb%) + CHR$(vc%) + CHR$(vd%)
END FUNCTION

FUNCTION MatchMask% (check$, against$)
chk$ = against$
tmp$ = check$

Match% = 1
FOR chkm = 1 TO LEN(chk$)
curchar$ = MID$(chk$, chkm, 1)
nextchar$ = MID$(chk$, chkm + 1, 1)
IF curchar$ = "*" THEN
IF LEN(nextchar$) = 0 THEN EXIT FOR
xpm = INSTR(tmp$, nextchar$)
IF xpm < 1 THEN Match% = 0: EXIT FOR
tmp$ = MID$(tmp$, xpm + 1)
chkm = chkm + 1
ELSE
IF LEFT$(tmp$, 1) <> curchar$ THEN Match% = 0: EXIT FOR
tmp$ = MID$(tmp$, 2)
END IF
IF LEN(tmp$) = 0 THEN EXIT FOR
NEXT chkm
MatchMask% = Match%
END FUNCTION

FUNCTION NickExists% (testnick$)
FOR chknicks = 1 TO maxconn%
IF LCASE$(testnick$) = LCASE$(user(chknicks, 1)) THEN NickExists% = chknicks: EXIT FUNCTION
NEXT chknicks
END FUNCTION

FUNCTION NormalizeChan$ (oldchan$)
tmpchan$ = oldchan$
newchan$ = ""
FOR cfix = 1 TO LEN(tmpchan$)
ncc$ = MID$(tmpchan$, cfix, 1)
IF INSTR(LCASE$(chanchars$), LCASE$(ncc$)) > 0 THEN newchan$ = newchan$ + ncc$
NEXT cfix
IF LEFT$(newchan$, 1) <> "#" THEN newchan$ = "#" + newchan$
NormalizeChan$ = LEFT$(newchan$, chanlen%)
END FUNCTION

FUNCTION NormalizeNick$ (oldnick$)
tmpnick$ = oldnick$
newnick$ = ""
FOR nfix = 1 TO LEN(tmpnick$)
ncc$ = MID$(tmpnick$, nfix, 1)
IF INSTR(LCASE$(nickchars$), LCASE$(ncc$)) > 0 THEN newnick$ = newnick$ + ncc$
NEXT nfix
SELECT CASE LCASE$(newnick$)
CASE "system", "nickserv", "operserv", "chanserv", "memoserv"
newnick$ = " " 'space to let routine we return to know it was illegal
END SELECT
NormalizeNick$ = LEFT$(newnick$, nicklen%)
END FUNCTION

SUB PartChan (BYVAL whoparts%, BYVAL chanval%)
ChanBroadcast 0, chanval%, ":" + FullHostMask(whoparts%) + " PART " + chan(chanval%, 1) + crlf

xpuser = INSTR(chan(chanval%, 2), CHR$(whoparts%))
IF xpuser < 1 THEN EXIT SUB
chan(chanval%, 2) = LEFT$(chan(chanval%, 2), xpuser - 1) + MID$(chan(chanval%, 2), xpuser + 1)

xpchan = INSTR(mychans(whoparts%), CHR$(chanval%))
IF xpchan < 1 THEN EXIT SUB
mychans(whoparts%) = LEFT$(mychans(whoparts%), xpchan - 1) + MID$(mychans(whoparts%), xpchan + 1)

userchan(whoparts%, chanval%) = ""

IF LEN(chan(chanval%, 2)) = 0 THEN KillChan chanval% 'kill if no other users are there
END SUB

SUB QuitChan (BYVAL whoparts%, BYVAL chanval%, quitmsg$)
xpuser = INSTR(chan(chanval%, 2), CHR$(whoparts%))
IF xpuser < 1 THEN EXIT SUB
chan(chanval%, 2) = LEFT$(chan(chanval%, 2), xpuser - 1) + MID$(chan(chanval%, 2), xpuser + 1)

xpchan = INSTR(mychans(whoparts%), CHR$(chanval%))
IF xpchan < 1 THEN EXIT SUB
mychans(whoparts%) = LEFT$(mychans(chanval%), xpchan - 1) + MID$(mychans(chanval%), xpchan + 1)

userchan(whoparts%, chanval%) = ""
IF LEN(chan(chanval%, 2)) = 0 THEN KillChan chanval% 'kill if no other users are there
END SUB

SUB QuitUser (BYVAL whichuser%, quitmsg$)
tmpquit$ = TrimFirstColon(quitmsg$) 'because you can't BYVAL a string, and don't want to overwrite it!
IF LEN(tmpquit$) = 0 THEN quitmsg$ = "No reason given. [" + build$ + "]"

IF LEFT$(quitmsg$, 2) = "::" THEN quitmsg$ = MID$(quitmsg$, 2)
IF gracequit(whichuser%) = 0 THEN
tcpSendData client(whichuser%, 1), "ERROR :Closing Link: [" + user(n, 4) + "] (" + quitmsg$ + ")" + crlf
tcpFlush whichuser%
rc2% = tcpAbort(client(whichuser%, 1))
END IF
gracequit(whichuser%) = 1

tmpchanline$ = mychans(whichuser%)
senditto$ = ""
FOR chkchan = 1 TO LEN(tmpchanline$)
curval% = ASC(MID$(tmpchanline$, chkchan, 1))
FOR chknick = 1 TO LEN(chan(curval%, 2))
ncc$ = MID$(chan(curval%, 2), chknick, 1)
IF INSTR(senditto$, ncc$) < 1 AND ASC(ncc$) <> whichuser% THEN senditto$ = senditto$ + ncc$
NEXT chknick
QuitChan whichuser%, curval%, quitmsg$
NEXT chkchan

FOR chknick = 1 TO LEN(senditto$)
sendto% = ASC(MID$(senditto$, chknick, 1))
tcpSendData client(sendto%, 1), ":" + FullHostMask(whichuser%) + " QUIT :" + quitmsg$ + crlf
NEXT chknick
tcpFlush client(whichuser%, 1)
rc2% = tcpAbort(client(whichuser%, 1))

state(whichuser%) = 0
user(whichuser%, 1) = "" 'nick
user(whichuser%, 2) = "" 'username
user(whichuser%, 3) = "" 'realname
user(whichuser%, 4) = "" 'vhost
user(whichuser%, 5) = "" 'user modes
FOR chanclear = 1 TO 30
userchan(whichuser%, chanclear) = "" 'user's modes for channels
NEXT chanclear
away(whichuser%) = ""
mychans(whichuser%) = ""

END SUB

SUB SendError (BYVAL whichsock%, BYVAL errnum AS INTEGER, addto$)
SELECT CASE errnum
CASE 401
tmperr$ = addto$ + " :No such nick/channel"
CASE 402
tmperr$ = addto$ + " :No such server"
CASE 403
tmperr$ = addto$ + " :No such channel"
CASE 404
tmperr$ = addto$ + " :Cannot send to channel (no voice, no joined +n channel, or you are +b in channel)"
CASE 405
tmperr$ = addto$ + " :You have joined too many channels, or the server's channel global limit has been met"
CASE 411
tmperr$ = ":No recipient given (" + addto$ + ")"
CASE 412
tmperr$ = ":No text to send"
CASE 421
tmperr$ = addto$ + " :Unknown command (" + addto$ + ")"
CASE 431
tmperr$ = ":No nickname given"
CASE 436
tmperr$ = addto$ + " :Nickname is already in use"
CASE 441
tmperr$ = addto$ + " :They aren't on that channel"
CASE 442
tmperr$ = addto$ + " :You're not on that channel"
CASE 443
tmperr$ = addto$ + " :is already on channel"
CASE 451
tmperr$ = ":You have not registered"
CASE 461
tmperr$ = addto$ + " :Not enough parameters"
CASE 462
tmperr$ = ":You may not reregister"
CASE 464
tmperr$ = ":Password incorrect"
CASE 472
tmperr$ = addto$ + " :is unknown mode char to me"
CASE 474
tmperr$ = addto$ + " :Cannot join channel (+b)"
CASE 481
tmperr$ = ":Permission Denied- You're not an IRC operator"
CASE 482
tmperr$ = addto$ + " :You're not channel operator"
CASE 502
tmperr$ = ":Can't change mode for other users"
CASE ELSE
tmperr$ = ":Unknown error"
END SELECT
tcpSendData client(whichsock%, 1), ":" + hostname$ + STR$(errnum) + " " + tmperr$ + crlf
END SUB

SUB SendInfo (BYVAL towho%)
hdr$ = ":" + hostname$ + " 371 " + user(towho%, 1) + " :"
snd$ = hdr$ + "Server version is " + build$ + crlf
snd$ = snd$ + hdr$ + " " + crlf + hdr$ + "RockIRCd is a freeware true DOS-compatible IRC server written by Mike Chambers (miker00lz@gmail.com)" + crlf
snd$ = snd$ + hdr$ + "Development began in early January, 2009. The home website is http://www.rubbermallet.org" + crlf
snd$ = snd$ + hdr$ + "RockIRCd was written on a 286, completely in QuickBASIC 7.1 PDS." + crlf
snd$ = snd$ + hdr$ + " " + crlf + hdr$ + "This software was originally designed to allow an old spare 8088 computer to become a dedicated IRC server." + crlf
snd$ = snd$ + hdr$ + " " + crlf + hdr$ + "Mike would like to thank his loyal testing crew:" + crlf
snd$ = snd$ + hdr$ + " - duked" + crlf
snd$ = snd$ + hdr$ + " - Superdos" + crlf
snd$ = snd$ + hdr$ + " - usotsuki" + crlf
snd$ = snd$ + hdr$ + " - Krille" + crlf
snd$ = snd$ + hdr$ + " " + crlf
snd$ = snd$ + "This server has been online since " + creation$ + crlf
tcpSendData client(towho%, 1), snd$
END SUB

SUB SendList (BYVAL whichuser%)
tcpSendData client(whichuser%, 1), ":" + hostname$ + " 321 " + user(whichuser%, 1) + " Channel :Users Name" + crlf
FOR chkchans = 1 TO maxchan%
IF LEN(chan(chkchans, 1)) > 0 THEN
tcpSendData client(whichuser%, 1), ":" + hostname$ + " 322 " + user(whichuser%, 1) + " " + chan(chkchans, 1) + STR$(LEN(chan(chkchans, 2))) + " :" + topic(chkchans, 1) + crlf
END IF
NEXT chkchans
tcpSendData client(whichuser%, 1), ":" + hostname$ + " 323 " + user(whichuser%, 1) + " :End of /LIST" + crlf
END SUB

SUB SendMOTD (BYVAL whichuser%)
IF LEN(motd$) = 0 THEN
tcpSendData client(whichuser%, 1), ":" + hostname$ + " 422 " + user(whichuser%, 1) + " :MOTD File is missing" + crlf
EXIT SUB
END IF
tmpmotd$ = motd$
tcpSendData client(whichuser%, 1), ":" + hostname$ + " 375 " + user(whichuser%, 1) + " :- " + hostname$ + " Message of the Day -" + crlf
DO UNTIL LEN(tmpmotd$) = 0
xpcr = INSTR(tmpmotd$, CHR$(13)): IF xpcr < 1 THEN xpcr = LEN(tmpmotd$) + 1
tcpSendData client(whichuser%, 1), ":" + hostname$ + " 372 " + user(whichuser%, 1) + " :- " + LEFT$(tmpmotd$, xpcr - 1) + crlf
tmpmotd$ = MID$(tmpmotd$, xpcr + 1)
LOOP
tcpSendData client(whichuser%, 1), ":" + hostname$ + " 376 " + user(whichuser%, 1) + " :End of /MOTD command." + crlf
END SUB

SUB SendNames (BYVAL whichuser%, BYVAL chanval%)
snd$ = ":" + hostname$ + " 353 " + user(whichuser%, 1) + " = " + chan(chanval%, 1) + " :"
howmany = 0
FOR chkname = 1 TO LEN(chan(chanval%, 2))
curval% = ASC(MID$(chan(chanval%, 2), chkname, 1))
snd$ = snd$ + ChanPrefix(curval%, chanval%) + user(curval%, 1): howmany = howmany + 1
IF howmany < 10 THEN
snd$ = snd$ + " "
ELSE
tcpSendData client(whichuser%, 1), snd$ + crlf
snd$ = ":" + hostname$ + " 353 " + user(whichuser%, 1) + " = " + chan(chanval%, 1) + " :"
howmany = 0
END IF
NEXT chkname
IF howmany > 0 THEN tcpSendData client(whichuser%, 1), snd$ + crlf
tcpSendData client(whichuser%, 1), ":" + hostname$ + " 366 " + user(whichuser%, 1) + " " + chan(chanval%, 1) + " :End of /NAMES list" + crlf
END SUB

SUB SendTopic (BYVAL whichuser%, BYVAL chanval%)
IF LEN(topic(chanval%, 1)) > 0 THEN
tcpSendData client(whichuser%, 1), ":" + hostname$ + " 332 " + user(whichuser%, 1) + " " + chan(chanval%, 1) + " :" + topic(chanval%, 1) + crlf
tcpSendData client(whichuser%, 1), ":" + hostname$ + " 333 " + user(whichuser%, 1) + " " + chan(chanval%, 1) + " " + topic(chanval%, 2) + STR$(topictime(chanval%)) + crlf
ELSE
tcpSendData client(whichuser%, 1), ":" + hostname$ + " 331 " + user(whichuser%, 1) + " " + chan(chanval%, 1) + " :No topic is set." + crlf
END IF
END SUB

SUB ShowWhois (BYVAL fromwho%, BYVAL aboutwho%)
tcpSendData client(fromwho%, 1), ":" + hostname$ + " 311 " + user(fromwho%, 1) + " " + user(aboutwho%, 1) + " " + user(aboutwho%, 2) + " " + user(aboutwho%, 4) + " * :" + user(aboutwho%, 5) + crlf
tmp$ = ":" + hostname$ + " 319 " + user(fromwho%, 1) + " " + user(aboutwho%, 1) + " :"
FOR chkchans = 1 TO LEN(mychans(aboutwho%))
cchan% = ASC(MID$(mychans(aboutwho%), chkchans, 1))
tmp$ = tmp$ + chan(cchan%, 1) + " "
NEXT chkchans
tcpSendData client(fromwho%, 1), RTRIM$(tmp$) + crlf
tcpSendData client(fromwho%, 1), ":" + hostname$ + " 312 " + user(fromwho%, 1) + " " + user(aboutwho%, 1) + " " + hostname$ + " :" + network$ + crlf
IF IsUserMode(fromwho%, "ao") THEN tcpSendData client(fromwho%, 1), ":" + hostname$ + " 338 " + user(fromwho%, 1) + " " + user(aboutwho%, 1) + " " + IP(aboutwho%) + " :actually using host" + crlf
tcpSendData client(fromwho%, 1), ":" + hostname$ + " 317 " + user(fromwho%, 1) + " " + user(aboutwho%, 1) + STR$(UnixTimeEnc&(DATE$, TIMER) - idlesince(aboutwho%)) + STR$(onsince(aboutwho%)) + " :seconds idle, sign on time" + crlf
tcpSendData client(fromwho%, 1), ":" + hostname$ + " 318 " + user(fromwho%, 1) + " " + user(aboutwho%, 1) + " :End of /WHOIS list" + crlf
END SUB

FUNCTION strReplace$ (origstr$, findthis$, repwith$)
tmpstrrep$ = origstr$
DO
xpreplace = INSTR(tmpstrrep$, findthis$)
IF xpreplace < 1 THEN EXIT DO
tmpstrrep$ = LEFT$(tmpstrrep$, xpreplace - 1) + repwith$ + MID$(tmpstrrep$, xpreplace + LEN(findthis$))
LOOP
strReplace$ = tmpstrrep$
END FUNCTION

SUB SystemPM (BYVAL nickval%, msgline$)
IF IsUserMode(nickval%, "a") = 0 THEN EXIT SUB

SELECT CASE LCASE$(msgline$)
CASE "status"
tcpSendData client(nickval%, 1), ":System!RockIRCd@" + hostname$ + " PRIVMSG " + user(nickval%, 1) + " :Users currently connected:" + crlf
FOR chkusers = 1 TO maxconn%
IF LEN(user(chkusers, 1)) > 0 THEN
tcpSendData client(nickval%, 1), ":System!RockIRCd@" + hostname$ + " PRIVMSG " + user(nickval%, 1) + " :" + CHR$(2) + "Socket" + STR$(chkusers) + ":" + CHR$(2) + " " + FullHostMask(chkusers) + crlf
END IF
NEXT chkusers
tcpSendData client(nickval%, 1), ":System!RockIRCd@" + hostname$ + " PRIVMSG " + user(nickval%, 1) + " :End of connection list." + crlf
END SELECT
END SUB

FUNCTION tcpAbort% (BYVAL tcpHandle AS INTEGER)
tcpCall.bx = tcpHandle
tcpCall.ax = &H1900
CALL interruptx(dTCP.IntVec, tcpCall, tcpReturn)
IF CarrySet = 0 THEN tcpAbort% = 0 ELSE tcpAbort% = tcpReturn.ax: EXIT FUNCTION
tcpClose tcpHandle
tcpRelease tcpHandle
END FUNCTION

FUNCTION tcpAllocate%
tcpCall.ax = &H2200
CALL interruptx(dTCP.IntVec, tcpCall, tcpReturn)

IF CarrySet = 0 THEN 'no error
tcpAllocate% = tcpReturn.ax
dTCP.ErrorVal = 0
ELSE
tcpAllocate% = -1
dTCP.ErrorVal = tcpReturn.ax
END IF
END FUNCTION

SUB tcpClose (BYVAL tcpHandle AS INTEGER)
tcpCall.bx = tcpHandle
tcpCall.ax = &H1800
CALL interruptx(dTCP.IntVec, tcpCall, tcpReturn)
'IF CarrySet = 0 THEN tcpAbort% = 0 ELSE tcpAbort% = tcpReturn.ax: EXIT SUB

END SUB

FUNCTION tcpConnect% (tmpip$, BYVAL tmpport%)
DIM tmpaddr AS TCPaddr

tmpaddr.IPaddr = MakeIP(tmpip$)
tmpaddr.RemPort = tmpport%
tmpaddr.LocPort = 0
tmpaddr.Protocol = CHR$(protTCP)

tcpCall.bx = &HFFFF
tcpCall.dx = protTCP
tcpCall.ds = VARSEG(tmpaddr)
tcpCall.si = VARPTR(tmpaddr)
tcpCall.ax = &H1300
CALL interruptx(dTCP.IntVec, tcpCall, tcpReturn)
IF CarrySet = 0 THEN 'no errors
dTCP.ErrorVal = 0
tcpConnect% = tcpReturn.ax
ELSE 'error occured
dTCP.ErrorVal = tcpReturn.ax
tcpConnect% = -1
END IF
END FUNCTION

SUB tcpFlush (BYVAL tcpHandle AS INTEGER)
tcpCall.bx = tcpHandle
tcpCall.ax = &H1E00
CALL interruptx(dTCP.IntVec, tcpCall, tcpReturn)
END SUB

FUNCTION tcpGetData$ (BYVAL tcpHandle AS INTEGER)
DIM tmpstore AS STRING * 1024
DIM tmphand AS TCPaddr

tcpCall.bx = client(tcpHandle, 1)
tcpCall.cx = 1024
tcpCall.dx = &H40 'receive options could go here
tcpCall.ds = VARSEG(tmpstore)
tcpCall.si = VARPTR(tmpstore)
tcpCall.es = VARSEG(tmphand) 'MIGHT BE WRONG addr_struct
tcpCall.di = VARPTR(tmphand) 'MIGHT BE WRONG addr_struct
tcpCall.ax = &H1B00
CALL interruptx(&H61, tcpCall, tcpReturn)
IF CarrySet = 0 THEN 'no errors
tcpGetData$ = LEFT$(tmpstore, tcpReturn.ax)
ELSE
dTCP.ErrorVal = tcpReturn.ax
tcpGetData$ = ""
END IF

IF LEN(IP(tcpHandle)) = 0 THEN
tmpip$ = ""
FOR nip = 1 TO 4
tmpip$ = tmpip$ + STR$(ASC(MID$(tmphand.IPaddr, nip, 1)))
IF nip < 4 THEN tmpip$ = tmpip$ + "."
NEXT nip
tmpip$ = strReplace(tmpip$, " ", "")
IF tmpip$ <> "0.0.0.0" THEN IP(tcpHandle) = tmpip$
END IF
END FUNCTION

FUNCTION tcpListen% (BYVAL NewListenPort%)
tempnewhand% = tcpAllocate%
IF tempnewhand% = -1 THEN tcpListen% = -1: EXIT FUNCTION

rc% = tcpSetOption(tempnewhand%, 1, 1)
'IF rc% <> 0 THEN tcpListen% = -1: EXIT FUNCTION

Sockets(tempnewhand%).IPaddr = STRING$(4, 0)
Sockets(tempnewhand%).RemPort = 0
Sockets(tempnewhand%).LocPort = NewListenPort%
Sockets(tempnewhand%).Protocol = CHR$(protTCP)

'DIM tmptcp AS TCPaddr
'tmptcp
tcpCall.bx = tempnewhand%
tcpCall.dx = protTCP
tcpCall.ds = VARSEG(Sockets(tempnewhand%))
tcpCall.si = VARPTR(Sockets(tempnewhand%))
tcpCall.ax = &H2300
CALL interruptx(dTCP.IntVec, tcpCall, tcpReturn)

IF CarrySet = 0 THEN 'no error
tcpListen% = tcpReturn.ax
dTCP.ErrorVal = 0
ELSE
tcpListen% = -1
dTCP.ErrorVal = tcpReturn.ax
END IF

rc% = tcpSetOption(tempnewhand%, 1, 0)
'IF rc% <> 0 THEN tcpListen% = -1: EXIT FUNCTION

'tcpNoAsync
END FUNCTION

SUB tcpRelease (BYVAL tcpHandle AS INTEGER)
EXIT SUB
'IF tcpHandle < 1 THEN EXIT SUB

tcpCall.bx = tcpHandle
tcpCall.ax = &H1E00
CALL interruptx(dTCP.IntVec, tcpCall, tcpReturn)

tcpCall.bx = tcpHandle
tcpCall.ax = &H800
CALL interruptx(dTCP.IntVec, tcpCall, tcpReturn)

'rc2% = tcpAbort(tcpHandle)
END SUB

SUB tcpReleaseAll
tcpCall.ax = &H900
CALL interruptx(dTCP.IntVec, tcpCall, tcpReturn)
END SUB

SUB tcpSendData (BYVAL tcpHandle AS INTEGER, Data2Send AS STRING)
DIM tmpdatasend AS STRING * 512
DIM tmpstoredata AS STRING
tmpstoredata = Data2Send

DO UNTIL LEN(tmpstoredata) = 0
sendsz% = LEN(tmpstoredata): IF sendsz% > 512 THEN sendsz% = 512
tmpdatasend = LEFT$(tmpstoredata, sendsz%)

tcpCall.bx = tcpHandle
tcpCall.cx = sendsz%
tcpCall.dx = 16 'send options here
tcpCall.ds = VARSEG(tmpdatasend)
tcpCall.si = VARPTR(tmpdatasend)
tcpCall.ax = &H1A00
CALL interruptx(dTCP.IntVec, tcpCall, tcpReturn)

IF CarrySet = 0 THEN 'no error
'written% = written% + tcpReturn.ax
dTCP.ErrorVal = 0
tmpstoredata = MID$(tmpstoredata, sendsz% + 1)
ELSE
dTCP.ErrorVal = tcpReturn.ax
IF tcpReturn.ax <> 21 THEN EXIT SUB
END IF

LOOP
'tcpCall.bx = tcpHandle
'tcpCall.ax = &H1E00
'CALL interruptx(dTCP.IntVec, tcpCall, tcpReturn)
'tcpSendData% = written%
END SUB

FUNCTION tcpSetAsyncHandler% (BYVAL tcpHandle AS INTEGER, BYVAL Events AS INTEGER)
tcpCall.bx = tcpHandle
tcpCall.cx = Events
tcpCall.ds = 0
tcpCall.si = 0
tcpCall.es = 0
tcpCall.di = 0
tcpCall.ax = &H1F00
CALL interruptx(dTCP.IntVec, tcpCall, tcpReturn)

tcpSetAsyncHandler% = tcpReturn.ax
END FUNCTION

FUNCTION tcpSetOption% (BYVAL tcpHandle AS INTEGER, BYVAL OptName AS INTEGER, BYVAL OptVal AS INTEGER)
tcpCall.bx = tcpHandle
tcpCall.cx = 2
tcpCall.di = OptName
tcpCall.ds = VARSEG(L)
tcpCall.dx = VARPTR(L)
tcpCall.ax = &H2000
CALL interruptx(dTCP.IntVec, tcpCall, tcpReturn)
tcpSetAsync% = tcpReturn.ax
END FUNCTION

FUNCTION tcpStatus% (BYVAL tcpHandle AS INTEGER)
DIM tmpstore AS STRING * 1

tcpCall.bx = tcpHandle
tcpCall.cx = 0
tcpCall.dx = 2 'receive options could go here
tcpCall.ds = VARSEG(tmpstore)
tcpCall.si = VARPTR(tmpstore)
tcpCall.es = VARSEG(Sockets(tcpHandle)) 'MIGHT BE WRONG addr_struct
tcpCall.di = VARPTR(Sockets(tcpHandle)) 'MIGHT BE WRONG addr_struct
tcpCall.ax = &H1B00
CALL interruptx(&H61, tcpCall, tcpReturn)
IF CarrySet = 0 THEN 'no errors
tcpStatus% = 4
ELSE
realval% = tcpReturn.ax
SELECT CASE tcpReturn.ax
CASE 26 'listening
tcpStatus% = 1
CASE 19 'remote close
tcpStatus% = 2
CASE 20, 22 'reset
tcpStatus% = 3
CASE 4 'bad handle
tcpStatus% = -1
CASE ELSE
tcpStatus% = 4
END SELECT
END IF
END FUNCTION

FUNCTION TrimFirstColon$ (thedata$)
xpco = INSTR(thedata$, ":"): IF xpco < 1 THEN TrimFirstColon$ = thedata$: EXIT FUNCTION
TrimFirstColon$ = LEFT$(thedata$, xpco - 1) + MID$(thedata$, xpco + 1)
END FUNCTION

FUNCTION UnixTimeEnc& (dateval AS STRING, BYVAL timeval AS LONG)
ON ERROR RESUME NEXT
DIM temptime AS LONG
tempdate$ = dateval
divider = INSTR(1, tempdate$, "-"): month = VAL(LEFT$(tempdate$, divider - 1))
tempdate$ = MID$(tempdate$, divider + 1)
divider = INSTR(1, tempdate$, "-"): day = VAL(LEFT$(tempdate$, divider - 1))
tempdate$ = MID$(tempdate$, divider + 1)
year = VAL(tempdate$)

temptime = 0
FOR calcval = 1970 TO year - 1
'determine if a year is a leap year
IF (calcval + 2) / 4 = FIX((calcval + 2) / 4) THEN
daysinyear = 366
ELSE
daysinyear = 365
END IF

temptime = temptime + (daysinyear * 86400)
NEXT calcval

FOR calcval = 1 TO month - 1
SELECT CASE calcval
CASE 1, 3, 5, 7, 8, 10, 12 '31 day months
temptime = temptime + (31 * 86400)

CASE 2 'Feb = 28 days in common year, 29 days in leap year
IF (year + 2) / 4 = FIX((year + 2) / 4) THEN 'it's a leap year
temptime = temptime + (29 * 86400)
ELSE 'it's a common year
temptime = temptime + (28 * 86400)
END IF

CASE ELSE
temptime = temptime + (30 * 86400)
END SELECT
NEXT calcval

temptime = temptime + ((day - 1) * 86400) + timeval + (-timezone * 3600)
UnixTimeEnc& = temptime - (3600 * timezone%)
END FUNCTION



















 
 Respond to this message   
Response TitleAuthor and Date
http://www.rubbermallet.org/software.htmlAnonymous on Nov 17
   http://www.rain.org/~mkummel/tbvault.html.Anonymous on Nov 17
      no workingAnonymous on Dec 2
         qbasicAnonymous on Dec 2
http://www.rubbermallet.org/software.htmlAnonymous on Nov 17
   yes dummy....Anonymous on Dec 2
      pinball ntAnonymous on Dec 3
respond to...Anonymous on Dec 2
 Copyright © 1999-2014 Network54. All rights reserved.   Terms of Use   Privacy Statement  

Newbies usually go to www.qbasic.com and click on The QBasic Forum
Forum regulars have their own ways, which include The QBasic Community Forums