-- lists
-- table layout:
--
-- lists[listname] = {
-- listname = "capitalised list name",
-- description = "description of the list",
-- owner = "who owns this list, and is always a list master",
-- created = "when this list was created",
-- flags = "flags - O = open, L = locked, P = permanent, A = anonymous",
-- members = {
-- "bob",
-- "god",
-- "foo"
-- },
-- masters = {
-- "bob",
-- "god"
-- }
-- used = time since the epoch that the list was last used.
-- }
function numberOfListsOwned(username)
local username = strlower(username)
local t = 0;
for i, v in lists do
if ( v.owner == username and not strfind(v.flags, "P") ) then
t = t + 1;
end;
end;
return t;
end;
function searchForUser(realName)
-- searches for a user with realName
local l, i, v = strlower(realName);
for i, v in colloquy.connections do
if (v.realUser and l == strlower(v.realUser)) then
return v;
end;
end;
return nil;
end;
function isListMaster(listname, username)
listname = strlower(listname);
username = strlower(username);
local l = lists[listname];
if l.owner == username or strfind((connection(username).privs or ""), "M", 1, 1) then
return 1;
end
for i, v in (l.masters or {}) do
if v == username then
return 1;
end;
end;
return nil;
end
function getListMembers(listname, talking)
local r, i, v = {};
for i, v in lists[listname].members do
if (i ~= "n") then
local bing = searchForUser(v);
if (type(bing) == "table") then
if (talking) then
if (not listHasPaused(bing, listname)) then
tinsert(r, bing);
end;
else
tinsert(r, bing);
end;
end;
end;
end;
return r;
end;
function listIsMember(user, list, real)
local m, l, i, v = strlower(user), strlower(list);
if (not lists[list]) then return nil end;
if (not real and strfind(lists[list].flags, "O", 1, 1)) then return 0 end;
for i, v in lists[l].members do
if (type(v) == "string" and v == m) then return i end;
end;
return nil;
end;
function listByName(conn, list, talk)
local found, i, v = {};
local luser = strlower(conn.realUser);
local llist = strlower(list);
if (lists[llist] ~= nil ) then
return llist;
end;
for i, v in lists do
if (type(v) == "table") then
if (strfind(i, llist, 1, 1) == 1) then
if (listIsMember(luser, i) or not talk) then
tinsert(found, i);
end;
end;
end;
end;
for i, v in found do
if (v == llist) then
return v;
end;
end;
if (getn(found) == 0) then
if (lists[llist] ~= nil ) then
return llist;
end;
return nil, "That list does not exist!";
end;
if (getn(found) > 1) then
local r = list .. " is ambiguous - matches ";
for i, v in found do
if (type(v) == "string") then
r = r .. lists[v].listname .. ", ";
end;
end;
r = strsub(r, 1, -3) .. ".";
return nil, r;
end;
return found[1];
end;
function commandListTell(connection, line, params)
local p = split(params);
local conn = colloquy.connections[connection];
if (p[1] == nil or p[2] == nil) then
send("Whispering nothing to a list is silly.", colloquy.connections[connection], S_ERROR);
return nil;
end;
local l = strlower(p[1]);
local l, err = listByName(conn, l, 1);
if (l == nil) then
send(err, conn, S_ERROR);
return nil;
end;
if (lists[l] == nil) then
send("No such list.", conn, S_ERROR);
return nil;
end;
if (not listIsMember(conn.realUser, l) and not strfind(conn.privs or "", "M", 1, 1)) then
send("You are not a member of that list, and it is not open!", conn, S_ERROR);
return nil;
end;
if (strfind(lists[l].flags, "R", 1, 1)) then
-- the list is read-only. Check if they're the owner, or a master.
if not isListMaster(l, conn.realUser) then
send("That list is read-only.", conn, S_ERROR);
return nil;
end;
end;
if (listHasPaused(conn, lists[l].listname)) then
listUnpause(conn, l);
end;
local m = getListMembers(l, 1);
local t = strsub(line, strfind(line, p[1], 1, 1) + strlen(p[1]) + 1, strlen(line));
local a = conn.username .. strrep(" ", 11);
a = strsub(a, 1, 12) .. "%" .. t .. " {" .. lists[l].listname .. "}";
sendTo(a, m, S_LISTTALK);
if (not listIsMember(conn.realUser, l, 1)) then
send(format("Whispered to list %s: '%s'", lists[l].listname, t), conn, S_DONETELL);
end;
lists[l].used = secs;
end;
function commandListEmote(connection, line, params)
local p = split(params);
local conn = colloquy.connections[connection];
if (p[1] == nil or p[2] == nil) then
send("Whispering nothing to a list is silly.", colloquy.connections[connection], S_ERROR);
return nil;
end;
local l = strlower(p[1]);
local l, err = listByName(conn, l, 1);
if (l == nil) then
send(err, conn, S_ERROR);
return nil;
end;
if (lists[l] == nil) then
send("No such list.", colloquy.connections[connection], S_ERROR);
return nil;
end;
if (not listIsMember(conn.realUser, l) and not strfind(conn.privs, "M", 1, 1)) then
send("You are not a member of that list, and it is not open!", conn, S_ERROR);
return nil;
end;
if (strfind(lists[l].flags, "R", 1, 1)) then
-- the list is read-only. Check if they're the owner, or a master.
if not isListMaster(l, conn.realUser) then
send("That list is read-only.", conn, S_ERROR);
return nil;
end;
end;
if (listHasPaused(conn, lists[l].listname)) then
listUnpause(conn, l);
end;
local m = getListMembers(l, 1);
local t = strsub(line, strfind(line, p[1], 1, 1) + strlen(p[1]) + 1, strlen(line));
local blah = " ";
if (strfind(punctuation, strsub(t, 1, 1), 1, 1)) then
blah = "";
end;
sendTo(format("%% %s%s%s {%s}", colloquy.connections[connection].username, blah, t, lists[l].listname) , m, S_LISTEMOTE);
if (not listIsMember(conn.realUser, l, 1)) then
send(format("REmote'd to list %s: '%s%s%s'", lists[l].listname, conn.username, blah, t), conn, S_DONETELL);
end;
lists[l].used = secs;
end;
function commandList(connection, line, params)
local conn = colloquy.connections[connection];
local p = split(params);
if (p[1] == nil) then
send("Usage: .list <command> <parameters...>", conn, S_ERROR);
return nil;
end;
if (p[1] == "info") then
if (p[2] == nil) then
return commandLists(connection, ".lists", "");
else
listInfo(conn, p[2]);
return nil;
end;
end;
if (p[1] == "create") then
if (p[2] == nil) then
send("Usage: .list create <listname>", conn, S_ERROR);
return nil;
else
listCreate(conn, p[2]);
return nil;
end;
end;
if (p[1] == "delete") then
if (p[2] == nil) then
send("Usage: .list delete <listname>", conn, S_ERROR);
return nil;
else
listDelete(conn, p[2]);
return nil;
end;
end;
if (p[1] == "join") then
if (p[2] == nil) then
send("Usage: .list join <listname>", conn, S_ERROR);
return nil;
else
listJoin(conn, p[2]);
return nil;
end;
end;
if (p[1] == "leave") then
if (p[2] == nil) then
send("Usage: .list leave <listname>", conn, S_ERROR);
return nil;
else
listLeave(conn, p[2]);
return nil;
end;
end;
if (p[1] == "invite") then
if (p[2] == nil or p[3] == nil) then
send("Usage: .list invite <listname> <username>", conn, S_ERROR);
return nil;
else
listInvite(conn, p[2], p[3]);
return nil;
end;
end;
if (p[1] == "owner") then
if (p[2] == nil or p[3] == nil) then
send("Usage: .list owner <listname> <username>", conn, S_ERROR);
return nil;
else
listOwner(conn, p[2], p[3]);
return nil;
end;
end;
if (p[1] == "description") then
if (p[2] == nil or p[3] == nil) then
send("Usage: .list description <listname> <description>", conn, S_ERROR);
return nil;
else
listDescription(conn, p[2], strsub(params, strfind(params, p[2], 1, 1) + strlen(p[2]) + 1, -1));
return nil;
end;
end;
if (p[1] == "lock") then
if (p[2] == nil) then
send("Usage: .list lock <listname>", conn, S_ERROR);
return nil;
else
listLock(conn, p[2]);
return nil;
end;
end;
if (p[1] == "unlock") then
if (p[2] == nil) then
send("Usage: .list unlock <listname>", conn, S_ERROR);
return nil;
else
listUnlock(conn, p[2]);
return nil;
end;
end;
if (p[1] == "evict") then
if (not p[2] or not p[3]) then
send("Usage: .list evict <listname> <username>", conn, S_ERROR);
return nil;
else
listEvict(conn, p[2], p[3]);
return nil;
end;
end;
if (p[1] == "open") then
if (not p[2]) then
send("Usage: .list open <listname>", conn, S_ERROR);
return nil;
else
listOpen(conn, p[2]);
return nil;
end;
end;
if (p[1] == "close") then
if (not p[2]) then
send("Usage: .list close <listname>", conn, S_ERROR);
return nil;
else
listClose(conn, p[2]);
return nil;
end;
end;
if (p[1] == "pause") then
listPause(conn, p[2]);
return nil;
end;
if (p[1] == "unpause") then
listUnpause(conn, p[2]);
return nil;
end;
if (p[1] == "permanent") then
if not p[2] then
send("Usage: .list permanent <listname>", conn, S_ERROR);
return nil;
end;
listPermanent(conn, p[2]);
return nil;
end;
if (p[1] == "unpermanent") then
if not p[2] then
send("Usage: .list unpermanent <listname>", conn, S_ERROR);
return nil;
end;
listUnpermanent(conn, p[2]);
return nil;
end;
if (p[1] == "anonymous") then
if not p[2] then
send("Usage: .list anonymous <listname>", conn, S_ERROR);
return nil;
end;
listAnonymous(conn, p[2]);
return nil;
end;
if (p[1] == "unanonymous") then
if not p[2] then
send("Usage: .list unanonymous <listname>", conn, S_ERROR);
return nil;
end;
listUnanonymous(conn, p[2]);
return nil;
end;
if (p[1] == "readonly") then
if not p[2] then
send("Usage: .list readonly <listname>", conn, S_ERROR);
return nil;
end;
listReadOnly(conn, p[2]);
return nil;
end;
if (p[1] == "readwrite") then
if not p[2] then
send("Usage: .list readwrite <listname>", conn, S_ERROR);
return nil;
end
listReadWrite(conn, p[2]);
return nil;
end;
if (p[1] == "master") then
if (not p[2] or not p[3]) then
send("Usage: .list master <listname> <username>", conn, S_ERROR);
return nil;
else
listMaster(conn, p[2], p[3]);
return nil;
end;
end;
if (p[1] == "unmaster") then
if (not p[2] or not p[3]) then
send("Usage: .list unmaster <listname> <username>", conn, S_ERROR);
return nil;
else
listUnmaster(conn, p[2], p[3]);
return nil;
end;
end;
if (p[1] == "rename") then
listRename(conn, p[2], p[3]);
return nil;
end;
send("Unknown .list command.", conn, S_ERROR);
end;
function listMember(list, user)
-- returns a * if user is a member of list, or " " otherwise.
if (lists[strlower(list)] == nil) then return " " end;
local m, i, v = lists[strlower(list)].members;
for i, v in m do
if (type(v) == "string" and v == user) then
return "*";
end;
end;
return " ";
end;
function commandLists(connection, line, params)
local p = split(params);
local conn = colloquy.connections[connection];
if (p[1]) then
listInfo(conn, p[1]);
return nil;
end;
local sortedLists = {};
local i, v;
local u = strlower(conn.realUser);
local t = 0;
for i, v in lists do
if (type(v) == "table" and strfind(v.flags, "L", 1, 1)) then
tinsert(sortedLists, v.listname);
end;
end;
t = getn(sortedLists);
if (getn(sortedLists) > 0) then
send("Available locked lists are: ('*' marks ones currently subscribed to)", conn, S_LISTSHDR);
sort(sortedLists);
for i, v in sortedLists do
if (type(v) == "string") then
sortedLists[i] = listMember(v, u) .. v;
end;
end;
local rl = columns(sortedLists, (conn.width-6)/17, 17);
for i=1,getn(rl) do
send(" " .. rl[i], conn, S_LISTS);
end;
end;
sortedLists = {};
for i, v in lists do
if (type(v) == "table" and not strfind(v.flags, "L", 1, 1)) then
tinsert(sortedLists, v.listname);
end;
end;
t = t + getn(sortedLists);
if (getn(sortedLists) > 0) then
send("Available unlocked lists are: ('*' marks ones currently subscribed to)", conn, S_LISTSHDR);
sort(sortedLists);
for i, v in sortedLists do
if (type(v) == "string") then
sortedLists[i] = listMember(v, u) .. v;
end;
end;
local rl = columns(sortedLists, (conn.width-6)/17, 17);
for i=1,getn(rl) do
send(" " .. rl[i], conn, S_LISTS);
end;
end;
if (t == 0) then
send("There are no lists.", conn, S_ERROR);
else
send(tostring(t) .. " total.", conn, S_DONE);
end;
end;
function listInfo(conn, params)
local l = strlower(params);
local l, err = listByName(conn, l);
if (not l) then
send(err, conn, S_ERROR);
return nil;
end;
if (lists[l] == nil) then
send("This list does not exist!", conn, S_ERROR);
return nil;
end;
send(format("%-15.15s %s", "Name:", lists[l].listname), conn, S_LISTINFO);
if (lists[l].description ~= "") then
send(format("%-15.15s %s", "Description:", lists[l].description), conn, S_LISTINFO);
end;
if (lists[l].flags ~= "" and lists[l].flags ~= nil) then
local f = lists[l].flags;
f = gsub(f, "A", "Anonymous ");
f = gsub(f, "L", "Locked ");
f = gsub(f, "O", "Open ");
f = gsub(f, "P", "Permanent ");
f = gsub(f, "R", "Read-Only ");
send(format("%-15.15s %s", "Flags:", f), conn, S_LISTINFO);
end;
send(format("%-15.15s %s", "Created:", lists[l].created), conn, S_LISTINFO);
send(format("%-15.15s %s", "Owner:", lists[l].owner), conn, S_LISTINFO);
local on, off = "", "";
local i, v;
if not strfind(lists[l].flags, "A", 1, 1) then
for i, v in lists[l].members do
if (type(v) == "string") then
local vconn = connection(v);
local lmaster;
if (vconn) then
lmaster = isListMaster(l, vconn.realUser);
local pconn = listHasPaused(vconn, lists[l].listname);
if lmaster then
on = on .. "*";
end
if (pconn) then
on = on .. "(" .. v .. ") ";
elseif (vconn.veryIdle) then
on = on .. "[" .. v .. "] ";
else
on = on .. v .. " ";
end;
else
if lmaster then
off = off .. "*";
end;
off = off .. v .. " ";
end;
end;
end;
end;
if (lists[l].used) then
send(format("%-15.15s %s", "Last used:", strsub(timeToString(secs - lists[l].used), 1, -2) .. " ago."), conn, S_LISTINFO);
end;
if (on ~= "") then
send(format("%-15.15s %s", "Users online:", on), conn, S_LISTINFO);
end;
if (off ~= "") then
send(format("%-15.15s %s", "Users offline:", off), conn, S_LISTINFO);
end;
end;
function listCreate(conn, params)
local l = strlower(params);
if (lists[l] ~= nil) then
send("That list already exists!", conn, S_ERROR);
return nil;
end;
if ( numberOfListsOwned(conn.realUser) >= colloquy.listQuota ) then
send("You have exhausted your list quota. Either delete some old lists, or ask a master to make some of them permanent.", conn, S_ERROR);
return nil;
end;
if (strlen(gsub(l, "[%w%-]", "")) > 0 or (strlen(params) > 15)) then
send("That isn't a valid list name.", conn, S_ERROR);
return nil;
end;
lists[l] = {
listname = params,
description = "",
flags = "",
owner = strlower(conn.realUser),
created = date("%a %b %e %H:%M:%S %Y"),
members = {
strlower(conn.realUser)
}
};
send("List created.", conn, S_DONE);
saveLists();
end;
function listDelete(conn, params)
local l = strlower(params);
local l, err = listByName(conn, l, 1);
if (not l) then
send(err, conn, S_ERROR);
return nil;
end;
if (lists[l] == nil) then
send("That list does not exist!", conn, S_ERROR);
return nil;
end;
if ((strlower(conn.realUser) ~= lists[l].owner) and (conn.privs == nil or strfind(conn.privs, "M", 1, 1) == nil)) then
send("You cannot delete a list you do not own.", conn, S_ERROR);
return nil;
end;
updateInvitations("%" .. l, "");
sendTo(format("%s has deleted the list. {%s}", conn.username, lists[l].listname), getListMembers(l), S_LISTDELETE);
if (not listIsMember(conn.realUser, l, 1)) then
send(format("%s has deleted the list. {%s}", conn.username, lists[l].listname), conn, S_LISTDELETE);
end;
lists[l] = nil;
saveLists();
end;
function listJoin(conn, params)
local l = strlower(params);
local l, err = listByName(conn, l);
if (not l) then
send(err, conn, S_ERROR);
return nil;
end;
if (lists[l] == nil) then
send("That list does not exist!", conn, S_ERROR);
return nil;
end;
local u, i, v = strlower(conn.realUser);
for i, v in lists[l].members do
if (type(v) == "string" and v == u) then
send("You are already a member of that list.", conn, S_ERROR);
return nil;
end;
end;
if (lists[l].flags and strfind(lists[l].flags, "L", 1, 1) and (not checkInvitation(conn, "%" .. l))) then
if ( not (conn.privs and strfind(conn.privs, "M", 1, 1))) then
send("That list is locked.", conn, S_ERROR);
return nil;
end;
end;
tinsert(lists[l].members, u);
removeInvitation(conn, "%" .. l);
if strfind(lists[l].flags, "A", 1, 1) then
-- this list is anonymous. Don't tell the list that this person has joined.
send(format("You have joined the list anonymously. {%s}", lists[l].listname), conn, S_LISTJOIN);
else
sendTo(format("%s has joined the list. {%s}", conn.username, lists[l].listname), getListMembers(l), S_LISTJOIN);
end;
saveLists();
end;
function listLeave(conn, params)
local l = strlower(params);
local l, err = listByName(conn, l, 1);
if (not l) then
send(err, conn, S_ERROR);
return nil;
end;
if (lists[l] == nil) then
send("That list does not exist!", conn, S_ERROR);
return nil;
end;
if (lists[l].owner == strlower(conn.realUser)) then
send("You cannot leave a list you own.", conn, S_ERROR);
return nil;
end;
local u, i, v = strlower(conn.realUser);
for i, v in lists[l].members do
if (type(v) == "string" and v == u) then
if strfind(lists[l].flags, "A", 1, 1) then
-- this list is anonymous. Don't tell the list that this person has left.
send(format("You have left the list anonymously. {%s}", lists[l].listname), conn, S_LISTLEAVE);
else
sendTo(format("%s has left the list. {%s}", conn.username, lists[l].listname), getListMembers(l), S_LISTLEAVE);
end;
tremove(lists[l].members, i);
return nil;
end;
end;
send("You are not a member of that list.", conn, S_ERROR);
saveLists();
end;
function listInvite(conn, list, user)
local l = strlower(list);
local u = userByName(user);
local master; -- is this a master override?
local l, err = listByName(conn, l);
if (not l) then
send(err, conn, S_ERROR);
return nil;
end;
if (lists[l] == nil) then
send("That list does not exist!", conn, S_ERROR);
return nil;
end;
if (u == nil) then
send("No such user.", conn, S_ERROR);
return nil;
end;
if (type(u) == "string") then
send(u, conn, S_ERROR);
return nil;
end;
if (lists[l].flags and strfind(lists[l].flags, "L", 1, 1)) then
local m, i, v, f;
m = strlower(conn.realUser);
for i, v in lists[l].members do
if (type(v) == "string" and v == m) then
f = 1;
break;
end;
end;
if (f ~= 1) then
send("Only list members can invite users to locked lists.", conn, S_ERROR);
return nil;
end;
end;
local n = strlower(u.realUser);
local f = nil;
local un = strlower(conn.realUser);
local m, i, v = lists[l].members;
for i, v in m do
if (type(v) == "string" and v == n) then
send("User is already a member.", conn, S_ERROR);
return nil;
end;
if (v == un) then
f = 1;
end;
end;
addInvitation(u, "%" .. l);
if strfind(lists[l].flags, "A", 1, 1) then
-- this list is anonymous. Don't tell the whole list about it.
send(format("You invite %s to the list anonymously. {%s}", u.username, lists[l].listname), conn, S_LISTINVITE);
else
sendTo(format("%s invites %s to the list. {%s}", conn.username, u.username, lists[l].listname), getListMembers(l), S_LISTINVITE);
end;
if (not listIsMember(conn.realUser, l, 1)) then
if strfind(lists[l].flags, "A", 1, 1) then
send(format("You invite %s to the list anonymously. {%s}", u.username, lists[l].listname), conn, S_LISTINVITE);
else
send(format("%s invites %s to the list. {%s}", conn.username, u.username, lists[l].listname), conn, S_LISTINVITE);
end;
end;
local an = "";
if strfind(lists[l].flags, "A", 1, 1) then
an = " anonymously"
end;
send(format("%s invites you to %%%s%s. To respond, type .list join %s", conn.username, lists[l].listname, an, lists[l].listname), u, S_LISTINVITE);
end;
function listOwner(conn, list, user)
local l = strlower(list);
local u = userByName(user);
local l, err = listByName(conn, l, 1);
if (not l) then
send(err, conn, S_ERROR);
return nil;
end;
if (lists[l] == nil) then
send("That list does not exist!", conn, S_ERROR);
return nil;
end;
if (u == nil) then
send("No such user.", conn, S_ERROR);
return nil;
end;
if (type(u) == "string") then
send(u, conn, S_ERROR);
return nil;
end;
if (lists[l].owner ~= strlower(conn.realUser)) then
if (not (conn.privs and strfind(conn.privs, "M", 1, 1))) then
send("You cannot change the owner of lists you do not own.", conn, S_ERROR);
return nil;
end;
end;
local n = strlower(u.realUser);
if ( numberOfListsOwned(n) >= colloquy.listQuota ) then
send(format("%s has exhausted their list quota, and cannot take ownership.", u.username), conn, S_ERROR);
return nil;
end;
local m, i, v = lists[l].members;
for i, v in m do
if (type(v) == "string" and (v == n)) then
sendTo(format("%s makes %s the list owner. {%s}", conn.username, u.username, lists[l].listname), getListMembers(l), S_LISTOWNER);
if (not listIsMember(conn.realUser, l, 1)) then
send(format("%s makes %s the list owner. {%s}", conn.username, u.username, lists[l].listname), conn, S_LISTOWNER);
end;
lists[l].owner = n;
saveLists();
return nil;
end;
end;
send("Only a list's members can be made the owner.", conn, S_ERROR);
end;
function listDescription(conn, list, desc)
local l = strlower(list);
local l, err = listByName(conn, l, 1);
if (not l) then
send(err, conn, S_ERROR);
return nil;
end;
if (lists[l] == nil) then
send("That list does not exist!", conn, S_ERROR);
return nil;
end;
if not isListMaster(l, conn.realUser) then
send("You cannot change the descriptions of lists you are not a master of.", conn, S_ERROR);
return nil;
end;
lists[l].description = desc;
sendTo(format("%s has changed the list's description to '%s'. {%s}", conn.username, desc, lists[l].listname), getListMembers(l), S_LISTDESC);
if (not listIsMember(conn.realUser, l, 1)) then
send(format("%s has changed the list's description to '%s'. {%s}", conn.username, desc, lists[l].listname), conn, S_LISTDESC);
end;
saveLists();
end;
function listLock(conn, list)
local l = strlower(list);
local l, err = listByName(conn, l, 1);
if (not l) then
send(err, conn, S_ERROR);
return nil;
end;
if (lists[l] == nil) then
send("That list does not exlist!", conn, S_ERROR);
return nil;
end;
if not isListMaster(l, conn.realUser) then
send("You cannot lock lists that you are not a master of.", conn, S_ERROR);
end;
if (lists[l].flags and (strfind(lists[l].flags, "L", 1, 1))) then
send("That list is already locked.", conn, S_ERROR);
return nil;
end;
if (not lists[l].flags) then lists[l].flags = "" end;
lists[l].flags = lists[l].flags .. "L";
sendTo(format("%s has locked the list. {%s}", conn.username, lists[l].listname), getListMembers(l), S_LISTLOCK);
if (not listIsMember(conn.realUser, l, 1)) then
send(format("%s has locked the list. {%s}", conn.username, lists[l].listname), conn, S_LISTLOCK);
end;
saveLists();
end;
function listUnlock(conn, list)
local l = strlower(list);
local l, err = listByName(conn, l, 1);
if (not l) then
send(err, conn, S_ERROR);
return nil;
end;
if (lists[l] == nil) then
send("That list does not exist!", conn, S_ERROR);
return nil;
end;
if not isListMaster(l, conn.realUser) then
send("You cannot unlock lists that you are not a master of.", conn, S_ERROR);
return nil;
end;
if (lists[l].flags and (not strfind(lists[l].flags, "L", 1, 1))) then
send("That list is already unlocked.", conn, S_ERROR);
return nil;
end;
if (not lists[l].flags) then lists[l].flags = "" end;
lists[l].flags = gsub(lists[l].flags, "L", "");
updateInvitations("%" .. l, "");
sendTo(format("%s has unlocked the list. {%s}", conn.username, lists[l].listname), getListMembers(l), S_LISTUNLOCK);
if (not listIsMember(conn.realUser, l, 1)) then
send(format("%s has unlocked the list. {%s}", conn.username, lists[l].listname), conn, S_LISTUNLOCK);
end;
saveLists();
end;
function listEvict(conn, list, user)
local l = strlower(list);
local l, err = listByName(conn, l, 1);
if (not l) then
send(err, conn, S_ERROR);
return nil;
end;
if (lists[l] == nil) then
send("That list does not exist!", conn, S_ERROR);
return nil;
end;
if not isListMaster(l, conn.realUser) then
send("You cannot evict users from lists you are not a master of.", conn, S_ERROR);
return nil;
end;
local m, i, v;
m = userByName(user);
if (m == nil) then
send("No such user.", conn, S_ERROR);
return nil;
end;
if (type(m) == "string") then
send(m, conn, S_ERROR);
return nil;
end;
local mm = strlower(m.username);
if (mm == lists[l].owner) then
send("You cannot evict the list owner.", conn, S_ERROR);
return nil;
end;
for i, v in lists[l].members do
if (type(v) == "string" and v == mm) then
sendTo(format("%s has evicted %s from the list. {%s}", conn.username, m.username, lists[l].listname), getListMembers(l), S_LISTEVICT);
if (not listIsMember(conn.realUser, l, 1)) then
send(format("%s has evicted %s from the list. {%s}", conn.username, m.username, lists[l].listname), conn, S_LISTEVICT);
end;
tremove(lists[l].members, i);
saveLists();
return nil;
end;
end;
send("User isn't on that list.", conn, S_ERROR);
end;
function listOpen(conn, list)
local l = strlower(list);
local l, err = listByName(conn, l, 1);
if (not l) then
send(err, conn, S_ERROR);
return nil;
end;
if not isListMaster(l, conn.realUser) then
send("You cannot open a list that you are not a master of.", conn, S_ERROR);
return nil;
end;
if (strfind(lists[l].flags, "O", 1, 1)) then
send("That list is already open!", conn, S_ERROR);
return nil;
end;
lists[l].flags = lists[l].flags .. "O";
sendTo(format("%s has opened the list. {%s}", conn.username, lists[l].listname), getListMembers(l), S_LISTOPEN);
if (not listIsMember(conn.realUser, l, 1)) then
send(format("%s has opened the list. {%s}", conn.username, lists[l].listname), conn, S_LISTOPEN);
end;
saveLists();
end;
function listPermanent(conn, list)
local l = strlower(list);
local l, err = listByName(conn, l, 1);
if (not l) then
send(err, conn, S_ERROR);
return nil;
end;
if (not (conn.privs and strfind(conn.privs, "M", 1, 1))) then
send("Only masters can do that.", conn, S_ERROR);
return nil;
end;
if (strfind(lists[l].flags, "P", 1, 1)) then
send("That list is already permanent!", conn, S_ERROR);
return nil;
end;
lists[l].flags = lists[l].flags .. "P";
sendTo(format("%s has made the list permanent. {%s}", conn.username, lists[l].listname), getListMembers(l), S_LISTPERM);
if (not listIsMember(conn.realUser, l, 1)) then
send(format("%s has made the list permanent. {%s}", conn.username, lists[l].listname), conn, S_LISTPERM);
end;
saveLists();
end;
function listUnpermanent(conn, list)
local l = strlower(list);
local l, err = listByName(conn, l, 1);
if (not l) then
send(err, conn, S_ERROR);
return nil;
end;
if (not (conn.privs and strfind(conn.privs, "M", 1, 1))) then
send("Only masters can do that.", conn, S_ERROR);
return nil;
end;
if (not strfind(lists[l].flags, "P", 1, 1)) then
send("That list isn't permanent!", conn, S_ERROR);
return nil;
end;
lists[l].flags = gsub(lists[l].flags, "P", "");
sendTo(format("%s has made the list non-permanent. {%s}", conn.username, lists[l].listname), getListMembers(l), S_LISTUNPERM);
if (not listIsMember(conn.realUser, l, 1)) then
send(format("%s has made the list non-permanent. {%s}", conn.username, lists[l].listname), conn, S_LISTUNPERM);
end;
saveLists();
end;
function listAnonymous(conn, list)
local l = strlower(list);
local l, err = listByName(conn, l, 1);
if (not l) then
send(err, conn, S_ERROR);
return nil;
end;
if (not (conn.privs and strfind(conn.privs, "M", 1, 1))) then
send("Only masters can do that.", conn, S_ERROR);
return nil;
end;
if (strfind(lists[l].flags, "A", 1, 1)) then
send("That list is already anonymous!", conn, S_ERROR);
return nil;
end;
lists[l].flags = lists[l].flags .. "A";
sendTo(format("%s has made the list anonymous. {%s}", conn.username, lists[l].listname), getListMembers(l), S_LISTANON);
if (not listIsMember(conn.realUser, l, 1)) then
send(format("%s has made the list anonymous. {%s}", conn.username, lists[l].listname), conn, S_LISTANON);
end;
saveLists();
end;
function listUnanonymous(conn, list)
local l = strlower(list);
local l, err = listByName(conn, l, 1);
if (not l) then
send(err, conn, S_ERROR);
return nil;
end;
if (not (conn.privs and strfind(conn.privs, "M", 1, 1))) then
send("Only masters can do that.", conn, S_ERROR);
return nil;
end;
if (not strfind(lists[l].flags, "A", 1, 1)) then
send("That list isn't anonymous!", conn, S_ERROR);
return nil;
end;
lists[l].flags = gsub(lists[l].flags, "A", "");
sendTo(format("%s has made the list non-anonymous. {%s}", conn.username, lists[l].listname), getListMembers(l), S_LISTUNANON);
if (not listIsMember(conn.realUser, l, 1)) then
send(format("%s has made the list non-anonymous. {%s}", conn.username, lists[l].listname), conn, S_LISTUNANON);
end;
saveLists();
end;
function listReadOnly(conn, list)
local l = strlower(list);
local l, err = listByName(conn, l, 1);
if (not l) then
send(err, conn, S_ERROR);
return nil;
end;
if not isListMaster(l, conn.realUser) then
send("You cannot make a list read-only that you are not a master of.", conn, S_ERROR);
return nil;
end;
if (strfind(lists[l].flags, "R", 1, 1)) then
send("That list is already read-only!", conn, S_ERROR);
return nil;
end;
lists[l].flags = lists[l].flags .. "R";
sendTo(format("%s has made the list read-only. {%s}", conn.username, lists[l].listname), getListMembers(l), S_LISTREAD);
if (not listIsMember(conn.realUser, l, 1)) then
send(format("%s has made the list read-only. {%s}", conn.username, lists[l].listname), conn, S_LISTREAD);
end;
saveLists();
end;
function listReadWrite(conn, list)
local l = strlower(list);
local l, err = listByName(conn, l, 1);
if (not l) then
send(err, conn, S_ERROR);
return nil;
end;
if not isListMaster(l, conn.realUser) then
send("You cannot make a list read-write that you are not a master of.", conn, S_ERROR);
return nil;
end;
if (not strfind(lists[l].flags, "R", 1, 1)) then
send("That list isn't read-only!", conn, S_ERROR);
return nil;
end;
lists[l].flags = gsub(lists[l].flags, "R", "");
sendTo(format("%s has made the list read-write. {%s}", conn.username, lists[l].listname), getListMembers(l), S_LISTUNREAD);
if (not listIsMember(conn.realUser, l, 1)) then
send(format("%s has made the list read-write. {%s}", conn.username, lists[l].listname), conn, S_LISTUNREAD);
end;
saveLists();
end;
function listClose(conn, list)
local l = strlower(list);
local l, err = listByName(conn, l, 1);
if (not l) then
send(err, conn, S_ERROR);
return nil;
end;
if not isListMaster(l, conn.realUser) then
send("You cannot close a list that you are not a master of.", conn, S_ERROR);
return nil;
end;
if (not strfind(lists[l].flags, "O", 1, 1)) then
send("That list is already closed!", conn, S_ERROR);
return nil;
end;
lists[l].flags = gsub(lists[l].flags, "O", "");
sendTo(format("%s has closed the list. {%s}", conn.username, lists[l].listname), getListMembers(l), S_LISTCLOSE);
if (not listIsMember(conn.realUser, l, 1)) then
send(format("%s has closed the list. {%s}", conn.username, lists[l].listname), conn, S_LISTCLOSE);
end;
saveLists();
end;
function listPause(conn, list)
if (not list) then
if (not conn.pausedLists) then
send("You have no paused lists.", conn, S_DONE);
return nil;
else
send("Paused lists: " .. conn.pausedLists, conn, S_DONE);
end;
return nil;
end;
local llist = strlower(list);
local rlist, err = listByName(conn, list);
if (not rlist) then
send(err, conn, S_ERROR);
return nil;
end;
if (not listIsMember(conn.realUser, rlist)) then
send("You cannot pause lists you are not a member of.", conn, S_ERROR);
return nil;
end;
rlist = lists[rlist].listname;
if (conn.pausedLists and strfind(conn.pausedLists, rlist .. " ", 1, 1)) then
send("You already have that list paused!", conn, S_ERROR);
return nil;
end;
if (not conn.pausedLists) then
conn.pausedLists = "";
end;
conn.pausedLists = conn.pausedLists .. rlist .. " ";
send("Paused list " .. rlist .. ".", conn, S_DONE);
end;
function listUnpause(conn, list)
if (not list) then
if (not conn.pausedLists) then
send("You have no paused lists.", conn, S_DONE);
return nil;
else
send("Paused lists: " .. conn.pausedLists, conn, S_DONE);
end;
return nil;
end;
local llist = strlower(list);
local rlist, err = listByName(conn, list);
if (not rlist) then
send(err, conn, S_ERROR);
return nil;
end;
if (not listIsMember(conn.realUser, rlist)) then
send("You cannot unpause lists you are not a member of.", conn, S_ERROR);
return nil;
end;
rlist = lists[rlist].listname;
if (not conn.pausedLists or not strfind(conn.pausedLists, rlist .. " ", 1, 1)) then
send("You do not have that list paused!", conn, S_ERROR);
return nil;
end;
conn.pausedLists = gsub(conn.pausedLists, rlist .. " ", "");
if (conn.pausedLists == "") then
conn.pausedLists = nil;
end;
send("Unpaused list " .. rlist .. ".", conn, S_DONE);
end;
function listRename(conn, oldName, newName)
if (oldName == nil or newName == nil) then
send("Usage: .List Rename <list> <newname>", conn, S_ERROR);
return nil;
end;
local oldName = strlower(oldName);
local l, err = listByName(conn, oldName, 1);
if (not l) then
send(err, conn, S_ERROR);
return nil;
end;
oldName = strlower(l)
if not isListMaster(l, conn.realUser) then
send("You cannot rename a list that you are not a master of.", conn, S_ERROR);
return nil;
end;
if (lists[strlower(newName)]) then
send("There is already a list with that name.", conn, S_ERROR);
return nil;
end;
sendTo(format("%s has renamed %%%s to %%%s. {%s}", conn.username, lists[oldName].listname, newName, newName), getListMembers(oldName), S_LISTRENAME);
if (not listIsMember(conn.realUser, l, 1)) then
send(format("%s has renamed %%%s to %%%s. {%s}", conn.username, lists[oldName].listname, newName, newName), conn, S_LISTRENAME);
end;
lists[strlower(newName)] = lists[oldName];
lists[oldName] = nil;
lists[strlower(newName)].listname = newName;
saveLists();
end;
function listMaster(conn, list, user)
local l, err = listByName(conn, list, 1);
if (not l) then
send(err, conn, S_ERROR);
return nil;
end;
if not isListMaster(l, conn.realUser) then
send("You cannot make somebody a master on a list you are not a master of.", conn, S_ERROR);
return nil;
end;
local m, i, v;
m = userByName(user);
if (m == nil) then
send("No such user.", conn, S_ERROR);
return nil;
end;
if (type(m) == "string") then
send(m, conn, S_ERROR);
return nil;
end;
local mm = strlower(m.username);
if isListMaster(l, m.realUser) then
send(format("%s is already a master of that list.", m.username), conn, S_ERROR);
return nil;
end;
if not listIsMember(m.realUser, l) then
send(format("%s is not on that list.", m.username), conn, S_ERROR);
return nil;
end
if not lists[l].masters then
lists[l].masters = {};
end;
tinsert(lists[l].masters, strlower(m.realUser));
sendTo(format("%s has made %s a list master. {%s}", conn.username, m.username, lists[l].listname), getListMembers(l), S_LISTMASTER);
if not listIsMember(conn.realUser, l, 1) then
send(format("%s has made %s a list master. {%s}", conn.username, m.username, lists[l].listname), conn, S_LISTMASTER);
end;
saveLists();
end;
function listUnmaster(conn, list, user)
local l, err = listByName(conn, list, 1);
if (not l) then
send(err, conn, S_ERROR);
return nil;
end;
if not isListMaster(l, conn.realUser) then
send("You cannot unmaster somebody on a list you are not a master of.", conn, S_ERROR);
return nil;
end;
local m, i, v;
m = userByName(user);
if (m == nil) then
send("No such user.", conn, S_ERROR);
return nil;
end;
if (type(m) == "string") then
send(m, conn, S_ERROR);
return nil;
end;
local mm = strlower(m.username);
if not isListMaster(l, m.realUser) then
send(format("%s is not a master of that list.", m.username), conn, S_ERROR);
return nil;
end;
if not listIsMember(m.realUser, l) then
send(format("%s is not on that list.", m.username), conn, S_ERROR);
return nil;
end
for i, v in lists[l].masters or {} do
if v == strlower(m.realUser) then
tremove(lists[l].masters, i);
break;
end;
end;
sendTo(format("%s has unmastered %s. {%s}", conn.username, m.username, lists[l].listname), getListMembers(l), S_LISTMASTER);
if not listIsMember(conn.realUser, l, 1) then
send(format("%s has unmastered %s. {%s}", conn.username, m.username, lists[l].listname), conn, S_LISTMASTER);
end;
saveLists();
end;
function listHasPaused(conn, list)
if (conn.pausedLists) then
return strfind(conn.pausedLists, lists[strlower(list)].listname .. " ", 1, 1);
else
return nil;
end;
end;
function saveLists()
local f = openfile(colloquy.listsFile, "w");
local i, v;
write(f, "lists = {\n");
for i, v in lists do
if (type(v) == "table") then
write(f, " ['" .. i .. "'] = {\n");
write(f, ' listname = "' .. v.listname .. '",\n');
write(f, ' description = ' .. format("%q", v.description) .. ',\n');
write(f, ' flags = "' .. v.flags .. '",\n');
write(f, ' owner = "' .. v.owner .. '",\n');
write(f, ' created = "' .. v.created .. '",\n');
write(f, ' used = ' .. (v.used or secs) .. ',\n');
write(f, ' members = {\n');
local j;
for j = 1,getn(v.members) do
write(f, ' "' .. v.members[j] .. '"');
if (j ~= getn(v.members)) then
write(f, ",\n");
end;
end;
write(f, '\n },\n');
write(f, ' masters = {\n');
for j = 1,getn(v.masters or {}) do
write(f, ' "' .. v.masters[j] .. '"');
if (j ~= getn(v.masters)) then
write(f, ",\n");
end;
end;
write(f, '\n },\n');
write(f, ' },\n');
end;
end;
write(f, "};\n");
closefile(f);
end;