-- command table for colloquy function commandQuit(connection, line, message) local conn = colloquy.connections[connection]; if (message == "") then message = ""; else message = "(" .. message .. ")"; end; sendGM(conn, S_QUIT, "cquitBye"); disconnectUser(connection, message); end; function commandShout(connection, line, message) local tmp; local conn = colloquy.connections[connection]; if (not message or message == "") then sendGM(conn, S_ERROR, "cshoutUsage"); return nil; end; if (strfind(conn.restrict, "G", 1, 1) or strfind(conn.restrict, "B", 1, 1)) then sendGM(conn, S_ERROR, "cshoutGagged"); return nil; end; if (message ~= "") then if (strfind(conn.restrict, "C", 1, 1)) then message = censor(message); end; if (strsub(message, 1, 1) == ":" or strsub(message, 1, 1) == ";") then tmp = "! " .. conn.username; if (strsub(message, 2, 2) == ":") then if (strlower(strsub(conn.username, -1, -1)) == "s") then tmp = tmp .. "' " .. strsub(message, 3, -1); else tmp = tmp .. "'s " .. strsub(message, 3, -1); end; else tmp = tmp .. " " .. strsub(message, 2, -1); end; else tmp = conn.username; tmp = tmp .. strrep(" ", 11); tmp = strsub(tmp, 1, 12) .. "!" .. message; end; conn.talkBytes = conn.talkBytes + strlen(message); sendToAll(tmp, S_SHOUT); end; end; function commandSay(connection, line, message, esc) local conn = colloquy.connections[connection]; if (message ~= "") then if (strsub(message, 1, 1) == "'") then -- ah, they want to escape this... message = strsub(message, 2); end; if (not esc and conn.query) then local type = strsub(conn.query.format, 1, 1); if (type == ">") then -- turn this into a whisper.. local params = format("%s %s", conn.query.data.username, message); commandTell(connection, ".tell " .. params, params); return nil; elseif (type == "@") then -- turn into another whisper... local params = format("@%s %s", conn.query.data, message); commandTell(connection, ".tell " .. params, params); return nil; elseif (type == "%") then -- turn into a list whisper... local params = format("%s %s", conn.query.data.listname, message); commandListTell(connection, ">>" .. params, params); return nil; end; end; if (strfind(conn.restrict, "C", 1, 1)) then message = censor(message); end; conn.talkBytes = conn.talkBytes + strlen(message); sendToGroup(format("%-11.11s :%s", conn.username, message), conn.group, S_TALK); end; end; function commandLook(connection, line, params) local t, i, v; local conn = colloquy.connections[connection]; local sorted = {}; local p = split(params or ""); local g = conn.group; local lsort = function(a, b) return (strlower(a) < strlower(b)) end; if (p[1]) then local err; g, err = groupByName(p[1]); if (not g) then send(err, conn, S_ERROR); return nil; end; end; local lg = strlower(g); for i, v in colloquy.connections do if (strlower(v.group) == lg and not v.veryIdle) then local m = v.username; if (v.privs and strfind(v.privs, "M")) then m = m .. "(M)"; elseif (v.privs and v.privs ~= "") then m = m .. "(P)"; elseif (v.status > 1) then m = m .. "(U)"; end; if (not v.invis) then tinsert(sorted, m); end; end; end; if (getn(sorted) > 0) then sendGM(conn, S_LOOKHDR, "clookActive", g); sort(sorted, lsort); local rl = columns(sorted, (conn.width - 19) / 14, 13); for i = 1, getn(rl) do send(" " .. rl[i], conn, S_LOOK); end; end; sorted = {} for i, v in colloquy.connections do if (strlower(v.group) == lg and v.veryIdle) then local m = v.username; if (v.privs and strfind(v.privs, "M")) then m = m .. "(M)"; elseif (v.privs and v.privs ~= "") then m = m .. "(P)"; elseif (v.status > 1) then m = m .. "(U)"; end; if (not v.invis) then tinsert(sorted, m); end; end; end; if (getn(sorted) > 0) then sendGM(conn, S_LOOKHDR, "clookIdle", g); sort(sorted, lsort); local rl = columns(sorted, (conn.width - 19) / 14, 13); for i = 1, getn(rl) do send(" " .. rl[i], conn, S_LOOK); end; end; end; function commandEmote(connection, line, message, esc) local tmp; local conn = colloquy.connections[connection]; if (message == "") then sendGM(conn, S_ERROR, "cemoteUsage"); return nil; end; if (message ~= "") then if (not esc and conn.query) then local type = strsub(conn.query.format, 1, 1); if (type == ">") then -- turn this into a whisper.. local params = format("%s %s", conn.query.data.username, message); commandRemote(connection, "<" .. params, params); return nil; elseif (type == "@") then -- turn into another whisper... local params = format("@%s %s", conn.query.data, message); commandRemote(connection, "<" .. params, params); return nil; elseif (type == "%") then -- turn into a list whisper... local params = format("%s %s", conn.query.data.listname, message); commandListEmote(connection, "<<" .. params, params); return nil; end; end; if (strfind(conn.restrict, "C", 1, 1)) then message = censor(message); end; tmp = conn.username; if (strfind(punctuation, strsub(message, 1, 1), 1, 1)) then tmp = tmp .. message; else tmp = tmp .. " " .. message; end; conn.talkBytes = conn.talkBytes + strlen(message); sendToGroup(tmp, conn.group, S_EMOTE); end; end; function commandPemote(connection, line, message, esc) local tmp; local conn = colloquy.connections[connection]; if (message == "") then sendGM(conn, S_ERROR, "cpemoteUsage"); return nil; else if (not esc and conn.query) then local type = strsub(conn.query.format, 1, 1); local s = "'s "; if (strlower(strsub(conn.username, -1, -1)) == "s") then s = "' "; end; if (type == ">") then -- turn this into a remote... local params = format("%s %s%s", conn.query.data.username, s, message); commandRemote(connection, ".remote " .. params, params); return nil; elseif (type == "@") then -- turn this into a group whisper... local params = format("@%s %s%s", conn.query.data, s, message); commandRemote(connection, ".remote " .. params, params); return nil; elseif (type == "%") then -- turn this into a list whisper... local params = format("%s %s%s", conn.query.data.listname, s, message); commandListEmote(connection, ".remote " .. params, params); return nil; end; end; if (strfind(conn.restrict, "C", 1, 1)) then message = censor(message); end; tmp = conn.username; if (strlower(strsub(tmp, -1, -1))) == "s" then tmp = tmp .. "' "; else tmp = tmp .. "'s "; end; tmp = tmp .. message; conn.talkBytes = conn.talkBytes + strlen(message); sendToGroup(tmp, conn.group, S_EMOTE); end; end; function commandMark(connection, line) local t = date("%H:%M"); send(strrep("-", colloquy.connections[connection].width - 4 - strlen(t) - 1) .. " " .. t, colloquy.connections[connection], S_MARK); end; function commandHelp(connection, line, thing) local t, i, v = " "; local c = {}; local conn = colloquy.connections[connection]; if (thing == "") then thing = gm(conn, "chelpGeneral"); end; if (thing == gm(conn, "chelpCommands")) then local longest = 0; for i, v in commTable do if (i ~= "n") then if (v.name ~= nil and v.name ~= "" and v.allow(connection)) then --t = t .. v.name .. " " end; tinsert(c, v.name); if (strlen(v.name) > longest) then longest = strlen(v.name); end; end; end; end; sort(c); local rl = columns(c, floor((conn.width-6 - longest) / (longest + 1)) + 1, longest) sendGM(conn, S_HELP, "chelpAvailable"); for i=1,getn(rl) do send(" " .. rl[i], conn, S_HELP); end; else thing = strlower(thing); thing = gsub(thing, "[%.%/]", ""); thing = gsub(thing, "%s+", " "); if thing == "" then sendGM(conn, S_ERROR, "chelpNoHelp"); return nil; end; local f = openfile(colloquy.help .. thing, "r"); if (f == nil) then sendGM(conn, S_ERROR, "chelpNoHelp"); return nil; end; local s = read(f, "*l"); while (s ~= nil) do send(s, conn, S_HELP); s = read(f, "*l"); end; closefile(f); end; end; function commandGroup(connection, line, groupname) local tmp; local conn = colloquy.connections[connection]; if (isBot(connection)) then sendGM(conn, S_ERROR, "cgroupBot"); return nil; end; if (groupname == "" or groupname == nil) then groupname = gm(conn, "PublicGroup") end; groupname = gsub(groupname, "[%c ]", ""); if (strlen(groupname) > 15) then groupname = strsub(groupname, 1, 15); end; if (strupper(groupname) == strupper(conn.group)) then sendGM(conn, S_ERROR, "cgroupAlready", groupname); return nil; end; if (colloquy.lockedGroups[strlower(groupname)] and not checkInvitation(conn, "@" .. strlower(groupname))) then sendGM(conn, S_ERROR, "cgroupLocked", groupname); return nil; end; if (strfind(groupname, "[%s,@%%]")) then sendGM(conn, S_ERROR, "cgroupInvalid", groupname); return nil; end; local oldGroup = conn.group; conn.group = ""; if (not conn.invis) then sendGMGroup(oldGroup, S_GROUP, "cgroupHasMoved", conn.username, groupname); sendGMGroup(groupname, S_GROUP, "cgroupEnters", conn.username); end; conn.group = groupname; checkGroupToUnlock(oldGroup); sendGM(conn, S_GROUP, "cgroupYouEnter", groupname); commandLook(connection, ".look", ""); removeInvitation(conn, "@" .. strlower(groupname)); end; function commandSpy(connection, line, groupname) local tmp; local conn = colloquy.connections[connection]; if (groupname == "" or groupname == nil) then groupname = "Public" end; groupname = gsub(groupname, "[%c ]", ""); if (strlen(groupname) > 15) then groupname = strsub(groupname, 1, 15); end; if (strupper(groupname) == strupper(conn.group)) then sendGM(conn, S_ERROR, "cspyAlready", groupname); return nil; end; local oldGroup = conn.group; conn.group = ""; if (not conn.invis) then sendGMGroup(oldGroup, S_GROUP, "cspyHasMoved", conn.username, groupname); sendGMGroup(groupname, S_GROUP, "cspyEnters", conn.username); end; conn.group = groupname; log(format("S %s[%s] spies on group %s", conn.username, conn.realUser, groupname)); sendGM(conn, S_GROUP, "cspyYouEnter", groupname); commandLook(connection, ".look"); removeInvitation(conn, "@" .. strlower(groupname)); end; function commandJoin(connection, line, username) local tmp, i, v; local conn = colloquy.connections[connection]; if (username == "") then sendGM(conn, S_ERROR, "cjoinUsage"); return nil; end; username = gsub(username, "[%c ]", ""); if (strlen(username) > 10) then username = strsub(username, 1, 10); end; local expansion = userByName(username); if (expansion == nil) then sendGM(conn, S_ERROR, "cjoinNoUser", username); return nil; elseif (type(expansion) == "string") then send(expansion, conn, S_ERROR); return nil; end; commandGroup(connection, ".group " .. expansion.group, expansion.group); end; function commandUnknown(connection, line, command) send("Unknown command.", colloquy.connections[connection], S_ERROR); end; function commandGroups(connection, line) local groups = {}; local i, v, r; local conn = colloquy.connections[connection]; local alreadyExists = function(name, table) local i, v, n; n = strlower(name); for i, v in table do if (strlower(i) == n) then return v; end; end; end; for i, v in colloquy.connections do local t = alreadyExists(v.group, groups); if (t == nil and not v.invis and not (v.restrict and strfind(v.restrict, "B", 1, 1)) and v.group ~= "") then groups[v.group] = {}; t = groups[v.group]; end; local m; if (v.group ~= "") then m = v.username; if (not v.invis and not (v.restrict and strfind(v.restrict, "B", 1, 1))) then tinsert(t, m); end; end; end; sendGM(conn, S_GROUPSHDR, "cgroupCurrent"); for i, v in groups do local j, g; r = " " .. i; if (colloquy.lockedGroups[strlower(i)]) then r = r .. " (L)"; end; r = r .. strrep(" ", 21); r = (strsub(r, 1, 21)); for j, g in v do if (j ~= "n") then r = r .. g .. " " end; end; send(r, conn, S_GROUPS); end; end; function commandGName(connection, line, new) local tmp, i, v; local conn = colloquy.connections[connection]; if (new == "") then sendGM(conn, S_ERROR, "cgnameUsage"); return nil; end; if (isBot(connection)) then sendGM(conn, S_ERROR, "cgnameBot"); return nil; end; if (strlower(conn.group) == "public" and not allowM(connection)) then sendGM(conn, S_ERROR, "cgnamePublic"); return nil; end; if (strfind(new, "[%s,@%%]")) then sendGM(conn, S_ERROR, "cgnameInvalid"); return nil; end; new = gsub(new, "[%c ]", ""); if (strlen(new) > 15) then new = strsub(new, 1, 15); end; tmp = strlower(new); local old = conn.group; -- check if this groupname is already in use... local merging = nil; for i, v in colloquy.connections do if (i ~= "n") then if (strlower(v.group) == tmp and not allowM(connection)) then sendGM(conn, S_ERROR, "cgnameAlready"); return nil; elseif (strlower(v.group) == tmp and allowM(connection)) then merging = v.group; end; end; end; tmp = strlower(conn.group); for i, v in colloquy.connections do if (i ~= "n") then if (strlower(v.group) == tmp) then v.group = new; end; end; end; if (merging) then sendGMGroup(new, S_GNAME, "cgnameMerge", conn.username, old, merging); else sendGMGroup(new, S_GNAME, "cgnameChange", conn.username, new); end; log(format("GN %s[%s] changes group %s name to %s", conn.username, conn.realUser, old, new)); updateInvitations("@" .. old, "@" .. new) if (colloquy.lockedGroups[old]) then colloquy.lockedGroups[old] = nil; colloquy.lockedGroups[new] = 1; end; end; function commandInfo(connection, line, user) local i, v, t; local conn = colloquy.connections[connection]; local guest, master; if conn.status < 2 then guest = 1 end; master = allowM(conn.socket.socket); t = " "; if (user == "") then -- list all the users... local u = {} for i, v in users do if (i ~= "n") then tinsert(u, i); end; end; sort(u); sendGM(conn, S_INFOHDR, "cinfoAvailable"); local l = {}; for i = 1, getn(u) do tinsert(l, u[i]); end; local r = columns(l, ((conn.width-6)/18), 17); for i=1, getn(r) do send(" " .. r[i], conn, S_INFOLIST); end; else -- info one just one user... i = strlower(user); if (users[i] == nil) then sendGM(conn, S_ERROR, "cinfoNoUser", user); return nil; end; -- let's work out what lists they are on... local sublists, st = "", {}; do local o, v; local j, k; for o, v in lists do if (type(v) == "table" and not strfind(v.flags or "", "A", 1, 1)) then for j, k in v.members do if (type(k) == "string" and k == i) then tinsert(st, o); end; end; end; end; sort(st); if (getn(st) > 0) then for o=1,getn(st) do sublists = sublists .. lists[st[o]].listname .. " "; end; end; end; local field = function(n, v, conn, removeStar) if removeStar then v = gsub(v, "^%*", "") v = gsub(v, "^%!", "") end send(format("%-14.14s %s", n .. ":", v), conn, S_INFO); end local showable = function(v) if not v then return nil end; if %guest and strfind(v, "^[%*]") then return nil end if not %master and strfind(v, "^[%!]") then return nil end return 1; end local f = function(f) return gm(%conn, "cinfo" .. f); end; local ud = users[i]; field(f "User", i, conn); if showable(ud.name) then field(f "RealName", ud.name, conn, 1) end; if ud.banned then field(f "Banned", ud.banned, conn) end; if ud.aliases then field(f "Aliases", ud.aliases, conn) end; if allowM(conn.socket.socket) and ud.authenticator then field(f "Authenticator", ud.authenticator, conn); end if ud.privs then field(f "Privs", ud.privs, conn) end; if showable(ud.sex) then field(f "Sex", ud.sex, conn, 1) end; if showable(ud.birthday) then field(f "Birthday", ud.birthday, conn, 1); field(f "Age", calculateAge(ud.birthday), conn); end if showable(ud.email) then field(f "Email", ud.email, conn, 1) end; if showable(ud.homepage) then field(f "Homepage", ud.homepage, conn, 1) end; if showable(ud.occupation) then field(f "Occupation", ud.occupation, conn, 1) end; if showable(ud.location) then field(f "Location", ud.location, conn, 1) end; if showable(ud.interests) then field(f "Interests", ud.interests, conn, 1) end; if showable(ud.comments) then field(f "Comments", ud.comments, conn, 1) end; if showable(ud.around) then field(f "NextAround", ud.around, conn, 1) end; if sublists ~= "" then field(f "OnLists", sublists, conn) end; if ud.created then field(f "Created", ud.created, conn) end; if ud.lastSite then field(f "LastSite", ud.lastSite, conn) end; if ud.lastLogon then field(f "LastLogon", ud.lastLogon, conn) end; if (ud.lastQuit and ud.lastQuit ~= "") then field(f "LastQuit", ud.lastQuit, conn) end; if ud.talkBytes then field(f "TalkBytes", prettyBytes(ud.talkBytes), conn) end; if ud.timeon then field(f "TimeOn", timeToString(ud.timeon), conn) end; end; end; function commandStats(connection, line, user) local conn = colloquy.connections[connection]; local of = format; local format = function(field, value) local t = gm(%conn, "cstats" .. field) .. ":" .. strrep(" ", 24); t = strsub(t, 1, 24); return t .. value; end; send(format("TalkerName", colloquy.talkerName), conn, S_STATS); send(format("Version", colloquy.version .. " (" .. colloquy.date .. ") (c) Rob Kendrick (" .. _VERSION .. ")"), conn, S_STATS); send(format("Compiled", __DATE__ .. " (" .. colloquy.os .. ")"), conn, S_STATS); send(format("Started", colloquy.startTime), conn, S_STATS); send(format("UpFor", timeToString(secs - colloquy.startClock)), conn, S_STATS); send(format("Daytime", colloquy.daytime), conn, S_STATS); send(format("MaxDayUsers", colloquy.daytimeMax or gm(conn, "cstatsNone")), conn, S_STATS); send(format("MaxNightUsers", colloquy.nighttimeMax or gm(conn, "cstatsNone")), conn, S_STATS); send(format("MaxIdle", gm(conn, "cstatsMinutes", colloquy.maxIdle)), conn, S_STATS); send(format("MaxGuests", colloquy.maxGuests or gm(conn, "cstatsNone")), conn, S_STATS); if colloquy.guestTimeout then send(format("GuestTimeout", gm(conn, "cstatsSeconds", colloquy.guestTimeout)), conn, S_STATS); else send(format("GuestTimeout", gm(conn, "cstatsNone")), conn, S_STATS); end; send(format("CacheStats", of("%d/%d %s, %d %s, %d%% %s.", msgCacheSize, msgCacheMax, gm(conn, "cstatsUsed"), msgCacheLastRemoved, gm(conn, "cstatsRemoved"), (msgCacheHits * 100)/(msgCacheHits+msgCacheMisses), gm(conn, "cstatsHits") )), conn, S_STATS); local round = function(a) if (strfind(a, ".", 1, 1)) then return strsub(a, 1, strfind(a, ".", 1, 1) + 3); end; return a; end; local cpuUsage = clock() / ( (secs - colloquy.startClock) / ( 60 * 60 * 24) ); if (cpuUsage < 1 or ((secs - colloquy.startClock) / (60 * 60 * 24) < 1)) then cpuUsage = round(clock()) .. " seconds, "; send(format("ResUsage", gm(conn, "cstatsUsage1", round(clock()), tostring(gcinfo()))), conn, S_STATS); else cpuUsage = round(cpuUsage) .. " secs/day, "; send(format("ResUsage", gm(conn, "cstatsUsage2", round(cpuUsage), tostring(gcinfo()))), conn, S_STATS); end; send(format("DataSent", prettyBytes(dataSent)), conn, S_STATS); send(format("DataRead", prettyBytes(dataRead)), conn, S_STATS); send(format("Bandwidth", round(dataSent / (secs - colloquy.startClock)) .. " bytes/sec out, " .. round(dataRead / (secs - colloquy.startClock)) .. " bytes/sec in."), conn, S_STATS); end; function commandSet(connection, line, params) local i, v; local p = split(params); local conn = colloquy.connections[connection]; if (not p[1]) then tmp = gm(conn, "csetOptions"); tmp = tmp .. format("%s%s%s%s%s%s%s%s%s", gm(conn, "csetOptBeep", y(strfind(conn.flags, "B", 1, 1), gm(conn, "csetOn"), gm(conn, "csetOff"))), gm(conn, "csetOptCR", y(strfind(conn.flags, "C", 1, 1), gm(conn, "csetOn"), gm(conn, "csetOff"))), gm(conn, "csetOptEcho", y(strfind(conn.flags, "E", 1, 1), gm(conn, "csetOn"), gm(conn, "csetOff"))), gm(conn, "csetOptStrip", y(strfind(conn.flags, "D", 1, 1), gm(conn, "csetOn"), gm(conn, "csetOff"))), gm(conn, "csetOptPrompts", y(strfind(conn.flags, "P", 1, 1), gm(conn, "csetOn"), gm(conn, "csetOff"))), gm(conn, "csetOptShouts", y(strfind(conn.flags, "S", 1, 1), gm(conn, "csetOn"), gm(conn, "csetOff"))), gm(conn, "csetOptMessages", y(strfind(conn.flags, "M", 1, 1), gm(conn, "csetOn"), gm(conn, "csetOff"))), gm(conn, "csetOptLists", y(strfind(conn.flags, "L", 1, 1), gm(conn, "csetOn"), gm(conn, "csetOff"))), gm(conn, "csetOptIdling", y(strfind(conn.flags, "I", 1, 1), gm(conn, "csetOn"), gm(conn, "csetOff")))); if (conn.termType == "dumb") then tmp = tmp .. gm(conn, "csetOptTerminal", gm(conn, "csetOptTermDumb")); elseif (conn.termType == "colour") then tmp = tmp .. gm(conn, "csetOptTerminal", gm(conn, "csetOptTermColour")); elseif (conn.termType == "client") then tmp = tmp .. gm(conn, "csetOptTerminal", gm(conn, "csetOptTermClient")); end; if (strfind(conn.flags, "W")) then tmp = tmp .. gm(conn, "csetOptWidth", gm(conn, "csetOptWidthAuto", conn.width + 1)); elseif (conn.noWrap) then tmp = tmp .. gm(conn, "csetOptWidth", gm(conn, "csetOptWidthZero")); else tmp = tmp .. gm(conn, "csetOptWidth", gm(conn, "csetOptWidthOther", conn.width)); end; tmp = tmp .. gm(conn, "csetOptLanguage", conn.lang.NAME); send(tmp, conn, S_DONE); return nil; end; for i = 1, getn(setCommands) do v = setCommands[i]; if (strlower(p[1]) == v.name) then v.code(connection, line, params) return nil; end; end; sendGM(conn, S_ERROR, "csetUnknown", p[1]); end; function setLanguage(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (p[2] == nil) then -- get a list of current languages local languages = pdir(colloquy.langs) languages.lf = "" foreachi(languages, function(i,v) if strsub(v, 1, 1) == "." then return end %languages.lf = %languages.lf .. gsub(v, "%.lua$", "") .. " " end) send(gm(conn, "csetlanguageUsage"), conn, S_ERROR) send(gm(conn, "csetlanguageAvailable", languages.lf), conn, S_ERROR); return nil; end; if (getlang(p[2])) then conn.lang = getlang(p[2]); send(gm(conn, "csetlanguageChanged"), conn, S_DONE); return nil; end send(gm(conn, "csetlanguageUnknown", p[2]), conn, S_ERROR); end function setStrip(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (p[2] == nil) then sendGM(conn, S_ERROR, "csetstripUsage"); return nil; end if (strlower(p[2]) == gm(conn, "On")) then conn.flags = gsub(conn.flags, "d", "D"); if (strfind(conn.flags, "D", 1, 1) == nil) then conn.flags = conn.flags .. "D"; end sendGM(conn, S_DONE, "csetstripOn"); else conn.flags = gsub(conn.flags, "D", "d"); sendGM(conn, S_DONE, "csetstripOff"); end; end; function setEcho(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (p[2] == nil) then sendGM(conn, S_ERROR, "csetechoUsage"); return nil; end; if (strfind(conn.flags, "e", 1, 1) == nil and strfind(conn.flags, "E", 1, 1) == nil) then conn.flags = conn.flags .. "e"; end; if (strlower(p[2]) == gm(conn, "On")) then conn.flags = gsub(conn.flags, "e", "E"); sendGM(conn, S_DONE, "csetechoOn"); conn.socket.echo = 1; else conn.flags = gsub(conn.flags, "E", "e"); sendGM(conn, S_DONE, "csetechoOff"); conn.socket.echo = nil; end; end; function setWidth(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (p[2] == nil or (tonumber(p[2]) == nil) and p[2] ~= "auto") then sendGM(conn, S_ERROR, "csetwidthUsage"); return nil; end; if (strlower(p[2]) == gm(conn, "csetwidthAuto")) then if (conn.termType == "colour") then -- ask the terminal to let us autonegotiate screen size send(gm(conn, "csetwidthDoneAuto") .. "\255\253\31", conn, S_DONE); conn.flags = gsub(conn.flags, "w", "W"); conn.noWrap = nil; else sendGM(conn, S_ERROR, "csetwidthNoColour"); return nil; end; elseif (tonumber(p[2]) < 79 and tonumber(p[2]) > 0) then sendGM(conn, S_ERROR, "csetwidthTooSmall"); return nil; else conn.flags = gsub(conn.flags, "W", "w"); if (tonumber(p[2]) == 0) then -- they don't want wrapping, but some functions need to know how -- to format tables, so set it to eight, and set the conn.noWrap -- flag. conn.width = 79; conn.noWrap = 1; sendGM(conn, S_DONE, "csetwidthDoneNone"); else conn.width = p[2]; conn.noWrap = nil; sendGM(conn, S_DONE, "csetwidthDone", conn.width); end; end; end; function setPrompts(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (p[2] == nil) then sendGM(conn, S_ERROR, "csetpromptsUsage"); return nil end; if (strfind(conn.flags, "p", 1, 1) == nil and strfind(conn.flags, "P", 1, 1) == nil) then conn.flags = conn.flags .. "p"; end; if (strlower(p[2]) == gm(conn, "On")) then conn.flags = gsub(conn.flags, "p", "P"); sendGM(conn, S_DONE, "csetpromptsOn"); else conn.flags = gsub(conn.flags, "P", "p"); sendGM(conn, S_DONE, "csetpromptsOff"); end; end; function setPrivs(connection, line, params) local conn = colloquy.connections[connection]; if (strfind(conn.privs or "", "P", 1, 1) == nil) then sendGM(conn, S_ERROR, "NoPriv"); return nil; else local p = split(params); if (p[3] == nil or p[2] == nil) then sendGM(conn, S_ERROR, "csetprivsUsage"); return nil; end; local u = strlower(p[2]); local i, v; for i, v in colloquy.connections do if (i ~= "n" and strlower(v.username) == u) then -- right, found the user... if (v.privs and strfind(v.privs, "Z", 1, 1)) then sendGM(conn, S_ERROR, "Immune", v.username); return nil; end; v.privs = ""; v.status = 2; if (p[3] ~= "-") then local j, k, m; m = strlower(conn.realUser); for j, k in users do if (j == m) then local n; for n = 1, strlen(p[3]) do if (strfind(k.privs, strsub(p[3], n, n), 1, 1)) then v.privs = v.privs .. strsub(p[3], n, n); end; end; end; end; end; log(format("P %s[%s] sets %s[%s] privs to %s", conn.username, conn.realUser, v.username, v.realUser, p[3])); sendGM(conn, S_DONE, "csetprivsChanged", v.username, v.privs); return nil; end; end; sendGM(conn, S_ERROR, "UnknownUser", p[2]); end; end; function setTimewarn(connection, line, params) local conn = colloquy.connections[connection]; local p = split(params); if (p[2] == nil) then sendGM(conn, S_ERROR, "csettimeUsage"); return nil; end; local n = tonumber(p[2]); if (type(n) ~= "number") then sendGM(conn, S_ERROR, "csettimeUsage"); return nil; end; if (n > 0 and n < 1) then n = 1 end; n = floor(n); conn.timeWarn = n; conn.timeTick = secs; if (n > 0) then sendGM(conn, S_DONE, "csettimeDone", n); else sendGM(conn, S_DONE, "csettimeNone"); end; end; function setCR(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (p[2] == nil) then sendGM(conn, S_ERROR, "csetcrUsage"); return nil; end; if (strlower(p[2]) == gm(conn, "On")) then conn.flags = gsub(conn.flags, "c", "C"); sendGM(conn, S_DONE, "csetcrOn"); else conn.flags = gsub(conn.flags, "C", "c"); sendGM(conn, S_DONE, "csetcrOff"); end; end; function setTerm(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (p[2] == nil) then sendGM(conn, S_ERROR, "csettermUsage"); return nil; end; local t = strlower(p[2]); if (t == strlower(gm(conn, "csetOptTermDumb"))) then conn.termType = "dumb"; sendGM(conn, S_DONE, "csettermDone", gm(conn, "csetOptTermDumb")); elseif (t == strlower(gm(conn, "csetOptTermColour"))) then conn.termType = "colour"; sendGM(conn, S_DONE, "csettermDone", gm(conn, "csetOptTermColour")); elseif (t == strlower(gm(conn, "csetOptTermClient"))) then conn.termType = "client"; sendGM(conn, S_DONE, "csettermDone", gm(conn, "csetOptTermClient")); else sendGM(conn, S_ERROR, "csettermUnknown", p[2]); end; end; function setColour(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; local col = function(t) local f, b = getColouringName(%conn, t) return f .. " on " .. b end; if (p[2] == nil or p[3] == nil or p[4] == nil) then send("Current colour settings: ", conn, S_DONE); send(" Talk: " .. col("talk"), conn, S_DONE); send(" Tell: " .. col("tell"), conn, S_DONE); send(" List: " .. col("list"), conn, S_DONE); send(" ListName: " .. col("listname"), conn, S_DONE); send(" Shout: " .. col("shout"), conn, S_DONE); send(" Message: " .. col("message"), conn, S_DONE); send(" Nick: " .. col("nick"), conn, S_DONE); send(" Me: " .. col("me"), conn, S_DONE); send("Use .Set Colour <Type> <Foreground> <Background> to change them.", conn, S_DONE); return nil; end; local t = strlower(p[2]); local c = strlower(p[3]); local bc = strlower(p[4]); local br, brb; if (strsub(c, 1, 2) == "br") then br = 1; c = strsub(c, 3, -1); end; if (strsub(bc, 1, 2) == "br") then brb = 1; bc = strsub(bc, 3, -1); end if (not equal(t, { "talk", "tell", "list", "listname", "shout", "message", "nick", "me", "talkback", "tellback", "listback", "listnameback", "shoutback", "messageback", "nickback", "meback" })) then send("Unknown type. Valid types are: talk, tell, list, listname, shout, message, nick, me.", conn, S_ERROR); return nil; end; if (not equal(c, { "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white", "none" } )) then send("Unknown colour. Valid colours are: BrBlack, BrRed, BrGreen, BrYellow, BrBlue, BrMagenta, BrCyan, BrWhite, Black, Red, Green, Yellow, Blue, Magenta, Cyan, White.", conn, S_ERROR); return nil; end; if (not equal(bc, { "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white", "none" } )) then send("Unknown colour. Valid colours are: BrBlack, BrRed, BrGreen, BrYellow, BrBlue, BrMagenta, BrCyan, BrWhite, Black, Red, Green, Yellow, Blue, Magenta, Cyan, White.", conn, S_ERROR); return nil; end; setColouring(conn, t, strlower(p[3]), strlower(p[4])); send("Colour changed.", conn, S_DONE); saveUsers(colloquy.users); end; function setBeep(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (p[2] == nil) then sendGM(conn, S_ERROR, "csetbeepUsage"); return nil; end; if (strlower(p[2]) == gm(conn, "On")) then conn.flags = gsub(conn.flags, "b", "B"); sendGM(conn, S_DONE, "csetbeepOn"); else conn.flags = gsub(conn.flags, "B", "b"); sendGM(conn, S_DONE, "csetbeepOff"); end; saveUsers(colloquy.users); end; function setInfo(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (conn.status < 2) then sendGM(conn, S_ERROR, "csetinfoGuest"); return nil; end; if (p[2] == nil) then sendGM(conn, S_ERROR, "csetinfoUsage"); return nil; end; local t = strlower(p[2]); local f = function(a) return gm(%conn, "csetinfoF" .. a) end; if (not equal(t, {f"location", f"occupation", f"interests", f"comments", f"around", f"email", f"homepage"}) ) then sendGM(conn, S_ERROR, "csetinfoInvalid", p[2]); return nil; end; local u = users[strlower(conn.realUser)]; if (not u) then send("Sorry, I havn't a clue who you are.", conn, S_ERROR); return nil; end; local v; if (p[3]) then v = strsub(line, strfind(line, p[2], 1, 1) + strlen(p[2]) + 1, -1); end; if (t == f"location") then u.location = v; elseif (t == f"occupation") then u.occupation = v; elseif (t == f"interests") then u.interests = v; elseif (t == f"comments") then u.comments = v; elseif (t == f"around") then u.around = v; elseif (t == f"email") then u.email = v; elseif (t == f"homepage") then u.homepage = v; end; saveUsers(colloquy.users); if (v) then sendGM(conn, S_DONE, "csetinfoChanged", t, v); else sendGM(conn, S_DONE, "csetinfoUnset", t); end; end; function setHeard(connection, line, params) local p = split(params); local f = strlower(p[1]); local conn = colloquy.connections[connection]; if (f == gm(conn, "csetheardShouts")) then if (not p[2]) then if (strfind(conn.flags, "S", 1, 1)) then sendGM(conn, S_DONE, "csetheardShoutsOn"); else sendGM(conn, S_DONE, "csetheardShoutsOff"); end; return nil; end; local s = strlower(p[2]); if (s == gm(conn, "Off")) then conn.flags = exchange(conn.flags, "S", "s"); sendGM(conn, S_DONE, "csetheardShoutsOff"); else conn.flags = exchange(conn.flags, "s", "S"); sendGM(conn, S_DONE, "csetheardShoutsOn"); end; return nil; elseif (f == gm(conn, "csetheardMessages")) then if (not p[2]) then if (strfind(conn.flags, "M", 1, 1)) then sendGM(conn, S_DONE, "csetheardMessagesOn"); else sendGM(conn, S_DONE, "csetheardMessagesOff"); end; return nil; end; local s = strlower(p[2]); if (s == gm(conn, "Off")) then conn.flags = exchange(conn.flags, "M", "m"); sendGM(conn, S_DONE, "csetheardMessagesOff"); else conn.flags = exchange(conn.flags, "m", "M"); sendGM(conn, S_DONE, "csetheardMessagesOn"); end; return nil; elseif (f == gm(conn, "csetheardLists")) then if (not p[2]) then if (strfind(conn.flags, "L", 1, 1)) then sendGM(conn, S_DONE, "csetheardListsOn"); else sendGM(conn, S_DONE, "csetheardListsOff"); end; return nil; end; local s = strlower(p[2]); if (s == gm(conn, "Off")) then conn.flags = exchange(conn.flags, "L", "l"); sendGM(conn, S_DONE, "csetheardListsOff"); else conn.flags = exchange(conn.flags, "m", "M"); sendGM(conn, S_DONE, "csetheardListsOn"); end; return nil; elseif (f == gm(conn, "csetheardIdling")) then if (not p[2]) then if (strfind(conn.flags, "I", 1, 1)) then sendGM(conn, S_DONE, "csetheardIdlingOn"); else sendGM(conn, S_DONE, "csetheardIdlingOff"); end; return nil; end; local s = strlower(p[2]); if (s == gm(conn, "Off")) then conn.flags = exchange(conn.flags, "I", "i"); sendGM(conn, S_DONE, "csetheardIdlingOff"); else conn.flags = exchange(conn.flags, "i", "I"); sendGM(conn, S_DONE, "csetheardIdlingOn"); end; return nil; end; end; function commandClosedown(connection, line) log(format("C %s[%s] closed the talker down.", colloquy.connections[connection].username, colloquy.connections[connection].realUser)); local i, v; for i, v in colloquy.connections do if (i ~= "n") then send("Talker closed down by " .. colloquy.connections[connection].username .. ".", v, S_DISCONNECT); disconnectUser(i, " - Closedown"); end; end; colloquy.quit = 1; end; function commandForce(connection, line, thing) local username, command; local conn = colloquy.connections[connection]; if (strfind(thing, " ") ~= nil) then username = strsub(thing, 1, strfind(thing, " ") - 1); command = strsub(thing, strfind(thing, " ") + 1, strlen(thing)); else username, command = "", ""; end; if (username == "" or command == "") then sendGM(conn, S_ERROR, "cforceUsage"); return nil; end; local u, i, v = strlower(username); for i, v in colloquy.connections do if (i ~= "n") then if (u == strlower(v.username)) then if (allowZ(i)) then send(colloquy.connections[i].username .. " has immunity.", conn, S_ERROR); return nil; end; log(format("F %s[%s] forces %s[%s]: %s", conn.username, conn.realUser, v.username, v.realUser, command)); parseInput(i, command) sendGM(conn, S_DONE, "cforceDone", v.username, command); return nil; end; end; end; sendGM(conn, S_ERROR, "UnknownUser", username); end; function commandHelpUser(connection, line, thing) local username, command; local conn = colloquy.connections[connection]; if (strfind(thing, " ") ~= nil) then username = strsub(thing, 1, strfind(thing, " ") - 1); command = strsub(thing, strfind(thing, " ") + 1, strlen(thing)); else username, command = "", ""; end if (username == "" or command == "") then sendGM(conn, S_ERROR, "chelpuserUsage"); return nil; end local u, i, v = strlower(username); for i, v in colloquy.connections do if (i ~= "n") then if (u == strlower(v.username)) then log(format("H %s[%s] helps %s[%s]: %s", conn.username, conn.realUser, v.username, v.realUser, command)); parseInput(i, ".help " .. command) sendGM(conn, S_DONE, "chelpuserDone", v.username, command); return nil; end; end; end; sendGM(conn, S_ERROR, "UnknownUser", username); end; function commandSaveData(connection, line, file) if (file == "") then file = colloquy.users end; saveUsers(file); sendGM(colloquy.connections[connection], S_DONE, "csavedataDone", file); log(format("SD %s[%s] saves data to %s", colloquy.connections[connection].username, colloquy.connections[connection].realUser, file)); end; function commandPassword(connection, line, params) local old, new, cold; local conn = colloquy.connections[connection]; if (conn.status < 2) then sendGM(conn, S_ERROR, "cpasswordGuest"); return nil; end; if (strfind(params, " ") ~= nil) then old = strsub(params, 1, strfind(params, " ") - 1); new = strsub(params, strfind(params, " ") + 1, strlen(params)); else old, new = "", ""; end; if (old == "" or new == "") then sendGM(conn, S_ERROR, "cpasswordUsage"); return nil; end; local pr, message = changePassword(conn.realUser, old, new); if (not pr) then sendGM(conn, S_ERROR, "cpasswordFail"); else sendGM(conn, S_DONE, "cpasswordDone"); end; end; function commandLua(connection, line, command) log(format("L %s[%s] executes %s", colloquy.connections[connection].username, colloquy.connections[connection].realUser, command)); if (strsub(command, 1, 1) == "=") then -- they just want to view a variable local s = strsub(command, 2, -1); send(format("%s = %s", s, tostring(dostring("return " .. s))), colloquy.connections[connection], S_DONE); else dostring(command); sendGM(colloquy.connections[connection], S_DONE, "cluaDone", command); end; end; function commandNewUser(connection, line, params) local conn = colloquy.connections[connection]; local p = split(params); if (p[1] == nil or p[2] == nil) then sendGM(conn, S_ERROR, "cnewuserUsage"); return nil; end; if (users[strlower(p[1])]) then sendGM(conn, S_ERROR, "cnewuserAlready", p[1]); return nil; end; log(format("U %s[%s] creates '%s' with password '%s'", colloquy.connections[connection].username, colloquy.connections[connection].realUser, p[1], p[2])); users[strlower(p[1])] = { password2 = crypt(strlower(p[1]) .. p[2]), created = date() .. " by " .. colloquy.connections[connection].username, flags = "", restrict = "", }; saveUsers(colloquy.users); sendGM(conn, S_DONE, "cnewuserDone", strlower(p[1])); end; function commandDeleteUser(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (p[1] == nil) then sendGM(conn, S_ERROR, "cdeleteuserUsage"); return nil; end; if (users[strlower(p[1])] == nil) then sendGM(conn, S_ERROR, "UnknownUser", p[1]); return nil; end; if (users[strlower(p[1])].privs ~= nil and strfind(users[strlower(p[1])].privs, "Z", 1, 1)) then sendGM(conn, S_ERROR, "Immune", strlower(p[1])); return nil; end; log(format("U %s[%s] deletes %s", colloquy.connections[connection].username, colloquy.connections[connection].realUser, params)); users[strlower(p[1])] = nil; saveUsers(colloquy.users); sendGM(conn, S_DONE, "cdeleteuserDone", strlower(p[1])); end; function commandTell(connection, line, text) -- new .tell command! Can take lists of people to send a message to... for example: -- >bob,gavin,rick Ogg smells. -- <@public,-ogg thinks Ogg smells. -- etc... local p = split(text); -- split words into a table, so we have who to whisper to as p[1]... local dest = {}; -- table of connection tables that this will be sent to (for normal tells, just one, multitells, multiple.) local whoAdd = {}; -- table of people to add (later intergrated into dest{}) local whoSub = {}; -- table of people to subtract (later intergrated into dest{}) local who = {}; -- table used for extracting the entries out of p[1] local conn = colloquy.connections[connection]; local sep = ">" -- seperator to use... > for tells, ] for a tell to a group, | for a multitell. local tmp; local i, v; local destString = " <"; -- string that contains a pretty list of who a multitell was sent to. local namedGroups = ""; -- string containing a space seperated list of named lists. if (p[2] == nil and (p[1] == nil)) then sendGM(conn, S_ERROR, "ctellUsage"); return nil; end; -- is this a reply, rather than a new tell? if (strsub(p[1], 1, 1) == "!" or strsub(p[1], 1, 1) == "|") then if (not conn.replyTo) then sendGM(conn, S_ERROR, "ctellNone"); return nil; end; p[1] = strsub(p[1], 2, -1); tinsert(p, 1, conn.replyTo); if (strfind(conn.flags, "D", 1, 1)) then -- is this user a dunce? text = conn.replyTo .. " " .. gsub(strsub(text, 2, -1), "^(%s+)", ""); else text = conn.replyTo .. " " .. strsub(text, 2, -1); end; p = split(text); else -- it's not - let's check to see if the last character of p[1] is , and if it is, strip the following -- space, to allow ">bob, @public, -gavin Hello!" while (strsub(p[1], -1, -1) == ",") do local commapos = strfind(text, ", ", 1, 1); if( not commapos ) then sendGM(conn, S_ERROR, "cremoteUsage"); return nil; end local notspace = strfind(text, "%S", commapos + 1); local lComma = strsub(text, 1, commapos); local rComma = strsub(text, notspace, -1); text = lComma .. rComma; p = split(text); end; end; if (p[2] == nil or p[1] == nil) then sendGM(conn, S_ERROR, "ctellUsage"); return nil; end; -- extract the entries out of p[1] into who{} tmp = p[1]; if (strfind(tmp, ",", 1, 1)) then -- there are multiple things here, extract them. -- here's a quick bodge. :) if (strsub(tmp, -1, -1) ~= ",") then tmp = tmp .. "," end; sep = "|"; repeat local n = strsub(tmp, 1, strfind(tmp, ",", 1, 1) - 1); tinsert(who, n); tmp = strsub(tmp, strfind(tmp, ",", 1, 1) + 1, -1); until (not strfind(tmp, ",", 1, 1)); else -- there aren't multiple things in this list - just do a vanilla tell. who[1] = tmp; if (strsub(tmp, 1, 1) == "@") then -- they only want to whisper to one group - do a group tell... local groupExists = nil; local group = strlower(strsub(tmp, 2, -1)); local err; if (strlen(group) == 0) then -- There's no group name - this means they want to say something to their current group. commandSay(connection, "", strsub(text, strfind(text, " ", 1, 1) + 1, -1), "escape!"); return nil; end; group, err = groupByName(group); if (not group) then -- changed from groupExists, and err send(err, conn, S_ERROR); return nil; end; sep = "]"; local message = strsub(conn.username .. strrep(" ", 11), 1, 12) .. sep .. strsub(text, strfind(text, " ", 1, 1) + 1, -1); sendToGroup(message, group, S_TELL); sendGM(conn, S_DONETELL, "ctellToGroup", group, strsub(text, strfind(text, " ", 1, 1) + 1, -1)); -- now update everybody in the target group's replyTo. for i, v in colloquy.connections do if (i ~= "n" and strlower(v.group) == group) then v.replyTo = conn.username end; end; return nil; end; end; -- now work through the list, inserting entries into dest{}, raising an error if something can't be done. for i, v in who do if (i ~= "n") then local t = whoAdd; if (strsub(v, 1, 1) == "-") then t = whoSub; v = strsub(v, 2, -1); end; if (strsub(v, 1, 1) == "@") then -- right, they've supplied a group name - add everybody in that group to the current table... local group, err = groupByName(strlower(strsub(v, 2, -1))); if (not group) then if (err == "No such group.") then err = gm(conn, "UnknownGroup", strsub(v, 2, -1)) end; send(err, conn, S_ERROR); return nil; end; -- check to see if they've already mentioned this group... if (strfind(namedGroups, group .. " ", 1, 1)) then sendGM(conn, S_ERROR, "ctellMultipleGroup", group); return nil; end; namedGroups = namedGroups .. group .. " "; if (t == whoSub) then destString = destString .. "-"; end; destString = destString .. "@" .. group .. ", "; group = strlower(group); local i, v; for i, v in colloquy.connections do if (i ~= "n" and strlower(v.group) == group) then tinsert(t, v); end; end; else local expansion = userByName(v); if (expansion == nil) then sendGM(conn, S_ERROR, "ctellNoUser", v); return nil; end; if (type(expansion) == "string") then send(expansion, conn, S_ERROR); return nil; end; if (in(expansion, t)) then sendGM(conn, S_ERROR, "ctellMultipleUser", v); return nil; end; tinsert(t, expansion); if (t == whoSub) then destString = destString .. "-"; end; destString = destString .. expansion.username .. ", "; end; end; end; dest = whoAdd; destString = strsub(destString, 1, -3) .. ">"; -- now go though whoSub, and remove them from dest{} for i, v in whoSub do if (i ~= "n") then local where = in(v, dest); if (where) then tremove(dest, where); else sendGM(conn, S_ERROR, "ctellNoRemove", v.username); return nil; end; end; end; local message = strsub(conn.username .. strrep(" ", 11), 1, 12) .. sep .. strsub(text, strfind(text, " ", 1, 1) + 1, -1); if (sep == "|") then sendTo(message .. destString, dest, S_MULTITELL); if (not in(conn, dest)) then destString = gsub(destString, "^%s+", ""); sendGM(conn, S_DONETELL, "ctellDone", destString, strsub(text, strfind(text, " ", 1, 1) + 1, -1)); end; local replyTo = gsub(destString, "[ %>%<]", ""); if (not in(conn, dest)) then replyTo = replyTo .. "," .. conn.username; end; for i, v in dest do if (i ~= "n") then v.replyTo = replyTo; end; end; elseif (sep == ">") then sendTo(message, dest, S_TELL); sendGM(conn, S_DONETELL, "ctellDone", dest[1].username,strsub(text, strfind(text, " ", 1, 1) + 1, -1)); dest[1].replyTo = conn.username; end; end; function commandRemote(connection, line, text) local p = split(text); -- split words into a table, so we have who to whisper to as p[1]... local dest = {}; -- table of connection tables that this will be sent to (for normal tells, just one, multitells, multiple.) local whoAdd = {}; -- table of people to add (later intergrated into dest{}) local whoSub = {}; -- table of people to subtract (later intergrated into dest{}) local who = {}; -- table used for extracting the entries out of p[1] local conn = colloquy.connections[connection]; local sep = ">" -- seperator to use... > for tells, ] for a tell to a group, | for a multitell. local tmp; local i, v; local destString = " <"; -- string that contains a pretty list of who a multitell was sent to. local namedGroups = ""; -- string containing a space seperated list of named lists. if (p[2] == nil and p[1] == nil) then sendGM(conn, S_ERROR, "cremoteUsage"); return nil; end; -- is this a reply, rather than a new tell? if (strsub(p[1], 1, 1) == "!" or strsub(p[1], 1, 1) == "|") then if (not conn.replyTo) then sendGM(conn, S_ERROR, "cremoteNone"); return nil; end; p[1] = strsub(p[1], 2, -1); tinsert(p, 1, conn.replyTo); if (strfind(conn.flags, "D", 1, 1)) then -- is this user a dunce? text = conn.replyTo .. " " .. gsub(strsub(text, 2, -1), "^(%s+)", ""); else text = conn.replyTo .. " " .. strsub(text, 2, -1); end; else -- it's not - let's check to see if the last character of p[1] is , and if it is, strip the following -- space, to allow ">bob, @public, -gavin Hello!" while (strsub(p[1], -1, -1) == ",") do local commapos = strfind(text, ", ", 1, 1); if( not commapos ) then sendGM(conn, S_ERROR, "cremoteUsage"); return nil; end local notspace = strfind(text, "%S", commapos + 1); local lComma = strsub(text, 1, commapos); local rComma = strsub(text, notspace, -1); text = lComma .. rComma; p = split(text); end; end; if (p[2] == nil) then sendGM(conn, S_ERROR, "cremoteUsage"); return nil; end; -- extract the entries out of p[1] into who{} tmp = p[1]; if (strfind(tmp, ",", 1, 1)) then -- there are multiple things here, extract them. -- here's a quick bodge. :) if (strsub(tmp, -1, -1) ~= ",") then tmp = tmp .. "," end; sep = "|"; repeat local n = strsub(tmp, 1, strfind(tmp, ",", 1, 1) - 1); tinsert(who, n); tmp = strsub(tmp, strfind(tmp, ",", 1, 1) + 1, -1); until (not strfind(tmp, ",", 1, 1)); else who[1] = tmp; if (strsub(tmp, 1, 1) == "@") then -- they only want to whisper to one group - do a group tell... local groupExists = nil; local group = strlower(strsub(tmp, 2, -1)); local err; if (strlen(group) == 0) then commandEmote(connection, "", strsub(text, strfind(text, " ", 1, 1) + 1, -1), "escape!"); return nil; end; group, err = groupByName(group); if (not group) then send(err, conn, S_ERROR); return nil; end; sep = "]"; local message = sep .. " " .. conn.username; local t = strsub(text, strfind(text, " ", 1, 1) + 1, -1); if (strfind(punctuation, strsub(t, 1, 1), 1, 1)) then message = message .. t; else message = message .. " " .. t; t = " " .. t; end; sendToGroup(message, group, S_REMOTE); sendGM(conn, S_DONETELL, "cremoteToGroup", group, conn.username .. t); for i, v in colloquy.connections do if (i ~= "n" and strlower(v.group) == group) then v.replyTo = conn.username end; end; return nil; end; end; -- now work through the list, inserting entries into dest{}, raising an error if something can't be done. for i, v in who do if (i ~= "n") then local t = whoAdd; if (strsub(v, 1, 1) == "-") then t = whoSub; v = strsub(v, 2, -1); end; if (strsub(v, 1, 1) == "@") then -- right, they've supplied a group name - add everybody in that group to the current table... local group, err = groupByName(strlower(strsub(v, 2, -1))); if (not group) then if (err == "No such group.") then err = gm(conn, "UnknownGroup", strsub(v, 2, -1)) end; send(err, conn, S_ERROR); return nil; end; -- check to see if they've already mentioned this group... if (strfind(namedGroups, group .. " ", 1, 1)) then sendGM(conn, S_ERROR, "cremoteMultipleGroup", group); return nil; end; namedGroups = namedGroups .. group .. " "; if (t == whoSub) then destString = destString .. "-"; end; destString = destString .. "@" .. group .. ", "; group = strlower(group); local i, v; for i, v in colloquy.connections do if (i ~= "n" and strlower(v.group) == group) then tinsert(t, v); end; end; else local expansion = userByName(v); if (expansion == nil) then sendGM(conn, S_ERROR, "cremoteNoUser", v); return nil; end; if (type(expansion) == "string") then send(expansion, conn, S_ERROR); return nil; end; if (in(expansion, t)) then sendGM(conn, S_ERROR, "cremoteNoUser", v); return nil; end; tinsert(t, expansion); if (t == whoSub) then destString = destString .. "-"; end; destString = destString .. expansion.username .. ", "; end; end; end; dest = whoAdd; destString = strsub(destString, 1, -3) .. ">"; -- now go though whoSub, and remove them from dest{} for i, v in whoSub do if (i ~= "n") then local where = in(v, dest); if (where) then tremove(dest, where); else sendGM(conn, S_ERROR, "cremoteNoRemove", v.username); return nil; end; end; end; local message = sep .. " " .. conn.username; local t = strsub(text, strfind(text, " ", 1, 1) + 1, -1); if (strfind(punctuation, strsub(t, 1, 1), 1, 1)) then message = message .. t; else message = message .. " " .. t; t = " " .. t; end; if (sep == "|") then sendTo(message .. destString, dest, S_MULTITELL); if (not in(conn, dest)) then sendGM(conn, S_DONETELL, "cremoteDone", gsub(destString, "^%s+", ""), conn.username .. t); end; local replyTo = gsub(destString, "[ %>%<]", ""); if (not in(conn, dest)) then replyTo = replyTo .. "," .. conn.username; end; for i, v in dest do if (i ~= "n") then v.replyTo = replyTo; end; end; elseif (sep == ">") then sendTo(message, dest, S_REMOTE); sendGM(conn, S_DONETELL, "cremoteDone", dest[1].username, conn.username .. t); dest[1].replyTo = conn.username; end; end; function commandUserInfo(connection, line, params) local conn = colloquy.connections[connection]; local p = split(params); if (p[1] == nil or p[2] == nil or p[3] == nil) then sendGM(conn, S_ERROR, "cuserinfoUsage"); return nil; end; local u = strlower(p[1]); local i, v, s, c; s = strsub(params, strfind(params, p[2] .. " ") + strlen(p[2]) + 1, strlen(params)); c = strlower(p[2]); if (p[3] == "-") then s = nil; end; local f = function(n) return gm(%conn, "cuserinfoCat" .. n) end; local unset = gm(conn, "cuserinfoUnset"); for i, v in users do if (i == u) then if (c == f "username") then if (users[strlower(p[3])]) then sendGM(conn, S_ERROR, "cuserinfoAlready", strlower(p[3])); return nil; end; users[strlower(p[3])] = v; users[u] = nil; -- now work though all the lists, changing their name over for i, v in lists do if (v.owner == u) then v.owner = strlower(p[3]); end; for j, k in v.members do if (k == u) then v.members[j] = strlower(p[3]); break; end; end; end; sendGM(conn, S_DONE, "cuserinfoDone", f "username", s or unset); saveUsers(colloquy.users); elseif (c == f "password") then v.password = nil v.password2 = crypt(strlower(p[1])..p[3]); saveUsers(colloquy.users); sendGM(conn, S_DONE, "cuserinfoDone", f "password", s or unset); elseif (c == f "name") then v.name = s; saveUsers(colloquy.users); sendGM(conn, S_DONE, "cuserinfoDone", f "name", s or unset); elseif (c == f "birthday") then v.birthday = s; saveUsers(colloquy.users); sendGM(conn, S_DONE, "cuserinfoDone", f "birthday", s or unset); elseif (c == f "location") then v.location = s; saveUsers(colloquy.users); sendGM(conn, S_DONE, "cuserinfoDone", f "location", s or unset); elseif (c == f "occupation") then v.occupation = s; saveUsers(colloquy.users); sendGM(conn, S_DONE, "cuserinfoDone", f "occupation", s or unset); elseif (c == f "interests") then v.interests = s; saveUsers(colloquy.users); sendGM(conn, S_DONE, "cuserinfoDone", f "interests", s or unset); elseif (c == f "comments") then v.comments = s; saveUsers(colloquy.users); sendGM(conn, S_DONE, "cuserinfoDone", f "comments", s or unset); elseif (c == f "around") then v.around = s; saveUsers(colloquy.users); sendGM(conn, S_DONE, "cuserinfoDone", f "around", s or unset); elseif (c == f "homepage") then v.homepage = s; saveUsers(colloquy.users); sendGM(conn, S_DONE, "cuserinfoDone", f "homepage", s or unset); elseif (c == f "email") then v.email = s; saveUsers(colloquy.users); sendGM(conn, S_DONE, "cuserinfoDone", f "email", s or unset); elseif (c == f "sex") then v.sex = s; saveUsers(colloquy.users); sendGM(conn, S_DONE, "cuserinfoDone", f "sex", s or unset); elseif (c == f "aliases") then v.aliases = s; saveUsers(colloquy.users); sendGM(conn, S_DONE, "cuserinfoDone", f "aliases", s or unset); elseif (c == f "privs") then -- this is a complex one -- only allow somebody to set privs they've got. local j; v.privs = ""; if (s ~= nil) then for j = 1, strlen(s) do local k = strsub(s, j, j); if (strfind(colloquy.connections[connection].privs, k) ~= nil) then v.privs = v.privs .. k; end; end; else v.privs = nil; end; saveUsers(colloquy.users); sendGM(conn, S_DONE, "cuserinfoDone", f "privs", s or unset); elseif (c == f "auth") then v.authenticator = s; saveUsers(colloquy.users); sendGM(conn, S_DONE, "cuserinfoDone", f "auth", s or unset); elseif (c == f "quitmsg") then v.quitmsg = s; saveUsers(colloquy.users); sendGM(conn, S_DONE, "cuserinfoDone", f "quitmsg", s or unset); else sendGM(conn, S_ERROR, "cuserinfoCatunknown", c); return nil; end; log(format("U %s[%s] changes %s for %s to '%s'", colloquy.connections[connection].username, colloquy.connections[connection].realUser, c, i, s or "(nil)")); return nil; end; end; sendGM(conn, S_ERROR, "UnknownUser", u); end; function commandExamine(connection, line, user) local conn = colloquy.connections[connection]; if (user == nil or user == "") then sendGM(conn, S_ERROR, "cexamineUsage"); return nil; end; local expansion = userByName(user); if (expansion == nil) then sendGM(conn, S_ERROR, "UnknownUser", user); return nil; elseif (type(expansion) == "string") then send(expansion, colloquy.connections[connection], S_ERROR); return nil; end; local i, v, u, tmp; local format = function(field, value) local t = gm(%conn, "cexamineF" .. field) .. ":" .. strrep(" ", 15); t = strsub(t, 1, 15); return t .. value .. ""; end; v = expansion; if (not expansion.invis) then tmp = v.username; if (strlower(v.username) ~= strlower(v.realUser)) then tmp = tmp .. gm(conn, "cexamineOnAs", v.realUser); end; send(format("User", tmp), colloquy.connections[connection], S_EXAMINE); local j, k; for j, k in users do if (j ~= "n" and j == strlower(v.realUser)) then if (k.name) then send(format("Name", k.name), colloquy.connections[connection], S_EXAMINE); end; end; end; tmp = ""; if (v.privs ~= nil and strfind(v.privs, "M")) then tmp = gm(conn, "cexamineMaster", v.privs); elseif (v.privs ~= nil and v.privs ~= "") then tmp = gm(conn, "cexaminePrived", v.privs); elseif (v.status == 2) then tmp = gm(conn, "cexamineNormal"); else tmp = gm(conn, "cexamineGuest"); end; send(format("Status", tmp), colloquy.connections[connection], S_EXAMINE); if (v.restrict ~= nil and v.restrict ~= "") then local e = v.restrict; e = gsub(e, "G", gm(conn, "cexamineGagged")); e = gsub(e, "C", gm(conn, "cexamineCensored")); e = gsub(e, "B", gm(conn, "cexamineBot")); send(format("Restrictions", e), colloquy.connections[connection], S_EXAMINE); end; send(format("Group", v.group), colloquy.connections[connection], S_EXAMINE); if (colloquy.connections[connection].privs and strfind(colloquy.connections[connection].privs, "M", 1, 1) and v.invitations) then local t, j, k = ""; for j, k in v.invitations do t = t .. j .. " "; end; send(format("Invitations", t), colloquy.connections[connection], S_EXAMINE) end; if (v.pausedLists) then send(format("PausedLists", v.pausedLists), colloquy.connections[connection], S_EXAMINE); end; send(format("Site", v.site), colloquy.connections[connection], S_EXAMINE); if (v.via) then send(format("Via", v.via), colloquy.connections[connection], S_EXAMINE); end; send(format("OnSince", v.onSince), colloquy.connections[connection], S_EXAMINE); send(format("OnFor", timeToString(floor(secs - v.conTime))), colloquy.connections[connection], S_EXAMINE); send(format("TalkBytes", prettyBytes(v.talkBytes or 0)), colloquy.connections[connection], S_EXAMINE); send(format("IdleFor", timeToString(floor(secs - v.idle))), colloquy.connections[connection], S_EXAMINE); if (v.idleReason) then send(format("Idle", v.idleReason), colloquy.connections[connection], S_EXAMINE); end; send(format("TotalIdle", timeToString(floor(v.totalIdle))), colloquy.connections[connection], S_EXAMINE); end; end; function commandIdle(connection, line, params) local conn = colloquy.connections[connection]; local tmp; local listeners = idleListeners() if (params ~= nil and params ~= "") then tmp = " (" .. params .. ")"; conn.idleReason = params; else tmp = ""; conn.idleReason = ""; end; if (conn.veryIdle) then sendGMList(listeners, S_IDLE, "cidleReidle", conn.username, tmp); conn.veryIdle = 0; else sendGMList(listeners, S_IDLE, "cidleIdle", conn.username, tmp); end if not strfind(conn.flags, "I", 1, 1) then if conn.veryIdle then sendGM(conn, S_IDLE, "cidleYouReidle", tmp); conn.veryIdle = 0 else sendGM(conn, S_IDLE, "cidleYouIdle", tmp); end end end; function commandName(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (p[1] == nil or p[2] == nil) then sendGM(conn, S_ERROR, "cnameUsage"); return nil; end; local i, v, u, nu; u = strlower(p[1]); nu = p[2]; if (strlen(nu) > 10) then nu = strsub(nu, 1, 10) end; if (strlen(gsub(nu, "%w", "")) > 0 or (strlen(nu) > 10)) then sendGM(conn, S_ERROR, "cnameInvalid"); return nil; end; for i, v in colloquy.connections do if (i ~= "n" and u == strlower(v.username)) then -- we've found the user to be renamed... check if it's already in use... local j, k; for j, k in colloquy.connections do if (j ~= "n" and (strlower(p[1]) ~= strlower(p[2])) and strlower(k.username) == strlower(nu)) then sendGM(conn, S_ERROR, "cnameAlready"); return nil; end; end; local tmp = ""; if (i == connection) then sendGMAll(S_NAME, "cnameMyNameDone", v.username, nu); else if (allowZ(i)) then sendGM(conn, S_ERROR, "Immune", v.username); return nil; end; sendGMAll(S_NAME, "cnameDone", conn.username, v.username, nu); end; log(format("N %s[%s] changed name of %s[%s] to %s", colloquy.connections[connection].username, colloquy.connections[connection].realUser, v.username, v.realUser, nu)); v.username = nu; return nil; end; end; sendGM(conn, S_ERROR, "UnknownUser", p[1]); end; function commandNameself(connection, line, params) local conn = colloquy.connections[connection]; if (conn.status < 2) then sendGM(conn, S_ERROR, "cnameselfGuest"); return nil; end; local p = split(params); if (p[1] ~= nil) then if (strlower(p[1]) == strlower(conn.realUser)) then -- they're the same username at least... if (p[1] == conn.username) then sendGM(conn, S_ERROR, "cnameselfAlreadyNamed", conn.username); return nil; else for i, v in colloquy.connections do if (i ~= "n" and strlower(v.username) == strlower(conn.realUser) and v.realUser ~= conn.realUser) then sendGM(conn, S_ERROR, "cnameselfAlready"); return nil; end; end; conn.username = p[1]; conn.realUser = p[1]; sendGM(conn, S_DONE, "cnameselfChanged", conn.username); return nil; end; else sendGM(conn, S_ERROR, "cnameselfNotSame", p[1], conn.realUser); return nil; end; else if (conn.username == conn.realUser) then sendGM(conn, S_ERROR, "cnameselfAlreadyNamed", conn.username); return nil; end; for i, v in colloquy.connections do if (i ~= "n" and strlower(v.username) == strlower(conn.realUser) and v.realUser ~= conn.realUser) then sendGM(conn, S_ERROR, "cnameselfAlready"); return nil; end; end; sendGMAll(S_NAME, "cnameselfAllChange", conn.username, conn.realUser); log(format("N %s changed name back to %s", conn.username, conn.realUser)); conn.username = conn.realUser; end; end; function commandWarn(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (p[1] == nil or p[2] == nil) then sendGM(conn, S_ERROR, "cwarnUsage"); return nil; end; local i, v, u, m; u = strlower(p[1]); if (p[2] ~= nil) then m = strsub(params, strfind(params, " ") + 1, strlen(params)); end; for i,v in colloquy.connections do if (i ~="n" and u == strlower(v.username)) then log(format("W %s[%s] warns %s[%s]: %s", colloquy.connections[connection].username, colloquy.connections[connection].realUser, v.username, v.realUser, m)); sendGMAll(S_WARN, "cwarnDone", conn.username, v.username, m); return nil; end; end; sendGM(conn, S_ERROR, "UnknownUser", p[1]); end; function commandKick(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (p[1] == nil) then sendGM(conn, S_ERROR, "chickUsage"); return nil; end; local i, v, u, m; u = strlower(p[1]); if (p[2] ~= nil) then m = strsub(params, strfind(params, " ") + 1, strlen(params)); end; for i,v in colloquy.connections do if (i ~="n" and u == strlower(v.username)) then if (allowZ(i)) then sendGM(conn, S_ERROR, "Immune", v.username); return nil; end; local tmp = "K " .. colloquy.connections[connection].username .. " " .. p[1]; if (p[2] ~= nil) then tmp = tmp .. " " .. m; end; log(format("K %s[%s] kicks %s[%s]: %s", colloquy.connections[connection].username, colloquy.connections[connection].realUser, v.username, v.realUser, p[2] or "(no reason)")); tmp = "- Kicked by " .. colloquy.connections[connection].username; if (p[2] ~= nil) then tmp = tmp .. " (" .. m .. ")"; end; if (p[2] ~= nil) then sendGM(colloquy.connections[i], S_ERROR, "ckickMessage", "(" .. m .. ")"); else sendGM(colloquy.connections[i], S_ERROR, "ckickMessage", gm(colloquy.connections[i], "ckickDefault")); end; disconnectUser(i, tmp); return nil; end; end; sendGM(conn, S_ERROR, "UnknownUser", p[1]); end; function commandInvis(connection, line) colloquy.connections[connection].invis = 1; sendGM(colloquy.connections[connection], S_DONE, "cinvisDone"); log(format("I %s[%s]", colloquy.connections[connection].username, colloquy.connections[connection].realUser)); end; function commandVis(connection, line) colloquy.connections[connection].invis = nil; sendGM(colloquy.connections[connection], S_DONE, "cvisDone"); log(format("i %s[%s]", colloquy.connections[connection].username, colloquy.connections[connection].realUser)); end; function commandRequest(connection, line, params) local conn = colloquy.connections[connection]; if (params == "" or params == nil) then sendGM(conn, S_ERROR, "crequestUsage"); return nil; end; if colloquy.noFork then sendGM(conn, S_ERROR, "crequestNoFork"); return nil; end params = gsub(params, "^[^A-Za-z0-9]", ""); local f = writeto('|mail -a "Reply-To: ' .. y(users[strlower(colloquy.connections[connection].realUser)].email, users[strlower(colloquy.connections[connection].realUser)].email, colloquy.email) .. '" -s "[colloquy] Request from ' .. colloquy.connections[connection].realUser .. '" ' .. colloquy.email); write(f, params); closefile(f); sendGM(conn, S_DONE, "crequestDone"); end; function commandTime(connection, line) sendGM(colloquy.connections[connection], S_TIME, "ctimeDone", date("%a %b %e %H:%M:%S %Y")); end; function commandWho(connection, line, params) local i, v, l, count; local p = split(params); local conn = colloquy.connections[connection]; if (p[1]) then sendGM(conn, S_WHOHDR, "cwhoGroup", p[1]); else sendGM(conn, S_WHOHDR, "cwhoAll", colloquy.talkerName); end; sendGM(conn, S_WHOHDR, "cwhoColumns"); local sorted = {}; local lg; for i, v in colloquy.connections do if (type(v) == "table") then tinsert(sorted, v) end; end; sort(sorted, function(a, b) if (not b) then return 1 end; local la, lb = strlower(a.group), strlower(b.group); if (la == lb) then return (strlower(a.username) < strlower(b.username)); elseif (la == "public") then return 1; elseif (lb == "public") then return nil; elseif (la == "bots-r-us") then return nil; elseif (lb == "bots-r-us") then return 1; else return (strlower(a.group) < strlower(b.group)); end; end); count = 0; for i=1,getn(sorted) do v=sorted[i]; if (i ~= "n") then if (v.status == 0) then l = "--- Still connecting --- " else if (not (v.invis or (v.restrict and strfind(v.restrict, "B", 1, 1))) or (conn.privs and strfind(conn.privs, "M"))) and (p[1] == nil or (strlower(v.group) == strlower(p[1]))) then local flags = ""; if (v.privs and strfind(v.privs, "M", 1, 1)) then flags = "M" elseif (v.restrict and strfind(v.restrict, "B", 1, 1)) then flags = "B" elseif (v.privs ~= "" and v.privs ~= nil) then flags = "P" elseif (v.status > 1) then flags = "U" end; if (v.invis) then flags = flags .. "I" end; if (v.restrict ~= "" and v.restrict ~= nil) then flags = flags .. gsub(v.restrict, "B", "") end; local idle; if (v.veryIdle) then idle = gm(conn, "cwhoIdle"); else if (v.idle) then idle = timeToWhoString(secs - v.idle); else idle = "00:00"; end; end; local locked = colloquy.lockedGroups[strlower(v.group)]; if (locked) then locked = " (L)" else locked = "" end; send(format("%-10.10s %-1.1s %-19.19s %-6.6s %-5.5s %-27.27s", v.username, y(strlower(v.username) == strlower(v.realUser), "", "*"), v.group .. locked, flags, idle, v.site), conn, S_WHO); count = count + 1; end; end; end; end; sendGM(conn, S_WHOHDR, "cwhoTotal", count); end; function commandLWho(connection, line, params) local i, v, l, count; local p = split(params); local conn = colloquy.connections[connection]; local lname; if (p[1]) then lname, l = listByName(conn, p[1]); if (not lname) then send(l, conn, S_ERROR); return nil; end; sendGM(conn, S_WHOHDR, "clwhoList"); else sendGM(conn, S_ERROR, "clwhoUsage"); return nil; end; sendGM(conn, S_WHOHDR, "clwhoColumns"); local sorted = {}; local lg; for i, v in colloquy.connections do if (type(v) == "table") then tinsert(sorted, v) end; end; sort(sorted, function(a, b) if (not b) then return 1 end; local la, lb = strlower(a.group), strlower(b.group); if (la == lb) then return (strlower(a.username) < strlower(b.username)); elseif (la == "public") then return 1; elseif (lb == "public") then return nil; elseif (la == "bots-r-us") then return nil; elseif (lb == "bots-r-us") then return 1; else return (strlower(a.group) < strlower(b.group)); end; end); count = 0; for i=1,getn(sorted) do v=sorted[i]; if (i ~= "n") then if (v.status == 0) then l = "--- Still connecting --- " else if (not (v.invis or (v.restrict and strfind(v.restrict, "B", 1, 1))) or (conn.privs and strfind(conn.privs, "M"))) and (listIsMember(v.realUser, lname, 1)) then local flags = ""; if (v.privs and strfind(v.privs, "M", 1, 1)) then flags = "M" elseif (v.restrict and strfind(v.restrict, "B", 1, 1)) then flags = "B" elseif (v.privs ~= "" and v.privs ~= nil) then flags = "P" elseif (v.status > 1) then flags = "U" end; if (v.invis) then flags = flags .. "I" end; if (v.restrict ~= "" and v.restrict ~= nil) then flags = flags .. gsub(v.restrict, "B", "") end; local idle; if (v.veryIdle) then idle = "IDLE"; else if (v.idle) then idle = timeToWhoString(secs - v.idle); else idle = "00:00"; end; end; local locked = colloquy.lockedGroups[strlower(v.group)]; if (locked) then locked = " (L)" else locked = "" end; send(format("%-10.10s %-1.1s %-19.19s %-6.6s %-5.5s %-27.27s", v.username, y(strlower(v.username) == strlower(v.realUser), "", "*"), v.group .. locked, flags, idle, v.site), conn, S_WHO); count = count + 1; end; end; end; end; sendGM(conn, S_WHOHDR, "clwhoTotal", count); end; function commandGag(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (p[1] == nil) then sendGM(conn, S_ERROR, "cgagUsage"); return nil; end; local u = strlower(p[1]); local i, v; for i, v in colloquy.connections do if (i ~= "n") then if (strlower(v.username) == u) then if (allowZ(i)) then sendGM(conn, S_ERROR, "Immune", v.username); return nil; end; if (strfind(v.restrict, "G", 1, 1)) then sendGM(conn, S_ERROR, "cgagAlready", v.username); return nil; end; v.restrict = v.restrict .. "G"; sendGMAll(S_GAG, "cgagGag", v.username, conn.username); log(format("G %s[%s] gagged %s[%s]", colloquy.connections[connection].username, colloquy.connections[connection].realUser, v.username, v.realUser)); return nil; end; end; end; sendGM(conn, S_ERROR, "UnknownUser", p[1]); end; function commandCensor(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (p[1] == nil) then sendGM(conn, S_ERROR, "ccensorUsage"); return nil; end; local u = strlower(p[1]); local i, v; for i, v in colloquy.connections do if (i ~= "n") then if (strlower(v.username) == u) then if (allowZ(i)) then sendGM(conn, S_ERROR, "Immune", v.username); return nil; end; if (strfind(v.restrict, "C", 1, 1)) then sendGM(conn, S_ERROR, "ccensorAlready", v.username); return nil; end; v.restrict = v.restrict .. "C"; sendGMAll(S_GAG, "ccensorCensor", v.username, conn.username); log(format("MC %s[%s] censors %s[%s]", colloquy.connections[connection].username, colloquy.connections[connection].realUser, v.username, v.realUser)); return nil; end; end; end; sendGM(conn, S_ERROR, "UnknownUser", p[1]); end; function commandUngag(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (p[1] == nil) then sendGM(conn, S_ERROR, "cungagUsage"); return nil; end; local u = userByName(p[1]); if (not u) then sendGM(conn, S_ERROR, "UnknownUser", p[1]); return nil; elseif (type(u) == "string") then send(u, conn, S_ERROR); return nil; elseif (u.realUser == conn.realUser) then sendGM(conn, S_ERROR, "cungagSelf"); return nil; end; if (not strfind(u.restrict, "G", 1, 1)) then sendGM(conn, S_ERROR, "cungagAlready", u.username); return nil; end; u.restrict = gsub(u.restrict, "G", ""); sendGMAll(S_UNGAG, "cungagUngag", u.username, conn.username); log(format("g %s[%s] ungags %s[%s]", conn.username, conn.realUser, u.username, u.realUser)); end; function commandUncensor(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (p[1] == nil) then sendGM(conn, S_ERROR, "cuncensorUsage"); return nil; end; local u = strlower(p[1]); if (u == strlower(colloquy.connections[connection].username)) then sendGM(conn, S_ERROR, "cuncensorSelf"); return nil; end; local i, v; for i, v in colloquy.connections do if (i ~= "n") then if (strlower(v.username) == u) then if (strfind(v.restrict, "C", 1, 1) == nil) then sendGM(conn, S_ERROR, "cuncensorAlready", v.username); return nil; end; v.restrict = gsub(v.restrict, "C", "") sendGMAll(S_UNGAG, "cuncensorUncensor", v.username, conn.username); log(format("mc %s[%s] uncensors %s[%s]", colloquy.connections[connection].username, colloquy.connections[connection].realUser, v.username, v.realUser)); return nil; end; end; end; sendGM(conn, S_ERROR, "UnknownUser", p[1]); end; function commandBanUser(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (p[1] == nil or p[2] == nil) then sendGM(conn, S_ERROR, "cbanuserUsage"); return nil; end; local i, v, u; u = strlower(p[1]); for i, v in users do if (i ~= "n") then if (i == u) then if (v.privs ~= nil and strfind(v.privs, "Z", 1, 1)) then sendGM(conn, S_ERROR, "Immune", i); return nil; end; v.banned = strsub(params, strfind(params, p[1]) + strlen(p[1]) + 1, -1) .. " [" .. colloquy.connections[connection].realUser .. "]"; sendGM(conn, S_DONE, "cbanuserDone", i); log(format("B %s[%s] bans %s: %s", colloquy.connections[connection].username, colloquy.connections[connection].realUser, u, v.banned)); saveUsers(colloquy.users); return nil; end; end; end; sendGM(conn, S_ERROR, "UnknownUser", p[1]); end; function commandUnbanUser(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (p[1] == nil) then sendGM(conn, S_ERROR, "cunbanuserUsage"); return nil; end; local i, v, u; u = strlower(p[1]); for i, v in users do if (i ~= "n") then if (i == u) then if (v.banned ~= nil and v.banned ~= "") then v.banned = ""; sendGM(conn, S_DONE, "cunbanuserDone", i); log(format("b %s[%s] unbans %s", colloquy.connections[connection].username, colloquy.connections[connection].realUser, u)); saveUsers(colloquy.users); else sendGM(conn, S_ERROR, "cunbanuserAlready", i); end; return nil; end; end; end; sendGM(conn, S_ERROR, "UnknownUser", p[1]); end; function commandLockTalker(connection, line, params) local conn = colloquy.connections[connection]; sendGMAll(S_TALKERLOCK, "clocktalkerDone", conn.username); log(format("B %s[%s] locked the talker", conn.username, conn.realUser)); colloquy.locked = 1; end; function commandUnlockTalker(connection, line, params) local conn = colloquy.connections[connection]; sendGMAll(S_TALKERUNLOCK, "cunlocktalkerDone", conn.username); log(format("b %s[%s] unlocked the talker", conn.username, conn.realUser)); colloquy.locked = nil; end; function commandAlert(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (p[1] == nil) then sendGM(conn, S_ERROR, "calertUsage"); return nil; end; log(format("A %s[%s] %s", conn.username, conn.realUser, params)); sendGMAll(S_ALERT, "calertDone", params); end; function commandLogin(connection, line, params) local p = split(params); local c = colloquy.connections[connection]; if (p[2] == nil) then sendGM(c, S_ERROR, "cloginUsage"); return nil; end; local user = strlower(p[1]); if (users[user] == nil) then sendGM(c, S_ERROR, "UnknownUser", p[1]); return nil; end; local u = users[user]; local i, v; for i, v in colloquy.connections do if (i ~= "n" and strlower(c.username) ~= user) then if (strlower(v.username) == user) then sendGM(c, S_ERROR, "cloginAlready", v.username); return nil; end; end; end; local pr, message = checkPassword(user, p[2]); if (not pr) then u.failed = (u.failed or 0) + 1; send(message or gm(c, "cloginPassword"), c, S_ERROR); log(format("!+ Authentication for %s failed (%s) by %s[%s].", p[1], message or "incorrect password", c.username, c.realUser)); return nil; end; if u.banned and u.banned ~= "" then sendGM(c, S_ERROR, "cloginBanned", p[1], u.banned); log(format("!+ Banned user %s tried to logon from %s[%s].", p[1], c.username, c.realUser)); return nil; end if (u.timeon == nil) then sendGM(c, S_ERROR, "cloginNoNormal", p[1]); return nil; end; disconnectUser(c.socket.socket, "Logged on as " .. p[1], 1); log(format("- %s[%s] logged on as...", c.username, c.realUser)); log(format("+ %s", p[1])); local oldName = c.username; c.username = p[1]; c.realUser = p[1]; c.status = 2; c.privs = u.privs; c.flags = u.flags; c.termType = u.termType; c.colours = u.colours; c.restrict = u.restrict; c.timeWarn = u.timeWarn; c.aliases = u.aliases; u.connected = secs; if (u.termType == "colour" and strfind(c.flags, "W")) then send("\255\253\31", c, S_RAW); end; commandSet(connection, ".set", ""); sendGMAll(S_LOGIN, "cloginDone", oldName, p[1]); if (u.failed and u.failed > 0) then sendGM(c, S_DONE, "cloginFailures", u.failed); u.failed = 0; end; end; function commandComment(connection, line, params) local conn = colloquy.connections[connection]; if (params == nil or params == "") then if (conn.comment) then conn.comment = nil; sendGM(conn, S_DONE, "ccommentRemove"); else sendGM(conn, S_ERROR, "ccommentNone"); end; return nil; else sendGM(conn, S_DONE, "ccommentSet", params); conn.comment = params; end; end; function commandComments(connection, line, params) local i, v, p; local conn = colloquy.connections[connection]; p = 0; for i, v in colloquy.connections do if (i ~= "n" and v.comment ~= nil) then send(v.username .. ": " .. v.comment, conn, S_COMMENT); p = p + 1; end; end; if (p == 0) then sendGM(conn, S_COMMENT, "ccommentsNone"); end; end; function commandWake(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (p[1] == nil) then sendGM(conn, S_ERROR, "cwakeUsage"); return nil; end; local u = userByName(p[1]); if (u == nil) then sendGM(conn, S_ERROR, "UnknownUser", p[1]); return nil; end; if (type(u) == "string") then send(u, conn, S_ERROR); return nil; end; sendGM(u, S_WAKE, "cwakeAttempts", conn.username); sendGM(conn, S_DONE, "cwakeDone", u.username); end; function commandShowLog(connection, line, params) local conn = colloquy.connections[connection]; if colloquy.noFork then sendGM(conn, S_ERROR, "NotAvail"); return nil; end; local f = readfrom("|tail " .. colloquy.logName); local conn, l = colloquy.connections[connection]; repeat l = read(f, "*l"); if (l) then send(l, conn, S_LOOK); end; until (l == nil); closefile(f); end; function commandLock(connection, line, params) local conn = colloquy.connections[connection]; if (strlower(conn.group) == "public") then sendGM(conn, S_ERROR, "clockPublic"); return nil; end; if (colloquy.lockedGroups[strlower(conn.group)]) then sendGM(conn, S_ERROR, "clockAlready"); return nil; end; colloquy.lockedGroups[strlower(conn.group)] = 1; sendGMGroup(conn.group, S_DONE, "clockDone", conn.username); end; function commandUnlock(connection, line, params) local conn = colloquy.connections[connection]; if (strlower(conn.group) == "public") then sendGM(conn, S_ERROR, "cunlockPublic"); return nil; end; if (not colloquy.lockedGroups[strlower(conn.group)]) then sendGM(conn, S_ERROR, "cunlockAlready"); return nil; end; colloquy.lockedGroups[strlower(conn.group)] = nil; updateInvitations("@" .. strlower(conn.group), ""); sendGMGroup(conn.group, S_DONE, "cunlockDone", conn.username); end; function commandInvite(connection, line, params) local conn = colloquy.connections[connection]; local p = split(params); if (not p[1]) then sendGM(conn, S_ERROR, "cinviteUsage"); return nil; end; local u, spec = getUserMultiple(params); if (u == nil) then send(spec, conn, S_ERROR); return nil; end; -- check if everybody in the spec isn't already in this group. local g = strlower(conn.group); for i, v in u do if (i ~= "n") then if (g == strlower(v.group)) then sendGM(conn, S_ERROR, "cinviteAlready", v.username); return nil; end; end; end; sendGMGroup(conn.group, S_INVITE, "cinviteDone", conn.username, spec); for i, v in u do if (i ~= "n") then addInvitation(v, "@" .. strlower(conn.group)); sendGM(v, S_INVITE, "cinviteUser", conn.username, conn.group, conn.username); end; end; end; function commandIdlers(connection, line, params) local i, v, l, count; local p = split(params); local conn = colloquy.connections[connection]; if (p[1]) then sendGM(conn, S_WHOHDR, "cidlersGroup", p[1]); else sendGM(conn, S_WHOHDR, "cidlersAll", colloquy.talkerName); end; sendGM(conn, S_WHOHDR, "cidlersHeader") local sorted = {}; local lg; for i, v in colloquy.connections do if (type(v) == "table" and v.veryIdle) then tinsert(sorted, v) end; end; sort(sorted, function(a, b) if (not b) then return 1 end; local la, lb = strlower(a.group), strlower(b.group); if (la == lb) then return (strlower(a.username) < strlower(b.username)); elseif (la == "public") then return 1; elseif (lb == "public") then return nil; elseif (la == "bots-r-us") then return nil; elseif (lb == "bots-r-us") then return 1; else return (la < lb); end; end); count = 0; for i=1,getn(sorted) do v=sorted[i]; if (i ~= "n") then if (v.status == 0) then l = "--- Still connecting --- " else if (not v.invis or (conn.privs and strfind(conn.privs, "M"))) and (p[1] == nil or (strlower(v.group) == strlower(p[1]))) then send(format("%-10.10s %-8.8s %-55.55s", v.username, timeToShortString(secs - v.idle), v.idleReason), conn, S_WHO); count = count + 1; end; end; end; end; sendGM(conn, S_WHOHDR, "cidlersTotal", count); end; function commandEvict(connection, line, params) local conn = colloquy.connections[connection]; local p = split(params); if (not p[1]) then sendGM(conn, S_ERROR, "cevictUsage"); return nil; end; local ruser = userByName(p[1]); if (type(ruser) == "nil") then sendGM(conn, S_ERROR, "UnknownUser", p[1]); return nil; elseif (type(ruser) == "string") then send(ruser, conn, S_ERROR); return nil; end; if (ruser.username == conn.username) then sendGM(conn, S_ERROR, "cevictSelf"); return nil; end; if (strlower(ruser.group) == "public" and (not conn.privs or not strfind(conn.privs, "E", 1, 1))) then sendGM(conn, S_ERROR, "cevictPublic"); return nil; elseif (strlower(ruser.group) == "public" and (conn.privs and strfind(conn.privs, "E", 1, 1))) then sendGM(ruser, S_EVICT, "cevictEvictee", conn.username); ruser.group = ""; sendGMGroup("limbo", S_EVICT, "cevictOthers", ruser.username, conn.username); ruser.group = "Limbo"; commandLook(ruser.socket.socket); sendGMGroup("public", S_EVICT, "cevictDone", conn.username, ruser.username); log(format("E %s[%s] evicts %s[%s] from %s", conn.username, conn.realUser, ruser.username, ruser.realUser, "public")); return nil; end; if (strlower(conn.group) ~= strlower(ruser.group)) then if (conn.privs and strfind(conn.privs, "E", 1, 1)) then local o = ruser.group; sendGM(ruser, S_EVICT, "cevictEvictee", conn.username); ruser.group = ""; sendGMGroup("public", S_EVICT, "cevictOthers", ruser.username, conn.username); ruser.group = "Public"; commandLook(ruser.socket.socket); sendGMGroup(o, S_EVICT, "cevictDone", conn.username, ruser.username); sendGM(conn, S_DONE, "Done"); log(format("E %s[%s] evicts %s[%s] from %s", conn.username, conn.realUser, ruser.username, ruser.realUser, o)); return nil; else sendGM(conn, S_ERROR, "cevictGroup"); return nil; end; end; sendGM(ruser, S_EVICT, "cevictEvictee", conn.username); ruser.group = ""; sendGMGroup("public", S_EVICT, "cevictOthers", ruser.username, conn.username); ruser.group = "Public"; commandLook(ruser.socket.socket); sendGMGroup(o, S_EVICT, "cevictDone", conn.username, ruser.username); end; function commandQuery(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (not p[1]) then if (conn.query) then sendGM(conn, S_DONE, "cqueryEnd") conn.query = nil; else sendGM(conn, S_ERROR, "cqueryNone"); end; return nil; end; local t = strsub(p[1], 1, 1); local u; if (t == "%") then -- they want to query a list... local ll = strlower(strsub(p[1], 2, -1)); local l, err = listByName(conn, ll, 1); if (l == nil) then send(err, conn, S_ERROR); return nil; end; if (lists[l] == nil) then sendGM(conn, S_ERROR, "UnknownList", l); return nil; end; if (not listIsMember(conn.realUser, l)) then sendGM(conn, S_ERROR, "cqueryNoList"); return nil; end; conn.query = { format = "%" .. lists[l].listname, data = lists[l] }; sendGM(conn, S_DONE, "cqueryList", lists[l].listname); return nil; elseif (t == "@") then -- They want to query a group... -- Also, perhaps write a groupByName to handle contractions? local group, err = groupByName(strsub(p[1], 2, -1)); if (not group) then send(err, conn, S_ERROR); return nil; end; conn.query = { format = "@" .. group, data = group }; sendGM(conn, S_DONE, "cqueryGroup", group); return nil; else -- is it a user? u = userByName(p[1]); if (type(u) == "string") then send(u, conn, S_ERROR); return nil; elseif (u == nil) then sendGM(conn, S_ERROR, "UnknownUser", p[1]); return nil; end; conn.query = { format = ">" .. u.username, data = u }; sendGM(conn, S_DONE, "cqueryUser", u.username); end; end; function commandBan(connection, line, params) local conn = colloquy.connections[connection]; local p = split(params); if (p[1] ~= nil and p[2] == nil) then sendCM(conn, S_ERROR, "cbanUsage"); return nil; end; if (p[1] == nil and p[2] == nil) then sendGM(conn, S_INFO, "cbanHeader"); local i, v; for i, v in colloquy.banMasks do if (type(v) == "table") then send(format(" %s (%s)", v.mask, v.reason), conn, S_INFO); end; end; return nil; end; tinsert(colloquy.banMasks, { mask = p[1], reason = strsub(params, strfind(params, p[2], 1, 1), -1) .. " [" .. conn.realUser .. "]" } ); log(format("B %s[%s] bans %s : %s", conn.username, conn.realUser, p[1], strsub(params, strfind(params, p[2], 1, 1), -1))); saveBans(colloquy.banFile); sendGM(conn, S_DONE, "cbanDone", p[1]); end; function commandUnban(connection, line, params) local conn = colloquy.connections[connection]; local p = split(params); if (p[1] == nil) then sendGM(conn, S_ERROR, "cunbanUsage"); return nil; end; local i, v; for i, v in colloquy.banMasks do if (type(v) == "table" and v.mask == p[1]) then tremove(colloquy.banMasks, i); log(format("b %s[%s] unbans %s : %s", conn.username, conn.realUser, p[1], v.reason)); saveBans(colloquy.banFile); sendGM(conn, S_DONE, "cunbanDone", p[1]); return nil; end; end; sendGM(conn, S_ERROR, "cunbanNone", p[1]); end; function commandMOTD(connection, line, params) sendFile("data/misc/motd", {colloquy.connections[connection]}); end; function commandIgnore(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; local silent = (strlower(p[2] or "")) == gm(conn, "cignoreSilently"); if (p[1] == nil) then -- no parameters - print out who they're ignoring sendGM(conn, S_DONE, "cignoreIgnoring"); if (conn.ignoring) then local t = {}; foreach(conn.ignoring, function(i, v) tinsert(%t, i.username) end); sort(t); foreachi(t, function(i, v) send(" " .. v, %conn, S_DONE) end); else sendGM(conn, S_DONE, "cignoreNobody"); end; local t, i, v = {}; for i, v in colloquy.connections do if (v.ignoring and v.ignoring[conn]) then tinsert(t, v.username); end; end; sort(t); sendGM(conn, S_DONE, "cignoreIgnored"); if (getn(t) > 0) then foreachi(t, function(i, v) send(" " .. v, %conn, S_DONE) end); else sendGM(conn, S_DONE, "cignoreNobody"); end; return nil; end; local u = userByName(p[1]); if (not u) then sendGM(conn, S_ERROR, "UnknownUser", p[1]); return nil; end; if (type(u) == "string") then send(u, conn, S_ERROR); return nil; end; if (u == conn) then sendGM(conn, S_ERROR, "cignoreSelf"); return nil; end; if (conn.ignoring and conn.ignoring[u]) then sendGM(conn, S_ERROR, "cignoreAlready", u.username); return nil; end; if (not conn.ignoring) then conn.ignoring = {}; end; conn.ignoring[u] = 1; sendGM(conn, S_DONE, "cignoreDone", u.username); local suffix = ""; if (silent and u.privs and strfind(u.privs, "M", 1, 1)) then silent = nil; suffix = format(" (%s)", gm(u, "cignoreSilently")) end; if (not silent) then sendGM(u, S_DONE, "cignoreIgnoree", conn.username, suffix); end; end; function commandUnignore(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; local silent = (strlower(p[2] or "")) == gm(conn, "cingoreSilently"); if (not p[1]) then sendGM(conn, S_ERROR, "cunignoreUsage"); return nil; end; local u = userByName(p[1]); if (not u) then sendGM(conn, S_ERROR, "UnknownUser", p[1]); return nil; end; if (type(u) == "string") then send(u, conn, S_ERROR); return nil; end; if (not conn.ignoring or not conn.ignoring[u]) then sendGM(conn, S_ERROR, "cunignoreAlready", u.username); return nil; end; conn.ignoring[u] = nil; if (empty(conn.ignoring)) then conn.ignoring = nil; end; sendGM(conn, S_DONE, "cunignoreDone", u.username); local suffix = ""; if (silent and u.privs and strfind(u.privs, "M", 1, 1)) then silent = nil; suffix = format(" (%s)", gm(u, "cignoreSilently")) end; if (not silent) then sendGM(u, S_DONE, "cunignoreIgnoree", conn.username, suffix); end; end; function commandWhoAmI(connection, line, params) local conn = colloquy.connections[connection]; if (conn.realUser ~= conn.username) then sendGM(conn, S_DONE, "cwhoamiOther", conn.realUser, conn.username); else sendGM(conn, S_DONE, "cwhoamiNormal", conn.realUser); end; end; function commandBot(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (p[1] == nil) then sendGM(conn, S_ERROR, "cbotUsage"); return nil; end; local u = strlower(p[1]); local i, v; if (strsub(u, -3, -1) ~= "bot") then sendGM(conn, S_ERROR, "cbotNot", p[1]); return nil; end; for i, v in colloquy.connections do if (i ~= "n") then if (strlower(v.username) == u) then if (allowZ(i)) then sendGM(conn, S_ERROR, "Immune", v.username); return nil; end; if (strfind(v.restrict, "B", 1, 1)) then sendGM(conn, S_ERROR, "cbotAlready", v.username); return nil; end; v.restrict = v.restrict .. "B"; sendGMAll(S_GAG, "cbotDone", v.username, conn.username); log(format("MB %s[%s] bots %s[%s]", colloquy.connections[connection].username, colloquy.connections[connection].realUser, v.username, v.realUser)); return nil; end; end; end; sendGM(conn, S_ERROR, "UnknownUser", p[1]); end; function commandUnbot(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (p[1] == nil) then sendGM(conn, S_ERROR, "cunbotUsage"); return nil; end; local u = strlower(p[1]); if (strsub(u, -3, -1) ~= "bot") then sendGM(conn, S_ERROR, "cbotNot", p[1]); return nil; end; local i, v; for i, v in colloquy.connections do if (i ~= "n") then if (strlower(v.username) == u) then if (strfind(v.restrict, "B", 1, 1) == nil) then sendGM(conn, S_ERROR, "cunbotAlready", v.username); return nil; end; v.restrict = gsub(v.restrict, "B", "") sendGMAll(S_UNGAG, "cunbotDone", v.username, conn.username); log(format("mb %s[%s] has been unmade a bot by %s[%s]", colloquy.connections[connection].username, colloquy.connections[connection].realUser, v.username, v.realUser)); return nil; end; end; end; sendGM(conn, S_ERROR, "UnknownUser", p[1]); end; function commandBots(connection, line, params) local total = 0; local occ; local conn = colloquy.connections[connection]; for i, v in colloquy.connections do if (v.restrict and strfind(v.restrict, "B", 1, 1)) then if (total == 0) then send(format("%-15.15s %s", gm(conn, "cbotsName"), gm(conn, "cbotsUse")), conn, S_BOTHDR); end; if (users[strlower(v.realUser)] and users[strlower(v.realUser)].occupation) then occ = users[strlower(v.realUser)].occupation; else occ = gm(conn, "cbotsUseless"); end; send(format("%-15.15s %s", v.username, occ), colloquy.connections[connection], S_BOT); total = total + 1; end; end; if (total > 0) then sendGM(conn, S_DONE, "cbotsTotal", total); else sendGM(conn, S_ERROR, "cbotsNone"); end; end; function commandLaston(connection, line, params) local conn = colloquy.connections[connection]; local p = split(params); local i; if (p[1] == nil) then sendGM(conn, S_ERROR, "clastonUsage"); return nil; end; if (strsub(p[1], 1, 1) == "%") then -- they want to know about a list i = listByName(conn, strlower(strsub(p[1], 2, -1))); -- OK - first of all, we get the list of realUsers who are on a list. -- Then, one by one, go through and see if a user who is connected has -- the same realUser. When we find one, print out a match, and remove -- it from the list. After we've examined all active connections, look -- up the remaining entries in the list members in the users table to -- find out when they last connected. -- User * Last on local members = {}; local count = 0; if (i == nil) then sendGM(conn, S_ERROR, "UnknownList", p[1]); return nil; end; for i, v in lists[i].members do if (type(i) == "number") then tinsert(members, v) end; end; sendGM(conn, S_DONE, "clastonHeader"); for i = 1, getn(members) do for k, j in colloquy.connections do if (strlower(j.realUser) == members[i]) then local u = strlower(j.realUser); local tmp; tmp = gm(conn, "clastonConnected", j.group, timeToShortString(floor(secs - j.idle))); send(format("%-10.10s %-1.1s %s", j.username, y(strlower(j.username) == strlower(j.realUser), "", "*"), tmp), conn, S_DONE); count = count + 1; members[i] = nil; end end; end; -- right, we've dumped out the stuff for currently connected -- users, and removed them from the table. Now look up the remaining -- in the users table. for i = 1, getn(members) do if (members[i]) then local tmp; if (not users[members[i]]) then tmp = gm(conn, "clastonNoExist"); elseif (not users[members[i]].lastLogon) then tmp = gm(conn, "clastonNever"); else tmp = users[members[i]].lastLogon; end; send(format("%-10.10s %-1.1s %s", members[i], "", tmp), conn, S_DONE); count = count + 1; end; end; sendGM(conn, S_DONE, "clastonTotal", count); return nil; else -- they want to know about a single user i = strlower(p[1]); if (users[i] == nil) then sendGM(conn, S_ERROR, "UnknownUser", i); return nil; end; if (users[i].connected) then i = userByName(i); sendGM(conn, S_DONE, "clastonUser", i.username, i.group, timeToShortString(floor(secs - i.idle))); else if not users[i].lastLogon then sendGM(conn, S_DONE, "clastonUserNever", i); else sendGM(conn, S_DONE, "clastonUserConn", i, users[i].lastLogon); end; end; end; end; function commandGuest(connection, line, params) local p = split(params); local conn = colloquy.connections[connection]; if (p[1] == nil) then sendGM(conn, S_ERROR, "cguestUsage"); return nil; end; local u = userByName(p[1]); if (type(u) == "string") then send(u, conn, S_ERROR); return nil; end; if (u == nil) then sendGM(conn, S_ERROR, "UnknownUser", p[1]); return nil; end; if (u.status ~= 1) then sendGM(conn, S_ERROR, "cguestAlready", u.username); return nil; end; if (users.guest == nil) then sendGM(conn, S_ERROR, "cguestNoGuest"); return nil; end; u.status = 2; u.realUser = "guest" sendGMAll(S_LOGIN, "cguestDone", u.username, conn.username); log(format("MG %s[%s] guests %s[%s]", conn.username, conn.realUser, u.username, u.realUser)); end; function commandXyzzy(connection, line, params) send("Nothing happens.", colloquy.connections[connection], S_ERROR); end; -------------------------------------------------------------------------------------------------------------------------- function allowAll(connection) return 1; end; function allowConn(connection) return colloquy.connections[connection].status > 0; end; function allow(connection, p) if (colloquy.connections[connection].privs == nil) then return nil end; return strfind(colloquy.connections[connection].privs, p, 1, 1); end; function allowUsers(connection) return colloquy.connections[connection].status > 1; end; function allowA(connection) return allow(connection, "A"); end; function allowB(connection) return allow(connection, "B"); end; function allowC(connection) return allow(connection, "C"); end; function allowF(connection) return allow(connection, "F"); end; function allowG(connection) return allow(connection, "G"); end; function allowH(connection) return allow(connection, "H"); end; function allowI(connection) return allow(connection, "I"); end; function allowK(connection) return allow(connection, "K"); end; function allowL(connection) return allow(connection, "L"); end; function allowM(connection) return allow(connection, "M"); end; function allowN(connection) return allow(connection, "N"); end; function allowS(connection) return allow(connection, "S"); end; function allowU(connection) return allow(connection, "U"); end; function allowW(connection) return allow(connection, "W"); end; function allowZ(connection) return allow(connection, "Z"); end; function isBot(connection) if (not colloquy.connections[connection].restrict) then return nil end; return strfind(colloquy.connections[connection].restrict, "B", 1, 1); end; if (not commTable) then dofile("parser.lua"); end; setCommands = {}; tinsert(setCommands, { name = "cr", code = setCR }); tinsert(setCommands, { name = "beep", code = setBeep }); tinsert(setCommands, { name = "timewarn", code = setTimewarn }); tinsert(setCommands, { name = "prompts", code = setPrompts }); tinsert(setCommands, { name = "privs", code = setPrivs }); tinsert(setCommands, { name = "term", code = setTerm }); tinsert(setCommands, { name = "echo", code = setEcho }); tinsert(setCommands, { name = "colour", code = setColour }); tinsert(setCommands, { name = "info", code = setInfo }); tinsert(setCommands, { name = "shouts", code = setHeard }); tinsert(setCommands, { name = "messages", code = setHeard }); tinsert(setCommands, { name = "lists", code = setHeard }); tinsert(setCommands, { name = "idling", code = setHeard }); tinsert(setCommands, { name = "width", code = setWidth }); tinsert(setCommands, { name = "strip", code = setStrip }); tinsert(setCommands, { name = "language", code = setLanguage });