This commit is contained in:
BuckarooBanzay 2023-03-28 15:28:38 +02:00 committed by Athozus
parent 8ce3dc2ecf
commit dff068d75b
No known key found for this signature in database
GPG key ID: B50895022E8484BF
7 changed files with 91 additions and 139 deletions

53
api.lua
View file

@ -10,36 +10,15 @@ end
mail.receive_mail_message = "You have a new message from %s! Subject: %s\nTo view it, type /mail" mail.receive_mail_message = "You have a new message from %s! Subject: %s\nTo view it, type /mail"
mail.read_later_message = "You can read your messages later by using the /mail command" mail.read_later_message = "You can read your messages later by using the /mail command"
--[[ function mail.send(m)
mail sending function, can be invoked with one object argument (new api) or if type(m.from) ~= "string" then return false, "'from' is not a string" end
all 4 parameters (old compat version) if type(m.to) ~= "string" then return false, "'to' is not a string" end
see: "Mail format" api.md if type(m.body) ~= "string" then return false, "'body' is not a string" end
TODO: refactor this garbage code! -- defaults
--]] m.subject = m.subject or "(No subject)"
function mail.send(...)
-- figure out format
local m
if #{...} == 1 then
-- new format (one table param)
m = ...
-- populate "to" field
m.to = m.to or m.dst
-- populate "from" field
m.from = m.from or m.src
else
-- old format
m = {}
m.from, m.to, m.subject, m.body = ...
end
-- sane default values -- limit subject line
m.subject = m.subject or ""
m.body = m.body or ""
if m.subject == "" then
m.subject = "(No subject)"
end
if string.len(m.subject) > 30 then if string.len(m.subject) > 30 then
m.subject = string.sub(m.subject,1,27) .. "..." m.subject = string.sub(m.subject,1,27) .. "..."
end end
@ -63,9 +42,7 @@ function mail.send(...)
for name in pairs(undeliverable) do for name in pairs(undeliverable) do
undeliverable_names[#undeliverable_names + 1] = '"' .. name .. '"' undeliverable_names[#undeliverable_names + 1] = '"' .. name .. '"'
end end
return f("recipients %s don't exist; cannot send mail.", return false, f("recipients %s don't exist; cannot send mail.", table.concat(undeliverable_names, ", "))
table.concat(undeliverable_names, ", ")
)
end end
local extra = {} local extra = {}
@ -89,13 +66,13 @@ function mail.send(...)
-- form the actual mail -- form the actual mail
local msg = { local msg = {
id = mail.new_uuid(), id = mail.new_uuid(),
sender = m.from, from = m.from,
to = m.to, to = m.to,
cc = m.cc, cc = m.cc,
bcc = m.bcc, bcc = m.bcc,
subject = m.subject, subject = m.subject,
body = m.body, body = m.body,
time = os.time(), time = os.time(),
} }
-- add in senders outbox -- add in senders outbox
@ -124,4 +101,6 @@ function mail.send(...)
break break
end end
end end
return true
end end

113
api.md
View file

@ -9,47 +9,28 @@ mail = {
cc = "carbon copy", cc = "carbon copy",
bcc = "players, which, get, a, copy, but, are, not, visible, to, others", bcc = "players, which, get, a, copy, but, are, not, visible, to, others",
subject = "subject line", subject = "subject line",
body = "mail body", body = "mail body"
-- 8 attachments max
attachments = {"default:stone 99", "default:gold_ingot 99"}
} }
``` ```
The fields `to`, `cc` and `bcc` can contain a player, multiple player names separated by commas, or be empty. Players in `to` are the recipiants, who are addressed directly. `cc` specifies players that get the mail to get notified, but are not immediate part of the conversation. There is no technical difference between `to` and `cc`, it just implies meaning for the players. Players can see all fields making up the mail except `bcc`, which is the only difference to `cc`. The fields `to`, `cc` and `bcc` can contain a player, multiple player names separated by commas, or be empty.
Players in `to` are the recipiants, who are addressed directly. `cc` specifies players that get the mail to get notified, but are not immediate part of the conversation.
Attachments need to be provided for each player getting the mail. Until this is implemented, trying to send a mail to multiple players will fail. There is no technical difference between `to` and `cc`, it just implies meaning for the players.
Players can see all fields making up the mail except `bcc`, which is the only difference to `cc`.
The `from` and `to` fields were renamed from the previous format:
```lua
mail = {
src = "source name",
dst = "destination name",
subject = "subject line",
body = "mail body",
-- 8 attachments max
attachments = {"default:stone 99", "default:gold_ingot 99"}
}
```
## Sending mail ## Sending mail
Old variant (pre-1.1)
```lua
local error = mail.send("source name", "destination name", "subject line", "mail body")
-- error will contain an error message if mail couldn't be delivered, otherwise nil
```
New variant (1.1+)
```lua ```lua
local error = mail.send({ local success, error = mail.send({
from = "sender name", from = "singleplayer",
to = "destination name", to = "playername",
cc = "carbon copy", cc = "carbon, copy",
bcc = "blind carbon copy", bcc = "blind, carbon, copy",
subject = "subject line", subject = "subject line",
body = "mail body" body = "mail body"
}) })
-- error will contain an error message if mail couldn't be delivered, otherwise nil
-- if "success" is false the error parameter will contain a message
``` ```
# Hooks # Hooks
@ -61,22 +42,56 @@ mail.register_on_receive(function(m)
end) end)
``` ```
# internal mail format (on-disk) # Internals
The mail format on-disk
> (worldfolder)/mails/(playername).json mod-storage entry for a player (indexed by playername and serialized with json):
```lua
```json {
[{ contacts = {
"unread": true, {
"sender": "sender name", -- name of the player (unique key in the list)
"subject": "subject name", name = "",
"body": "main\nmultiline\nbody", -- note
"time": 1551258349, note = ""
"attachments": [ },{
"default:stone 99", ...
"default:gold_ingot 99" }
] },
}] inbox = {
{
``` -- globally unique mail id
id = "d6cce35c-487a-458f-bab2-9032c2621f38",
-- sending player name
from = "",
-- receiving player name
to = "",
-- carbon copy (optional)
cc = "playername, playername2",
-- blind carbon copy (optional)
bcc = "",
-- mail subject
subject = "",
-- mail body
body = "",
-- timestamp (os.time())
time = 1234,
-- read-flag (true: player has read the mail, inbox only)
read = true
},{
...
}
},
outbox = {
-- same format as "inbox"
},
lists = {
{
-- name of the maillist (unique key in the list)
name = "",
-- description
description = "",
-- playername list
players = {"playername", "playername2"}
}
}
}

View file

@ -41,7 +41,7 @@ function mail.migrate_v2_to_v3()
if msg.to then if msg.to then
table.insert(entry.inbox, { table.insert(entry.inbox, {
id = mail.new_uuid(), id = mail.new_uuid(),
sender = msg.sender, from = msg.sender or msg.from,
to = msg.to, to = msg.to,
cc = msg.cc, cc = msg.cc,
subject = msg.subject, subject = msg.subject,

View file

@ -4,7 +4,9 @@ mtt.register("send mail", function(callback)
auth_handler.set_password("player2", "") auth_handler.set_password("player2", "")
-- send a mail -- send a mail
mail.send({from = "player1", to = "player2", subject = "something", body = "blah"}) local success, err = mail.send({from = "player1", to = "player2", subject = "something", body = "blah"})
assert(success)
assert(not err)
-- check the receivers inbox -- check the receivers inbox
local entry = mail.get_storage_entry("player2") local entry = mail.get_storage_entry("player2")

View file

@ -1,3 +1,5 @@
-- storage getter/setter
function mail.get_storage_entry(playername) function mail.get_storage_entry(playername)
local str = mail.storage:get_string(playername) local str = mail.storage:get_string(playername)
if str == "" then if str == "" then
@ -14,52 +16,6 @@ function mail.get_storage_entry(playername)
end end
end end
--[[
Mail format (inbox, outbox):
table of: {
-- globally unique mail id
id = "d6cce35c-487a-458f-bab2-9032c2621f38",
-- sending player name
sender = "",
-- receiving player name
to = "",
-- carbon copy (optional)
cc = "",
-- blind carbon copy (optional)
bcc = "",
-- mail subject
subject = "",
-- mail body
body = "",
-- timestamp (os.time())
time = 1234,
-- read-flag (true: player has read the mail, inbox only)
read = true
}
Contact format:
table of: {
-- name of the player (unique key in the list)
name = "",
-- note
note = ""
}
Mail-list format:
table of: {
-- name of the maillist (unique key in the list)
name = "",
-- description
description = "",
-- playername list
players = {"playername", "playername2"}
}
--]]
function mail.set_storage_entry(playername, entry) function mail.set_storage_entry(playername, entry)
mail.storage:get_string(playername, minetest.write_json(entry)) mail.storage:get_string(playername, minetest.write_json(entry))
end end

View file

@ -42,7 +42,7 @@ function mail.show_inbox(name)
end end
end end
formspec[#formspec + 1] = "," formspec[#formspec + 1] = ","
formspec[#formspec + 1] = minetest.formspec_escape(message.sender) formspec[#formspec + 1] = minetest.formspec_escape(message.from)
formspec[#formspec + 1] = "," formspec[#formspec + 1] = ","
if message.subject ~= "" then if message.subject ~= "" then
if string.len(message.subject) > 30 then if string.len(message.subject) > 30 then

View file

@ -24,7 +24,7 @@ function mail.show_message(name, id)
button[6,8.5;2,1;delete;Delete] button[6,8.5;2,1;delete;Delete]
]] .. mail.theme ]] .. mail.theme
local from = minetest.formspec_escape(message.sender) or "" local from = minetest.formspec_escape(message.from) or ""
local to = minetest.formspec_escape(message.to) or "" local to = minetest.formspec_escape(message.to) or ""
local cc = minetest.formspec_escape(message.cc) or "" local cc = minetest.formspec_escape(message.cc) or ""
local date = type(message.time) == "number" local date = type(message.time) == "number"
@ -43,7 +43,7 @@ end
function mail.reply(name, message) function mail.reply(name, message)
local replyfooter = "Type your reply here.\n\n--Original message follows--\n" ..message.body local replyfooter = "Type your reply here.\n\n--Original message follows--\n" ..message.body
mail.show_compose(name, message.sender, "Re: "..message.subject, replyfooter) mail.show_compose(name, message.from, "Re: "..message.subject, replyfooter)
end end
function mail.replyall(name, message) function mail.replyall(name, message)
@ -51,8 +51,8 @@ function mail.replyall(name, message)
-- new recipients are the sender plus the original recipients, minus ourselves -- new recipients are the sender plus the original recipients, minus ourselves
local recipients = message.to or "" local recipients = message.to or ""
if message.sender ~= nil then if message.from ~= nil then
recipients = message.sender .. ", " .. recipients recipients = message.from .. ", " .. recipients
end end
recipients = mail.parse_player_list(recipients) recipients = mail.parse_player_list(recipients)
for k,v in pairs(recipients) do for k,v in pairs(recipients) do