colloquy-1.35.30/
colloquy-1.35.30/data/lang/
colloquy-1.35.30/data/misc/
colloquy-1.35.30/docs/
-- stuff to handle users

users = {
   god = {
      password = "a4757d7419ff3b48e92e90596f0e7548", -- god's default password is "god"
      privs = "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
      site = "",
      talktime = 0,
   }
}

-- the users table is keyed by lower-case username.  The values are
-- a table describing that user, in the following form:
--  .password  = [string] an md5 hash of their password
--  .password2 = [string] new style password - md5 of their username concatenated with their password
--  .privs     = [string] a list of the user's priviledges.
--  .site      = [string] site the user last connected from
--  .talktime  = [number] how many minutes the user has been connected
--  .name      = [string] real name of the user
--  .birthday  = [string] date of birth in ISO format
--  .location  = [string] where the user is based
--  .homepage  = [string] url to user's homepage
--  .email     = [string] user's email address
--  .sex       = [stirng] male/female/etc
--  .around    = [string] when the user is next around
--  .restrict  = [string] list of restrictions (eg, G)
--  .timeon    = [number] seconds of online time.
--  .connected = [number] time of their connection, if they're connected now, otherwise nil.

function escapeUserData(data)
  -- does stuff to a string so it can be safely saved...
  -- strings are assumed to only be sensitive to the double quote chartacter.
  local p, l = 1;
  local r = '" .. strchar(34) .. "';
  local rl = strlen(r);
  local dl = 0;

  repeat
    l = strfind(data, '"', p, 1);
    if (l) then
      data = strsub(data, 1, l - 1) .. r .. strsub(data, l + 1, - 1);
      p = l + rl;
      dl = strlen(data);
    end;
  until l == nil or p > dl

  return data;
end;

function saveUsers(filename)
   -- dumps the users table to file in an executable form
   
   local f;

   if (filename ~= "dump") then 
      f = openfile(filename, "w");
   else
      f = "(dump) ";
   end;

   local indent = 0;
   
   write(f, "users = ");
   saveTable(users, f, indent);

   if (f ~= "(dump) ") then closefile(f) end;
end;

function saveTable(table, f, indent)
   local i, v;

   write(f, "{\n"); indent = indent + 2;

   for i, v in table do
      if (i ~= "n") then
         write(f, strrep(" ", indent) .. i .. " = {\n"); indent = indent + 2;
         local j, k, t;
         for j, k in v do
            if (j ~= "n" and j ~= "connected") then
               write(f, strrep(" ", indent) .. j .. " = ");
               t = type(k);
               if     (t == "string") then 
                 k = format("%q", k);
                 write(f, k, ",", "\n");
               elseif (t == "number") then write(f, k .. ",\n");
               elseif (t == "table")  then saveTable(k, f, indent);
               end;
            end;
         end;
         indent = indent - 2; write(f, strrep(" ", indent) .. "},\n");
      end;
   end;

   write(f, "}\n");

end;

function loadUsers(filename)
   dofile(filename);
end;

function checkPasswordWithAuthenticator(authenticator, user, password)
  local null, null, rUser, host, port = strfind(authenticator, "^([^%@]-)%@([^%:]-):(.-)$");
  if (not null) then
    return nil, "Invalid authenticator field.";
  end;
  local s = connect(host, port);
  if (not s) then
    return nil, "Unable to connect to authenticator.";
  end;
  s:send(format("auth %s %s\n", rUser, password));
  local r = s:receive("*l");
  s:close();
  if (not r) then
    return nil, "Unable to get response from authenticator.";
  end;
  local null, null, code, message = strfind(r, "^auth (.-) (.-)$");
  if (not null) then
    return nil, "Invalid response from authenticator.";
  end;
  if (code == "1") then
    return 1, message;
  else
    return nil, message;
  end;
end;

function checkPassword(user, password)
  user = strlower(user);
  if (users[user].authenticator) then
    -- they have an authenticator!
    return checkPasswordWithAuthenticator(users[user].authenticator, user, password);
  elseif (users[user].password2) then
    -- they have a new-style password
    if (users[user].password2 == crypt(user .. password)) then
      return 1, "";
    else
      return nil, "Incorrect password.";
    end;
  else
    -- they have an old-style password.  Check it, if it's correct,
    -- generate a password2 from it, and delete the old one.
    if (users[user].password == crypt(password)) then
      users[user].password2 = crypt(user .. password);
      users[user].password = nil;
      return 1, "";
    else
      return nil, "Incorrect password.";
    end;
  end
end;

function changePassword(user, old, new)

  user = strlower(user);
  if (users[user].authenticator) then
    local null, null, rUser, host, port = strfind(users[user].authenticator, "^([^%@]-)%@([^%:]-):(.-)$");
    if (not null) then
      return nil, "Invalid authenticator field.";
    end;
    local s = connect(host, port);
    if (not s) then
      return nil, "Unable to connect to authenticator.";
    end;
    s:send(format("pass %s %s %s\n", rUser, old, new));
    local r = s:receive("*l");
    s:close();
    if (not r) then
      return nil, "Unable to get response from authenticator.";
    end;
    local null, null, code, message = strfind(r, "^pass (.-) (.-)$");
    if (not null) then
      return nil, "Invalid response from authenticator.";
    end;
    if (code == "1") then
      return 1, message;
    else
      return nil, message;
    end;
  else
    local pr, message = checkPassword(user, old);
    if (not pr) then
       return nil, (message or "Incorrect old password");
    end;
 
    users[user].password2 = crypt(user .. new);
    users[user].password = nil;
    saveUsers(colloquy.users);

    return 1, "Password changed.";
  end;
end;