mirror of
https://github.com/mt-mods/mail.git
synced 2025-04-30 08:21:44 -04:00
Compare commits
136 commits
Author | SHA1 | Date | |
---|---|---|---|
|
f7cc435f6b | ||
|
9fe6885f90 | ||
|
1cc18b840c | ||
|
87b24bae5d | ||
|
0d8f7cc445 | ||
|
030a7a3fe8 | ||
|
8a992b7a29 | ||
|
1bffd98132 | ||
|
59667bd35c | ||
|
09b233b039 | ||
|
b9982f11e6 | ||
|
4f15c2fe65 | ||
|
4cd06c5f5f | ||
|
036d37695a | ||
|
5cfec3a92a | ||
|
a347a79e6a | ||
|
48b632fba2 | ||
|
2938b74039 | ||
|
ed6f36ab6d | ||
|
1dab26f0bf | ||
|
9a52c1c181 | ||
|
19be2d46a2 | ||
|
dc9c4f86b7 | ||
|
1f208c6a21 | ||
|
30b9a0fba4 | ||
|
dfaa34c8c5 | ||
|
a3af9ee389 | ||
|
fc7b438de3 | ||
|
c6d8543c85 | ||
|
3670fe79cc | ||
|
f57473abd0 | ||
|
e516fe04c4 | ||
|
1dde4097f9 | ||
|
ccf07b50e2 | ||
|
1c5e4b6cd6 | ||
|
6f7ccc77bd | ||
|
163467379f | ||
|
2694ffa2dc | ||
|
851fa9f12a | ||
|
1eb3b7668d | ||
|
ea7773730e | ||
|
0e06718a51 | ||
|
ae238ba143 | ||
|
570cf788ec | ||
|
fcca0b7511 | ||
|
c5fd218415 | ||
|
103c4ae441 | ||
|
e45d56439f | ||
|
cd9e9ec8e1 | ||
|
48fc8470f5 | ||
|
bfe0ef2711 | ||
|
75510d2551 | ||
|
83842a8861 | ||
|
aab7acf2b5 | ||
|
46012a2b28 | ||
|
721d882c26 | ||
|
94f37da092 | ||
|
3eafeb4cf8 | ||
|
8d80e4c709 | ||
|
720315a22c | ||
|
77de24e467 | ||
|
3bad371353 | ||
|
802f9f727b | ||
|
bebb7a8702 | ||
|
8137e9405d | ||
|
2111db2ff9 | ||
|
f8f500ed76 | ||
|
7754e7e361 | ||
|
80ae9c3342 | ||
|
8d7c8c63cf | ||
|
88a276f4cb | ||
|
e5996469fb | ||
|
fe533eeb4d | ||
|
2a18322cdb | ||
|
7ae5bda5ab | ||
|
a9a4c8c4dc | ||
|
9990d56004 | ||
|
9c041f5905 | ||
|
b4ccc168c6 | ||
|
67108c6771 | ||
|
09791d58a7 | ||
|
a6f16c847e | ||
|
f171a3d50a | ||
|
be8f0e590f | ||
|
db2434c8f9 | ||
|
0248b051ef | ||
|
e038993f27 | ||
|
37fad48ec8 | ||
|
fbdaaeec11 | ||
|
fe9aca40f0 | ||
|
e470c58d83 | ||
|
c98cb401d8 | ||
|
d09fafc563 | ||
|
67cbef88f7 | ||
|
8917fd0b39 | ||
|
95475c7c59 | ||
|
f5198b9187 | ||
|
8c20aeba5b | ||
|
984d8c34d9 | ||
|
968f402566 | ||
|
bfd3692280 | ||
|
8dadd8043c | ||
|
d53b07451c | ||
|
65764ee318 | ||
|
c6d8f8a069 | ||
|
31645f263b | ||
|
2e106e3df7 | ||
|
de07f6b24b | ||
|
42db40b7a7 | ||
|
fab6f1a1e5 | ||
|
660d460af2 | ||
|
c655ff32e2 | ||
|
7822ff3038 | ||
|
869cc2bbc3 | ||
|
5605b07e30 | ||
|
5e24b9274f | ||
|
9679251249 | ||
|
f8ace25104 | ||
|
02853fc3d0 | ||
|
8dcfc7dc77 | ||
|
2f01739d35 | ||
|
955f7d123f | ||
|
a79ebd94b8 | ||
|
f70ce537a7 | ||
|
5e3cfedc5e | ||
|
95ab299016 | ||
|
720029a73e | ||
|
a8632255b3 | ||
|
c670d48622 | ||
|
ec92aaba05 | ||
|
47b18f2138 | ||
|
7449aaca52 | ||
|
1a84c66346 | ||
|
fc90443952 | ||
|
2290c2838e | ||
|
ed3c8b97a1 |
63 changed files with 3517 additions and 815 deletions
5
.gitattributes
vendored
Normal file
5
.gitattributes
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
mtt.lua export-ignore
|
||||||
|
docker-compose.yml export-ignore
|
||||||
|
*.spec.lua export-ignore
|
||||||
|
test/* export-ignore
|
||||||
|
screenshot_* export-ignore
|
17
.github/workflows/luacheck.yml
vendored
17
.github/workflows/luacheck.yml
vendored
|
@ -1,17 +1,10 @@
|
||||||
name: luacheck
|
name: luacheck
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
luacheck:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- name: Checkout
|
||||||
- name: apt
|
uses: actions/checkout@master
|
||||||
run: sudo apt-get install -y luarocks
|
- name: Luacheck
|
||||||
- name: luacheck install
|
uses: lunarmodules/luacheck@master
|
||||||
run: luarocks install --local luacheck
|
|
||||||
- name: luacheck run
|
|
||||||
run: $HOME/.luarocks/bin/luacheck ./
|
|
||||||
|
|
6
.github/workflows/test.yml
vendored
6
.github/workflows/test.yml
vendored
|
@ -9,9 +9,9 @@ jobs:
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
ENGINE_VERSION: [5.0.0, 5.1.0, 5.2.0, 5.3.0, 5.4.0, 5.5.0, 5.6.0, 5.6.1, latest]
|
ENGINE_VERSION: [5.0.1, 5.1.1, 5.2.0, 5.3.0, 5.4.1, 5.5.1, 5.6.1, 5.7.0, 5.8.0, 5.9.1, 5.10.0, latest]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: test
|
- name: test
|
||||||
run: docker-compose up --exit-code-from sut
|
run: docker compose up --exit-code-from sut
|
||||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,2 +1,4 @@
|
||||||
i18n.py
|
i18n.py
|
||||||
|
mod_translation_updater.py
|
||||||
locale/*.tr.old
|
locale/*.tr.old
|
||||||
|
*.patch
|
||||||
|
|
|
@ -5,15 +5,16 @@ globals = {
|
||||||
read_globals = {
|
read_globals = {
|
||||||
-- Stdlib
|
-- Stdlib
|
||||||
string = {fields = {"split"}},
|
string = {fields = {"split"}},
|
||||||
table = {fields = {"copy", "getn"}},
|
table = {fields = {"copy", "getn", "indexof", "insert_all"}},
|
||||||
|
beerchat = {fields = {"has_player_muted_player", "execute_callbacks"}},
|
||||||
|
|
||||||
-- Minetest
|
-- Luanti
|
||||||
"minetest",
|
"core",
|
||||||
"vector", "ItemStack",
|
"vector", "ItemStack",
|
||||||
"dump",
|
"dump",
|
||||||
|
|
||||||
-- Deps
|
-- Deps
|
||||||
"unified_inventory", "default",
|
"unified_inventory", "default", "sfinv_buttons",
|
||||||
|
|
||||||
-- optional mods
|
-- optional mods
|
||||||
"mtt", "canonical_name"
|
"mtt", "canonical_name"
|
||||||
|
|
78
README.md
78
README.md
|
@ -5,37 +5,58 @@ Mail mod for Minetest (ingame mod)
|
||||||

|

|
||||||
[](https://content.minetest.net/packages/mt-mods/mail/)
|
[](https://content.minetest.net/packages/mt-mods/mail/)
|
||||||
|
|
||||||
This is a fork of cheapies mail mod
|
This is a fork of @cheapie's mail mod.
|
||||||
|
|
||||||
It adds a mail-system that allows players to send each other messages in-game and via webmail (optional)
|
It adds a mail-system that allows players to send each other messages in-game and via webmail (optional).
|
||||||
|
|
||||||
# Screenshot
|
# Screenshot
|
||||||
|
|
||||||

|

|
||||||
|

|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
## In-game mail mod
|
## In-game mail mod
|
||||||
|
|
||||||
Install it like any other mod: copy the directory `mail_mod` to your "worldmods" folder or use the [contentdb](https://content.minetest.net)
|
Install it like any other mod: copy the directory `mail_mod` to your "worldmods" folder or use the [ContentDB](https://content.minetest.net)
|
||||||
|
|
||||||
## Webmail
|
## Webmail
|
||||||
|
|
||||||
To provide a web-based interface to receive/send mails you can use the [mtui](https://github.com/minetest-go/mtui) project
|
To provide a web-based interface to receive/send mails you can use the [mtui](https://github.com/minetest-go/mtui) project.
|
||||||
|
|
||||||
# Commands/Howto
|
# Commands/Howto
|
||||||
|
|
||||||
To access your mail click on the inventory mail button or use the "/mail" command
|
To access your mail type `/mail` command or click on the mail button in your inventory (`unified_inventory`).
|
||||||
Mails can be deleted, marked as read or unread, replied to and forwarded to another player
|
|
||||||
|
Mails can be deleted, marked as read or unread, replied to and forwarded to another player. You can also manage your contacts and your mailing lists.
|
||||||
|
|
||||||
|
# Features
|
||||||
|
|
||||||
|
* Inbox page
|
||||||
|
* Outbox page
|
||||||
|
* Saved drafts
|
||||||
|
* Read/unread marks
|
||||||
|
* To/Cc/Bcc system
|
||||||
|
* Intuitive UI
|
||||||
|
* Contacts book
|
||||||
|
* Mailing lists
|
||||||
|
* Sorters/filters (new in 1.1.0)
|
||||||
|
* Multiple selection (new in 1.1.0)
|
||||||
|
* Settings
|
||||||
|
* Chat, on join, HUD and sound notifications
|
||||||
|
* Anti-spam detection
|
||||||
|
* Translated in : English, French, German, Chinese (both traditional and simplified), Spanish, Brazilian Portuguese, Hungarian, Indonesian.
|
||||||
|
|
||||||
# Compatibility / Migration
|
# Compatibility / Migration
|
||||||
|
|
||||||
Overview:
|
Overview:
|
||||||
* `v1` all the data is in the `<worldfolder>/mails.db` file
|
* `v1` all the data is in the `<worldfolder>/mails.db` file
|
||||||
* `v2` every player has its own (in-) mailbox in the `<worldfolder>/mails/<playername>.json` file
|
* `v2` every player has its own (in-) mailbox in the `<worldfolder>/mails/<playername>.json` file
|
||||||
* `v3` every player has an entry in the `<playername>` modstorage (inbox, outbox, contacts)
|
* `v3` every player has an entry in the `<playername>` `mod_storage/` (inbox, outbox, drafts, contacts, mailing lists, settings)
|
||||||
|
* `v3.1` database fix after the message id mess
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
|
||||||
* None
|
* None
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
@ -45,34 +66,55 @@ See the "LICENSE" file
|
||||||
# Textures
|
# Textures
|
||||||
* textures/email_mail.png (https://github.com/rubenwardy/email.git WTFPL)
|
* textures/email_mail.png (https://github.com/rubenwardy/email.git WTFPL)
|
||||||
|
|
||||||
# Contributors
|
# Contributors / Credits
|
||||||
|
|
||||||
* Cheapie (Initial idea/project)
|
* Cheapie (Initial idea/project)
|
||||||
* Rubenwardy (Lua/UI improvements)
|
* Rubenwardy (Lua/UI improvements)
|
||||||
* BuckarooBanzay (Clean-ups, Refactoring)
|
* BuckarooBanzay (Clean-ups, Refactoring)
|
||||||
* Athozus (Outbox, Maillists, UI, Drafts)
|
* Athozus (Outbox, Maillists, UI, Drafts, Trash, Settings)
|
||||||
* SX (Various fixes, UI)
|
* SX (Various fixes, UI)
|
||||||
* fluxionary (Minor fixups)
|
* fluxionary (Minor fixups)
|
||||||
* Toby1710 (UX fixes)
|
* Toby1710 (UX fixes)
|
||||||
* Peter Nerlich (CC, BCC)
|
* Peter Nerlich (CC, BCC)
|
||||||
* Emojigit (Chinese translation)
|
* Emojigit (Performance, Traditional Chinese translation)
|
||||||
* Niklp09 (German translation)
|
* Niklp09 (German translation)
|
||||||
|
* Dennis Jenkins (UX fixes)
|
||||||
|
* Thomas Rudin (Maintenance)
|
||||||
|
* imre84 (UI fixes)
|
||||||
|
* Chache (Spanish translation)
|
||||||
|
* APercy (Brazilian Portuguese translation)
|
||||||
|
* Nuno Filipe Povoa (mail_notif.ogg - https://invent.kde.org/plasma/oxygen-sounds/-/blob/master/sounds/Oxygen-Im-Nudge.ogg)
|
||||||
|
* TheTrueBeginner (Simplified Chinese translation)
|
||||||
|
* nyomi (Hungarian translation)
|
||||||
|
* whosit (UI fixes)
|
||||||
|
* Wuzzy (German translation)
|
||||||
|
* savilli (UX fixes)
|
||||||
|
* Panquesito7 (Maintenance)
|
||||||
|
* Eredin (Spanish translation)
|
||||||
|
* Muhammad Rifqi Priyo Susanto (Indonesian translation)
|
||||||
|
* aBlueShadow (sfinv compatibility)
|
||||||
|
* Singularis (UX and storage fixes)
|
||||||
|
|
||||||
# Contribute
|
# Contribute
|
||||||
|
|
||||||
You can contribute by :
|
You can contribute by :
|
||||||
* Reporting an issue
|
* Reporting an issue : Go to the [Issues](https://github.com/mt-mods/mail/issues) tab, click on the button **New issue** and type a short title then give many informations (Minetest version, tab where the bug occured, steps to reproduce the crash, etc.)
|
||||||
* Give a review on Content DB
|
* Give a review on ContentDB : [Just write ;)](https://content.minetest.net/packages/mt-mods/mail/review/)
|
||||||
* Adding new features
|
* Requesting new features : [Open an issue](https://github.com/mt-mods/mail/issues) and indicate what you need more in details.
|
||||||
* Fixing an issue
|
* Adding those new features : [Open a pull request](https://github.com/mt-mods/mail/pulls), and if issue(s) are linked, ping them (#number).
|
||||||
* Translate into a new language
|
* Fixing an issue : Same as before, open a pull request.
|
||||||
* Add documentation
|
* Translate into a new language : copy `locale/template.txt` into `locale/mail.<codelang>.tr`, and add translated strings (syntax : `not translated=translated`). Then, open a pull request. We're also working on opening a [Weblate](https://weblate.org) (free web interface) to translate strings easier.
|
||||||
|
* Add documentation : adds `.md` (markdown) or `.txt` files and open a pull request.
|
||||||
* ...
|
* ...
|
||||||
|
|
||||||
You're encouraged to create a fork of this repo, then make your changes and create a pull request when it's done. If you do so, please also check "Git branches" section.
|
You're encouraged to create a fork of this repo, then make your changes and create a pull request when it's done. ~~If you do so, please also check "Git branches" section.~~ (obsolete). Request for merging into `master`, if needed we will push into another branch.
|
||||||
|
|
||||||
|
If you don't have a GitHub account, you can also contact maintainers to add manually your contributions.
|
||||||
|
|
||||||
# Git branches
|
# Git branches
|
||||||
|
|
||||||
|
***Caution : might be obsolete***
|
||||||
|
|
||||||
* master : main branch, where are pushed releases and tags
|
* master : main branch, where are pushed releases and tags
|
||||||
* dev : for new release works, A.B.C release to A.B+1.0
|
* dev : for new release works, A.B.C release to A.B+1.0
|
||||||
* A.B.X : for fix releases (no new features), A.B.C release to A.B.C+1
|
* A.B.X : for fix releases (no new features), A.B.C release to A.B.C+1
|
||||||
|
|
79
api.lua
79
api.lua
|
@ -1,5 +1,8 @@
|
||||||
-- see: mail.md
|
-- see: mail.md
|
||||||
|
|
||||||
|
-- translation
|
||||||
|
local S = mail.S
|
||||||
|
|
||||||
local f = string.format
|
local f = string.format
|
||||||
|
|
||||||
mail.registered_on_receives = {}
|
mail.registered_on_receives = {}
|
||||||
|
@ -7,42 +10,49 @@ function mail.register_on_receive(func)
|
||||||
mail.registered_on_receives[#mail.registered_on_receives + 1] = func
|
mail.registered_on_receives[#mail.registered_on_receives + 1] = func
|
||||||
end
|
end
|
||||||
|
|
||||||
mail.receive_mail_message = "You have a new message from %s! Subject: %s\nTo view it, type /mail"
|
mail.registered_on_player_receives = {}
|
||||||
mail.read_later_message = "You can read your messages later by using the /mail command"
|
function mail.register_on_player_receive(func)
|
||||||
|
table.insert(mail.registered_on_player_receives, func)
|
||||||
|
end
|
||||||
|
|
||||||
|
mail.registered_recipient_handlers = {}
|
||||||
|
function mail.register_recipient_handler(func)
|
||||||
|
table.insert(mail.registered_recipient_handlers, func)
|
||||||
|
end
|
||||||
|
|
||||||
function mail.send(m)
|
function mail.send(m)
|
||||||
if type(m.from) ~= "string" then return false, "'from' is not a string" end
|
if type(m.from) ~= "string" then return false, "'from' is not a string" end
|
||||||
if type(m.to) ~= "string" then return false, "'to' is not a string" end
|
if type(m.to or "") ~= "string" then return false, "'to' is not a string" end
|
||||||
|
if type(m.cc or "") ~= "string" then return false, "'cc' is not a string" end
|
||||||
|
if type(m.bcc or "") ~= "string" then return false, "'bcc' is not a string" end
|
||||||
|
if type(m.subject or "") ~= "string" then return false, "'subject' is not a string" end
|
||||||
if type(m.body) ~= "string" then return false, "'body' is not a string" end
|
if type(m.body) ~= "string" then return false, "'body' is not a string" end
|
||||||
|
|
||||||
-- defaults
|
-- defaults
|
||||||
m.subject = m.subject or "(No subject)"
|
m.subject = m.subject or "(No subject)"
|
||||||
|
|
||||||
-- limit subject line
|
|
||||||
if string.len(m.subject) > 30 then
|
|
||||||
m.subject = string.sub(m.subject,1,27) .. "..."
|
|
||||||
end
|
|
||||||
|
|
||||||
-- normalize to, cc and bcc while compiling a list of all recipients
|
-- normalize to, cc and bcc while compiling a list of all recipients
|
||||||
local recipients = {}
|
local recipients = {}
|
||||||
local undeliverable = {}
|
local undeliverable = {}
|
||||||
m.to = mail.concat_player_list(mail.extractMaillists(m.to, m.from))
|
m.to = mail.concat_player_list(mail.extract_maillists(m.to, m.from))
|
||||||
m.to = mail.normalize_players_and_add_recipients(m.to, recipients, undeliverable)
|
m.to = mail.normalize_players_and_add_recipients(m.from, m.to, recipients, undeliverable)
|
||||||
if m.cc then
|
if m.cc then
|
||||||
m.cc = mail.concat_player_list(mail.extractMaillists(m.cc, m.from))
|
m.cc = mail.concat_player_list(mail.extract_maillists(m.cc, m.from))
|
||||||
m.cc = mail.normalize_players_and_add_recipients(m.cc, recipients, undeliverable)
|
m.cc = mail.normalize_players_and_add_recipients(mail.from, m.cc, recipients, undeliverable)
|
||||||
end
|
end
|
||||||
if m.bcc then
|
if m.bcc then
|
||||||
m.bcc = mail.concat_player_list(mail.extractMaillists(m.bcc, m.from))
|
m.bcc = mail.concat_player_list(mail.extract_maillists(m.bcc, m.from))
|
||||||
m.bcc = mail.normalize_players_and_add_recipients(m.bcc, recipients, undeliverable)
|
m.bcc = mail.normalize_players_and_add_recipients(m.from, m.bcc, recipients, undeliverable)
|
||||||
end
|
end
|
||||||
|
|
||||||
if next(undeliverable) then -- table is not empty
|
if next(undeliverable) then -- table is not empty
|
||||||
local undeliverable_names = {}
|
local undeliverable_reason = {S("The mail could not be sent:")}
|
||||||
for name in pairs(undeliverable) do
|
for _, reason in pairs(undeliverable) do
|
||||||
undeliverable_names[#undeliverable_names + 1] = '"' .. name .. '"'
|
table.insert(undeliverable_reason, reason)
|
||||||
end
|
end
|
||||||
return false, f("recipients %s don't exist; cannot send mail.", table.concat(undeliverable_names, ", "))
|
return false, table.concat(undeliverable_reason, "\n")
|
||||||
|
elseif not next(recipients) then
|
||||||
|
return false, S("You did not specify any valid recipient.")
|
||||||
end
|
end
|
||||||
|
|
||||||
local extra = {}
|
local extra = {}
|
||||||
|
@ -59,7 +69,7 @@ function mail.send(m)
|
||||||
extra_log = ""
|
extra_log = ""
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.log("action", f("[mail] %q send mail to %q%s with subject %q and body %q",
|
core.log("action", f("[mail] %q send mail to %q%s with subject %q and body %q",
|
||||||
m.from, m.to, extra_log, m.subject, m.body
|
m.from, m.to, extra_log, m.subject, m.body
|
||||||
))
|
))
|
||||||
|
|
||||||
|
@ -85,24 +95,11 @@ function mail.send(m)
|
||||||
local entry = mail.get_storage_entry(m.from)
|
local entry = mail.get_storage_entry(m.from)
|
||||||
table.insert(entry.outbox, 1, msg)
|
table.insert(entry.outbox, 1, msg)
|
||||||
mail.set_storage_entry(m.from, entry)
|
mail.set_storage_entry(m.from, entry)
|
||||||
|
msg.spam = #mail.check_spam(msg) >= 1
|
||||||
|
|
||||||
-- add in every receivers inbox
|
-- add in every receivers inbox
|
||||||
for recipient in pairs(recipients) do
|
for _, deliver in pairs(recipients) do
|
||||||
entry = mail.get_storage_entry(recipient)
|
deliver(msg)
|
||||||
table.insert(entry.inbox, msg)
|
|
||||||
mail.set_storage_entry(recipient, entry)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- notify recipients that happen to be online
|
|
||||||
local mail_alert = f(mail.receive_mail_message, m.from, m.subject)
|
|
||||||
for _, player in ipairs(minetest.get_connected_players()) do
|
|
||||||
local name = player:get_player_name()
|
|
||||||
if recipients[name] then
|
|
||||||
minetest.chat_send_player(name, mail_alert)
|
|
||||||
local receiver_entry = mail.get_storage_entry(name)
|
|
||||||
local receiver_messages = receiver_entry.inbox
|
|
||||||
mail.hud_update(name, receiver_messages)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
for i=1, #mail.registered_on_receives do
|
for i=1, #mail.registered_on_receives do
|
||||||
|
@ -116,18 +113,16 @@ end
|
||||||
|
|
||||||
function mail.save_draft(m)
|
function mail.save_draft(m)
|
||||||
if type(m.from) ~= "string" then return false, "'from' is not a string" end
|
if type(m.from) ~= "string" then return false, "'from' is not a string" end
|
||||||
if type(m.to) ~= "string" then return false, "'to' is not a string" end
|
if type(m.to or "") ~= "string" then return false, "'to' is not a string" end
|
||||||
|
if type(m.cc or "") ~= "string" then return false, "'cc' is not a string" end
|
||||||
|
if type(m.bcc or "") ~= "string" then return false, "'bcc' is not a string" end
|
||||||
|
if type(m.subject or "") ~= "string" then return false, "'subject' is not a string" end
|
||||||
if type(m.body) ~= "string" then return false, "'body' is not a string" end
|
if type(m.body) ~= "string" then return false, "'body' is not a string" end
|
||||||
|
|
||||||
-- defaults
|
-- defaults
|
||||||
m.subject = m.subject or "(No subject)"
|
m.subject = m.subject or "(No subject)"
|
||||||
|
|
||||||
-- limit subject line
|
core.log("verbose", f("[mail] %q saves draft with subject %q and body %q",
|
||||||
if string.len(m.subject) > 30 then
|
|
||||||
m.subject = string.sub(m.subject,1,27) .. "..."
|
|
||||||
end
|
|
||||||
|
|
||||||
minetest.log("verbose", f("[mail] %q saves draft with subject %q and body %q",
|
|
||||||
m.from, m.subject, m.body
|
m.from, m.subject, m.body
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
42
api.md
42
api.md
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
# Mail format
|
# Mail format
|
||||||
The mail format in the api hooks
|
The mail format in the api hooks
|
||||||
|
|
||||||
|
@ -34,7 +33,7 @@ local success, error = mail.send({
|
||||||
```
|
```
|
||||||
|
|
||||||
# Hooks
|
# Hooks
|
||||||
On-receive mail hook:
|
Generic on-receive mail hook:
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
mail.register_on_receive(function(m)
|
mail.register_on_receive(function(m)
|
||||||
|
@ -42,11 +41,35 @@ mail.register_on_receive(function(m)
|
||||||
end)
|
end)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Player-specific on-receive mail hook:
|
||||||
|
```lua
|
||||||
|
mail.register_on_player_receive(function(player, msg)
|
||||||
|
-- "player" is the name of a recipient; "msg" is a mail object (see "Mail format")
|
||||||
|
end)
|
||||||
|
```
|
||||||
|
|
||||||
|
# Recipient handler
|
||||||
|
Recipient handlers are registered using
|
||||||
|
|
||||||
|
```lua
|
||||||
|
mail.register_recipient_handler(function(sender, name)
|
||||||
|
end)
|
||||||
|
```
|
||||||
|
|
||||||
|
where `name` is the name of a single recipient.
|
||||||
|
|
||||||
|
The recipient handler should return
|
||||||
|
* `nil` if the handler does not handle messages sent to the particular recipient,
|
||||||
|
* `true, player` (where `player` is a string or a list of strings) if the mail should be redirected to `player`,
|
||||||
|
* `true, deliver` if the mail should be delivered by calling `deliver` with the message, or
|
||||||
|
* `false, reason` (where `reason` is optional or, if provided, a string) if the recipient explicitly rejects the mail.
|
||||||
|
|
||||||
# Internals
|
# Internals
|
||||||
|
|
||||||
mod-storage entry for a player (indexed by playername and serialized with json):
|
mod-storage entry for a player (indexed by playername and serialized with json):
|
||||||
```lua
|
```lua
|
||||||
{
|
{
|
||||||
|
|
||||||
contacts = {
|
contacts = {
|
||||||
{
|
{
|
||||||
-- name of the player (unique key in the list)
|
-- name of the player (unique key in the list)
|
||||||
|
@ -76,7 +99,9 @@ mod-storage entry for a player (indexed by playername and serialized with json):
|
||||||
-- timestamp (os.time())
|
-- timestamp (os.time())
|
||||||
time = 1234,
|
time = 1234,
|
||||||
-- read-flag (true: player has read the mail, inbox only)
|
-- read-flag (true: player has read the mail, inbox only)
|
||||||
read = true
|
read = true,
|
||||||
|
-- spam-flag (true: that mail is noted as a spam)
|
||||||
|
spam = false
|
||||||
},{
|
},{
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
@ -84,6 +109,12 @@ mod-storage entry for a player (indexed by playername and serialized with json):
|
||||||
outbox = {
|
outbox = {
|
||||||
-- same format as "inbox"
|
-- same format as "inbox"
|
||||||
},
|
},
|
||||||
|
drafts = {
|
||||||
|
-- same format as "inbox"
|
||||||
|
},
|
||||||
|
trash = {
|
||||||
|
-- same format as "inbox"
|
||||||
|
},
|
||||||
lists = {
|
lists = {
|
||||||
{
|
{
|
||||||
-- name of the maillist (unique key in the list)
|
-- name of the maillist (unique key in the list)
|
||||||
|
@ -93,5 +124,10 @@ mod-storage entry for a player (indexed by playername and serialized with json):
|
||||||
-- playername list
|
-- playername list
|
||||||
players = {"playername", "playername2"}
|
players = {"playername", "playername2"}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
settings = {
|
||||||
|
setting1 = "value",
|
||||||
|
setting2 = true,
|
||||||
|
setting3 = 123
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
82
api.spec.lua
82
api.spec.lua
|
@ -1,12 +1,76 @@
|
||||||
mtt.register("send mail", function(callback)
|
mail.register_recipient_handler(function(_, name)
|
||||||
-- send a mail
|
if name:sub(1, 6) == "alias/" then
|
||||||
local success, err = mail.send({from = "player1", to = "player2", subject = "something", body = "blah"})
|
return true, name:sub(7)
|
||||||
assert(success)
|
elseif name == "list/test" then
|
||||||
assert(not err)
|
return true, {"alias/player1", "alias/player2"}
|
||||||
|
elseif name == "list/reject" then
|
||||||
|
return false, "It works (?)"
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
mail.update_maillist("player1", {
|
||||||
|
owner = "player1",
|
||||||
|
name = "recursive",
|
||||||
|
desc = "",
|
||||||
|
players = {"@recursive", "player1"},
|
||||||
|
}, "recursive")
|
||||||
|
|
||||||
|
local received_count = {}
|
||||||
|
mail.register_on_player_receive(function(player)
|
||||||
|
received_count[player] = (received_count[player] or 0) + 1
|
||||||
|
end)
|
||||||
|
|
||||||
|
local sent_count = 0
|
||||||
|
mail.register_on_receive(function()
|
||||||
|
sent_count = sent_count+1
|
||||||
|
end)
|
||||||
|
|
||||||
|
local function assert_inbox_count(player_name, count)
|
||||||
|
local entry = mail.get_storage_entry(player_name)
|
||||||
|
assert(entry, player_name .. " has no mail entry")
|
||||||
|
local actual_count = #entry.inbox
|
||||||
|
assert(actual_count == count, ("incorrect mail count: %d expected, got %d"):format(count, actual_count))
|
||||||
|
local player_received = received_count[player_name] or 0
|
||||||
|
assert(player_received == count, ("incorrect receive count: %d expected, got %d"):format(count, player_received))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function assert_send(expected_success, ...)
|
||||||
|
local success, err = mail.send(...)
|
||||||
|
if expected_success then
|
||||||
|
assert(success, ("expected mail to be sent, got error message: %s"):format(err))
|
||||||
|
assert(not err, ("unexpected message after sending mail: %s"):format(err))
|
||||||
|
else
|
||||||
|
assert(not success, "expected mail to be rejected, mail was sent")
|
||||||
|
assert(type(err) == "string", ("expected error message, got datum of type %s"):format(type(err)))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
mtt.register("send mail", function(callback)
|
||||||
|
-- local maillists
|
||||||
|
assert_send(true, {from = "player1", to = "@recursive", subject = "hello recursion", body = "blah"})
|
||||||
|
assert_inbox_count("player1", 1)
|
||||||
|
assert(sent_count == 1)
|
||||||
|
|
||||||
|
-- do not allow empty recipients
|
||||||
|
assert_send(false, {from = "player1", to = "@doesnotexist", subject = "should not be sent", body = "blah"})
|
||||||
|
assert(sent_count == 1)
|
||||||
|
|
||||||
|
-- send a mail to a list
|
||||||
|
assert_send(true, {from = "player1", to = "list/test", subject = "something", body = "blah"})
|
||||||
|
assert_inbox_count("player2", 1)
|
||||||
|
assert_inbox_count("player1", 1)
|
||||||
|
assert(sent_count == 2)
|
||||||
|
|
||||||
|
-- send a second mail to the list and also the sender
|
||||||
|
assert_send(true, {from = "player1", to = "list/test, alias/player1", subject = "something", body = "blah"})
|
||||||
|
assert_inbox_count("player2", 2)
|
||||||
|
assert_inbox_count("player1", 2)
|
||||||
|
assert(sent_count == 3)
|
||||||
|
|
||||||
|
-- send a mail to list/reject - the mail should be rejected
|
||||||
|
assert_send(false, {from = "player1", to = "list/reject", subject = "something", body = "NO"})
|
||||||
|
assert_inbox_count("player2", 2)
|
||||||
|
assert_inbox_count("player1", 2)
|
||||||
|
assert(sent_count == 3)
|
||||||
|
|
||||||
-- check the receivers inbox
|
|
||||||
local entry = mail.get_storage_entry("player2")
|
|
||||||
assert(entry)
|
|
||||||
assert(#entry.inbox > 0)
|
|
||||||
callback()
|
callback()
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
minetest.register_chatcommand("mail",{
|
core.register_chatcommand("mail",{
|
||||||
description = "Open the mail interface",
|
description = "Open the mail interface",
|
||||||
func = function(name)
|
func = function(name, param)
|
||||||
mail.show_mail_menu(name)
|
if #param > 0 then -- if param is not empty
|
||||||
|
mail.show_compose(name, param) -- make a new message
|
||||||
|
else
|
||||||
|
mail.show_mail_menu(name) -- show main menu
|
||||||
|
end
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
version: "3.6"
|
version: "4.1"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
sut:
|
sut:
|
||||||
build:
|
build:
|
||||||
context: ./test
|
context: ./test
|
||||||
args:
|
args:
|
||||||
ENGINE_VERSION: ${ENGINE_VERSION:-5.5.0}
|
ENGINE_VERSION: ${ENGINE_VERSION:-5.7.0}
|
||||||
user: root
|
user: root
|
||||||
volumes:
|
volumes:
|
||||||
- "./:/root/.minetest/worlds/world/worldmods/mail/"
|
- "./:/root/.minetest/worlds/world/worldmods/mail/"
|
||||||
|
@ -16,4 +16,4 @@ services:
|
||||||
- "30000:30000/udp"
|
- "30000:30000/udp"
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
world_data: {}
|
world_data: {}
|
||||||
|
|
89
gui.lua
89
gui.lua
|
@ -1,82 +1,5 @@
|
||||||
|
|
||||||
function mail.compile_contact_list(name, selected, playernames)
|
if core.get_modpath("unified_inventory") then
|
||||||
-- TODO: refactor this - not just compiles *a* list, but *the* list for the contacts screen (too inflexible)
|
|
||||||
local formspec = {}
|
|
||||||
local contacts = mail.get_contacts(name)
|
|
||||||
|
|
||||||
if playernames == nil then
|
|
||||||
local length = 0
|
|
||||||
for k, contact, i, l in mail.pairsByKeys(contacts) do
|
|
||||||
if i == 1 then length = l end
|
|
||||||
formspec[#formspec + 1] = ","
|
|
||||||
formspec[#formspec + 1] = ","
|
|
||||||
formspec[#formspec + 1] = minetest.formspec_escape(contact.name)
|
|
||||||
formspec[#formspec + 1] = ","
|
|
||||||
local note = contact.note
|
|
||||||
-- display an ellipsis if the note spans multiple lines
|
|
||||||
local idx = string.find(note, '\n')
|
|
||||||
if idx ~= nil then
|
|
||||||
note = string.sub(note, 1, idx-1) .. ' ...'
|
|
||||||
end
|
|
||||||
formspec[#formspec + 1] = minetest.formspec_escape(note)
|
|
||||||
if type(selected) == "string" then
|
|
||||||
if string.lower(selected) == k then
|
|
||||||
selected = i
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if length > 0 then
|
|
||||||
if selected and type(selected) == "number" then
|
|
||||||
formspec[#formspec + 1] = ";"
|
|
||||||
formspec[#formspec + 1] = tostring(selected + 1)
|
|
||||||
end
|
|
||||||
formspec[#formspec + 1] = "]"
|
|
||||||
else
|
|
||||||
formspec[#formspec + 1] = "]label[2,4.5;No contacts]"
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if type(playernames) == "string" then
|
|
||||||
playernames = mail.parse_player_list(playernames)
|
|
||||||
end
|
|
||||||
for i,c in ipairs(playernames) do
|
|
||||||
formspec[#formspec + 1] = ","
|
|
||||||
formspec[#formspec + 1] = ","
|
|
||||||
formspec[#formspec + 1] = minetest.formspec_escape(c)
|
|
||||||
formspec[#formspec + 1] = ","
|
|
||||||
if contacts[string.lower(c)] == nil then
|
|
||||||
formspec[#formspec + 1] = ""
|
|
||||||
else
|
|
||||||
local note = contacts[string.lower(c)].note
|
|
||||||
-- display an ellipsis if the note spans multiple lines
|
|
||||||
local idx = string.find(note, '\n')
|
|
||||||
if idx ~= nil then
|
|
||||||
note = string.sub(note, 1, idx-1) .. ' ...'
|
|
||||||
end
|
|
||||||
formspec[#formspec + 1] = minetest.formspec_escape(note)
|
|
||||||
end
|
|
||||||
if not selected then
|
|
||||||
if type(selected) == "string" then
|
|
||||||
if string.lower(selected) == string.lower(c) then
|
|
||||||
selected = i
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if #playernames > 0 and selected and type(selected) == "number" then
|
|
||||||
formspec[#formspec + 1] = ";"
|
|
||||||
formspec[#formspec + 1] = tostring(selected + 1)
|
|
||||||
end
|
|
||||||
formspec[#formspec + 1] = "]"
|
|
||||||
end
|
|
||||||
return table.concat(formspec, "")
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
if minetest.get_modpath("unified_inventory") then
|
|
||||||
mail.receive_mail_message = mail.receive_mail_message ..
|
|
||||||
" or use the mail button in the inventory"
|
|
||||||
mail.read_later_message = mail.read_later_message ..
|
|
||||||
" or by using the mail button in the inventory"
|
|
||||||
|
|
||||||
unified_inventory.register_button("mail", {
|
unified_inventory.register_button("mail", {
|
||||||
type = "image",
|
type = "image",
|
||||||
|
@ -87,3 +10,13 @@ if minetest.get_modpath("unified_inventory") then
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if core.get_modpath("sfinv_buttons") then
|
||||||
|
sfinv_buttons.register_button("mail", {
|
||||||
|
title = "Mail",
|
||||||
|
image = "mail_button.png",
|
||||||
|
action = function(player)
|
||||||
|
mail.show_mail_menu(player:get_player_name())
|
||||||
|
end
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
12
hud.lua
12
hud.lua
|
@ -1,12 +1,12 @@
|
||||||
|
|
||||||
local huddata = {}
|
local huddata = {}
|
||||||
|
|
||||||
minetest.register_on_joinplayer(function(player)
|
core.register_on_joinplayer(function(player)
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
local data = {}
|
local data = {}
|
||||||
|
|
||||||
data.imageid = player:hud_add({
|
data.imageid = player:hud_add({
|
||||||
hud_elem_type = "image",
|
type = "image",
|
||||||
name = "MailIcon",
|
name = "MailIcon",
|
||||||
position = {x=0.52, y=0.52},
|
position = {x=0.52, y=0.52},
|
||||||
text="",
|
text="",
|
||||||
|
@ -15,7 +15,7 @@ minetest.register_on_joinplayer(function(player)
|
||||||
})
|
})
|
||||||
|
|
||||||
data.textid = player:hud_add({
|
data.textid = player:hud_add({
|
||||||
hud_elem_type = "text",
|
type = "text",
|
||||||
name = "MailText",
|
name = "MailText",
|
||||||
position = {x=0.55, y=0.52},
|
position = {x=0.55, y=0.52},
|
||||||
text= "",
|
text= "",
|
||||||
|
@ -27,7 +27,7 @@ minetest.register_on_joinplayer(function(player)
|
||||||
huddata[name] = data
|
huddata[name] = data
|
||||||
end)
|
end)
|
||||||
|
|
||||||
minetest.register_on_leaveplayer(function(player)
|
core.register_on_leaveplayer(function(player)
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
huddata[name] = nil
|
huddata[name] = nil
|
||||||
end)
|
end)
|
||||||
|
@ -35,7 +35,7 @@ end)
|
||||||
|
|
||||||
function mail.hud_update(playername, messages)
|
function mail.hud_update(playername, messages)
|
||||||
local data = huddata[playername]
|
local data = huddata[playername]
|
||||||
local player = minetest.get_player_by_name(playername)
|
local player = core.get_player_by_name(playername)
|
||||||
|
|
||||||
if not data or not player then
|
if not data or not player then
|
||||||
return
|
return
|
||||||
|
@ -48,7 +48,7 @@ function mail.hud_update(playername, messages)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if unreadcount == 0 then
|
if unreadcount == 0 or (not mail.get_setting(playername, "hud_notifications")) then
|
||||||
player:hud_change(data.imageid, "text", "")
|
player:hud_change(data.imageid, "text", "")
|
||||||
player:hud_change(data.textid, "text", "")
|
player:hud_change(data.textid, "text", "")
|
||||||
else
|
else
|
||||||
|
|
39
init.lua
39
init.lua
|
@ -3,7 +3,10 @@ mail = {
|
||||||
version = 3,
|
version = 3,
|
||||||
|
|
||||||
-- mod storage
|
-- mod storage
|
||||||
storage = minetest.get_mod_storage(),
|
storage = core.get_mod_storage(),
|
||||||
|
|
||||||
|
-- translation
|
||||||
|
S = core.get_translator(core.get_current_modname()),
|
||||||
|
|
||||||
-- ui theme prepend
|
-- ui theme prepend
|
||||||
theme = "",
|
theme = "",
|
||||||
|
@ -14,8 +17,10 @@ mail = {
|
||||||
-- per-user ephemeral data
|
-- per-user ephemeral data
|
||||||
selected_idxs = {
|
selected_idxs = {
|
||||||
inbox = {},
|
inbox = {},
|
||||||
sent = {},
|
outbox = {},
|
||||||
drafts = {},
|
drafts = {},
|
||||||
|
trash = {},
|
||||||
|
message = {},
|
||||||
contacts = {},
|
contacts = {},
|
||||||
maillists = {},
|
maillists = {},
|
||||||
to = {},
|
to = {},
|
||||||
|
@ -25,20 +30,22 @@ mail = {
|
||||||
sortfield = {},
|
sortfield = {},
|
||||||
sortdirection = {},
|
sortdirection = {},
|
||||||
filter = {},
|
filter = {},
|
||||||
multipleselection = {}
|
multipleselection = {},
|
||||||
|
optionstab = {},
|
||||||
|
settings_group = {},
|
||||||
|
contributor_grouping = {},
|
||||||
},
|
},
|
||||||
|
|
||||||
message_drafts = {}
|
message_drafts = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if minetest.get_modpath("default") then
|
if core.get_modpath("default") then
|
||||||
mail.theme = default.gui_bg .. default.gui_bg_img
|
mail.theme = default.gui_bg .. default.gui_bg_img
|
||||||
end
|
end
|
||||||
|
|
||||||
-- sub files
|
-- sub files
|
||||||
local MP = minetest.get_modpath(minetest.get_current_modname())
|
local MP = core.get_modpath(core.get_current_modname())
|
||||||
dofile(MP .. "/util/normalize.lua")
|
dofile(MP .. "/util/init.lua")
|
||||||
dofile(MP .. "/util/uuid.lua")
|
|
||||||
dofile(MP .. "/chatcommands.lua")
|
dofile(MP .. "/chatcommands.lua")
|
||||||
dofile(MP .. "/migrate.lua")
|
dofile(MP .. "/migrate.lua")
|
||||||
dofile(MP .. "/hud.lua")
|
dofile(MP .. "/hud.lua")
|
||||||
|
@ -46,24 +53,14 @@ dofile(MP .. "/storage.lua")
|
||||||
dofile(MP .. "/api.lua")
|
dofile(MP .. "/api.lua")
|
||||||
dofile(MP .. "/gui.lua")
|
dofile(MP .. "/gui.lua")
|
||||||
dofile(MP .. "/onjoin.lua")
|
dofile(MP .. "/onjoin.lua")
|
||||||
dofile(MP .. "/ui/mail.lua")
|
dofile(MP .. "/player_recipients.lua")
|
||||||
dofile(MP .. "/ui/inbox.lua")
|
-- sub directories
|
||||||
dofile(MP .. "/ui/outbox.lua")
|
dofile(MP .. "/ui/init.lua")
|
||||||
dofile(MP .. "/ui/drafts.lua")
|
|
||||||
dofile(MP .. "/ui/message.lua")
|
|
||||||
dofile(MP .. "/ui/events.lua")
|
|
||||||
dofile(MP .. "/ui/contacts.lua")
|
|
||||||
dofile(MP .. "/ui/edit_contact.lua")
|
|
||||||
dofile(MP .. "/ui/select_contact.lua")
|
|
||||||
dofile(MP .. "/ui/maillists.lua")
|
|
||||||
dofile(MP .. "/ui/edit_maillists.lua")
|
|
||||||
dofile(MP .. "/ui/compose.lua")
|
|
||||||
dofile(MP .. "/ui/about.lua")
|
|
||||||
|
|
||||||
-- migrate storage
|
-- migrate storage
|
||||||
mail.migrate()
|
mail.migrate()
|
||||||
|
|
||||||
if minetest.get_modpath("mtt") then
|
if core.get_modpath("mtt") then
|
||||||
dofile(MP .. "/mtt.lua")
|
dofile(MP .. "/mtt.lua")
|
||||||
dofile(MP .. "/api.spec.lua")
|
dofile(MP .. "/api.spec.lua")
|
||||||
dofile(MP .. "/migrate.spec.lua")
|
dofile(MP .. "/migrate.spec.lua")
|
||||||
|
|
|
@ -1,55 +1,123 @@
|
||||||
# textdomain: mail
|
# textdomain: mail
|
||||||
|
The mail could not be sent:=Die Mail konnte nicht gesendet werden:
|
||||||
|
You did not specify any valid recipient.=Sie haben keinen gültigen Empfänger angegeben.
|
||||||
|
You have mail! Type /mail to read=Sie haben Post! „/mail“ zum Lesen eingeben
|
||||||
|
You have a new message from @1! Subject: @2=Sie haben eine neue Nachricht von @1! Betreff: @2
|
||||||
|
To view it, type /mail=Geben Sie zum Anzeigen „/mail“ ein
|
||||||
|
You could also use the button in your inventory.=Sie können auch die Schaltfläche in Ihrem Inventar verwenden.
|
||||||
|
Original author=Ursprünglicher Autor
|
||||||
|
Code=Code
|
||||||
|
Internationalization=Internationalisierung
|
||||||
|
Textures=Texturen
|
||||||
|
Audio=Audio
|
||||||
|
Provided by mt-mods=Bereitgestellt von mt-mods
|
||||||
|
Version: @1=Version: @1
|
||||||
|
Licenses=Lizenzen
|
||||||
|
Expat (code), WTFPL (textures)=Expat (Code), WTFPL (Texturen)
|
||||||
|
Communication using this system is NOT guaranteed to be private!=Die Kommunikation über dieses System ist NICHT garantiert privat!
|
||||||
|
Admins are able to view the messages of any player.=Admins können die Nachrichten aller Spielenden sehen.
|
||||||
|
Contributors=Mitwirkende
|
||||||
|
Group by name=Nach Name gruppieren
|
||||||
|
Group by contribution=Nach Beitrag gruppieren
|
||||||
|
Note=Anmerkung
|
||||||
|
Settings=Einstellungen
|
||||||
|
About=Über
|
||||||
BCC=BCC
|
BCC=BCC
|
||||||
Cancel=Abbrechen
|
Cancel=Abbrechen
|
||||||
Save draft=Entwurf Speichern
|
Save draft=Entwurf speichern
|
||||||
Send=Senden
|
Send=Senden
|
||||||
|
Subject=Betreff
|
||||||
|
To=An
|
||||||
|
CC=CC
|
||||||
Delete=Löschen
|
Delete=Löschen
|
||||||
New=Neu
|
New=Neu
|
||||||
No drafts=Keine Entwürfe
|
|
||||||
Edit=Bearbeiten
|
Edit=Bearbeiten
|
||||||
Subject=Betreff
|
|
||||||
Player name=Spielername
|
|
||||||
your contacts.=ihre Kontakte.
|
|
||||||
The contact=Der Kontakt
|
|
||||||
Save=Speichern
|
|
||||||
That name=Der Name
|
|
||||||
is already in=ist bereits in
|
|
||||||
name cannot=Name kann nicht
|
|
||||||
be empty.=leer sein.
|
|
||||||
Back=Zurück
|
Back=Zurück
|
||||||
Note=Notiz
|
Name=Name
|
||||||
Maillist name=Verteilerlistenname
|
No drafts=Keine Entwürfe
|
||||||
Desc=Beschreibung
|
Trash=Papierkorb
|
||||||
Players=Spieler
|
|
||||||
your maillists.=ihre Verteilerlisten.
|
|
||||||
The maillist=Die Verteilerliste
|
|
||||||
Mark Read=Als gelesen makieren
|
|
||||||
Mark Unread=Als ungelesen makieren
|
|
||||||
From=Von
|
|
||||||
(No description)=(Keine Beschreibung)
|
|
||||||
No maillist=Keine Verteilerliste
|
|
||||||
CC=CC
|
|
||||||
Read=Lesen
|
|
||||||
Ascending=
|
|
||||||
Descending=
|
|
||||||
Filter=
|
|
||||||
Allow multiple selection=
|
|
||||||
selected=
|
|
||||||
(Un)select all=
|
|
||||||
No mail=Keine Nachrichten
|
|
||||||
Inbox=Posteingang
|
Inbox=Posteingang
|
||||||
Sent messages=Nachrichten senden
|
Outbox=Gesendet
|
||||||
Drafts=Entwürfe
|
Drafts=Entwürfe
|
||||||
Contacts=Kontakte
|
Contacts=Kontakte
|
||||||
Mail lists=Verteilerlisten
|
Mail lists=Verteilerlisten
|
||||||
About=Über
|
Options=Einstellungen
|
||||||
Close=Schließen
|
Close=Schließen
|
||||||
(No subject)=(Kein Betreff)
|
(No subject)=(Kein Betreff)
|
||||||
Date=Datum
|
Player name=Spielername
|
||||||
|
That name is already in your contacts=Dieser Name ist bereits in Ihren Kontakten
|
||||||
|
The contact name cannot be empty.=Der Kontaktname kann nicht leer sein.
|
||||||
|
Save=Speichern
|
||||||
|
Maillist name=Verteilerlistenname
|
||||||
|
Desc=Beschreibung
|
||||||
|
Players=Spieler
|
||||||
|
That name is already in your mailing lists.=Dieser Name ist bereits in Ihren Verteilerlisten.
|
||||||
|
The mailing list name cannot be empty.=Der Verteilerlistenname kann nicht leer sein.
|
||||||
|
Mark Read=Als gelesen makieren
|
||||||
|
Mark Unread=Als ungelesen makieren
|
||||||
|
Mark Spam=Als Spam markieren
|
||||||
|
Unmark Spam=Kein Spam
|
||||||
Reply=Antworten
|
Reply=Antworten
|
||||||
Reply all=Allen antworten
|
Reply all=Allen antworten
|
||||||
Forward=Weiter
|
Forward=Weiterleiten
|
||||||
|
Reply only to the sender=Nur dem Absender antworten
|
||||||
|
Reply to all involved people=Allen beteiligten Personen antworten
|
||||||
|
Transfer message to other people=Nachricht an andere Personen weiterleiten
|
||||||
|
Date=Datum
|
||||||
|
From=Von
|
||||||
|
Filter=Filter
|
||||||
|
Allow multiple selection=Mehrfachauswahl zulassen
|
||||||
|
@1 of @2 selected=@1 von @2 ausgewählt
|
||||||
|
(Un)select all=Alle aus-/abwählen
|
||||||
|
No mail=Keine Nachrichten
|
||||||
|
Read=Lesen
|
||||||
|
Ascending=Aufsteigend
|
||||||
|
Descending=Absteigend
|
||||||
|
(No description)=(Keine Beschreibung)
|
||||||
|
No maillist=Keine Verteilerliste
|
||||||
|
Receivers=Empfänger
|
||||||
|
(Un)mute sender=Absender stummschalten/entstummen
|
||||||
Add=Hinzufügen
|
Add=Hinzufügen
|
||||||
Remove=Entfernen
|
Remove=Entfernen
|
||||||
Name=Name
|
Reset=Zurücksetzen
|
||||||
To=An
|
Restore=Wiederherstellen
|
||||||
|
Empty=Leer
|
||||||
|
Trash is empty=Papierkorb ist leer
|
||||||
|
From/To=Von/An
|
||||||
|
No contacts=Keine Kontakte
|
||||||
|
The method of delivery to @1 is invalid.=Die Zustellmethode an @1 ist ungültig.
|
||||||
|
The recipient @1 could not be identified.=Der Empfänger @1 konnte nicht identifiziert werden.
|
||||||
|
@1 rejected your mail.=@1 hat Ihre Mail abgewiesen.
|
||||||
|
Chat notifications=Chat-Benachrichtigungen
|
||||||
|
Receive a message in the chat when there is a new message=Eine Nachricht im Chat erhalten, wenn es eine neue Mail gibt
|
||||||
|
On join notifications=Login-Benachrichtigungen
|
||||||
|
Receive a message at login when inbox isn't empty=Bei der Anmeldung eine Nachricht erhalten, wenn der Posteingang nicht leer ist
|
||||||
|
HUD notifications=HUD-Benachrichtigungen
|
||||||
|
Show an HUD notification when inbox isn't empty=Eine HUD-Benachrichtigung anzeigen, wenn der Posteingang nicht leer ist
|
||||||
|
Sound notifications=Klang-Benachrichtigungen
|
||||||
|
Play a sound when there is a new message=Einen Ton abspielen, wenn eine neue Mail eingeht
|
||||||
|
Show unread in different color=Ungelesenes in anderer Farbe anzeigen
|
||||||
|
Show CC/BCC in different color=CC/BCC in anderer Farbe anzeigen
|
||||||
|
Default sorting field=Standardsortierfeld
|
||||||
|
Default sorting direction=Standardmäßige Sortierrichtung
|
||||||
|
Move deleted messages to trash=Gelöschte Nachrichten in den Papierkorb verschieben
|
||||||
|
Automatic marking read=Automatisch als gelesen markieren
|
||||||
|
Mark a message as read when opened=Nachrichten beim Öffnen als gelesen markieren
|
||||||
|
Date format=Datumsformat
|
||||||
|
Timezone offset=Zeitverschiebung
|
||||||
|
Offset to add to server time.=Verschiebung, die zur Serverzeit addiert wird.
|
||||||
|
Mute list=Stummgeschaltet-Liste
|
||||||
|
Notifications=Benachrichtigungen
|
||||||
|
Message list=Nachrichtenliste
|
||||||
|
Fields=Felder
|
||||||
|
Spam=Spam
|
||||||
|
Other=Anderes
|
||||||
|
Date and Time=Datum und Uhrzeit
|
||||||
|
years=Jahren
|
||||||
|
months=Monaten
|
||||||
|
weeks=Wochen
|
||||||
|
days=Tagen
|
||||||
|
hours=Stunden
|
||||||
|
minuts=Minuten
|
||||||
|
seconds=Sekunden
|
||||||
|
@1 ago=Vor @1
|
||||||
|
|
128
locale/mail.es.tr
Normal file
128
locale/mail.es.tr
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
# textdomain: mail
|
||||||
|
The mail could not be sent:=
|
||||||
|
You did not specify any valid recipient.=
|
||||||
|
You have mail! Type /mail to read=¡Tienes correo! Escribe /mail para leerlo
|
||||||
|
You have a new message from @1! Subject: @2=¡Tienes un nuevo mensaje de @1! Asunto: @2
|
||||||
|
To view it, type /mail=Para verlo, escribe /mail
|
||||||
|
You could also use the button in your inventory.=También puedes usar el botón de tu inventario.
|
||||||
|
Original author=
|
||||||
|
Code=
|
||||||
|
Internationalization=
|
||||||
|
Textures=
|
||||||
|
Audio=
|
||||||
|
Provided by mt-mods=Proporcionado por mt-mods
|
||||||
|
Version: @1=
|
||||||
|
Licenses=Licencias
|
||||||
|
Expat (code), WTFPL (textures)=Expat (código), WTFPL (texturas)
|
||||||
|
Communication using this system is NOT guaranteed to be private!=¡NO se garantiza que la comunicación mediante este sistema sea privada!
|
||||||
|
Admins are able to view the messages of any player.=Los administradores pueden ver los mensajes de cualquier jugador.
|
||||||
|
Contributors=Colaboradores
|
||||||
|
Group by name=
|
||||||
|
Group by contribution=
|
||||||
|
Note=Nota
|
||||||
|
Settings=Ajustes
|
||||||
|
About=Acerca de
|
||||||
|
BCC=CCO
|
||||||
|
Cancel=Cancelar
|
||||||
|
Save draft=Guardar borrador
|
||||||
|
Send=Enviar
|
||||||
|
Subject=Asunto
|
||||||
|
To=Para
|
||||||
|
CC=CC
|
||||||
|
Delete=Borrar
|
||||||
|
New=Nuevo
|
||||||
|
Edit=Editar
|
||||||
|
Back=Volver
|
||||||
|
Name=Nombre
|
||||||
|
No drafts=No hay borradores
|
||||||
|
Trash=Papelera
|
||||||
|
Inbox=Entrada
|
||||||
|
Outbox=Enviados
|
||||||
|
Drafts=Borradores
|
||||||
|
Contacts=Contactos
|
||||||
|
Mail lists=Listas de correo
|
||||||
|
Options=Opciones
|
||||||
|
Close=Cerrar
|
||||||
|
(No subject)=(Sin asunto)
|
||||||
|
Player name=Nombre del jugador
|
||||||
|
That name is already in your contacts=Ese nombre ya está en tus contactos
|
||||||
|
The contact name cannot be empty.=El nombre de contacto no puede estar vacío.
|
||||||
|
Save=Guardar
|
||||||
|
Maillist name=Nombre de la lista de correo
|
||||||
|
Desc=Desc
|
||||||
|
Players=Jugadores
|
||||||
|
That name is already in your mailing lists.=Ese nombre ya está en tus listas de correo.
|
||||||
|
The mailing list name cannot be empty.=El nombre de lista de correo no puede estar vacío.
|
||||||
|
Mark Read=Marcar como leído
|
||||||
|
Mark Unread=Marcar como no leído
|
||||||
|
Mark Spam=
|
||||||
|
Unmark Spam=
|
||||||
|
Reply=Responder
|
||||||
|
Reply all=Responder a todos
|
||||||
|
Forward=Reenviar
|
||||||
|
Reply only to the sender=Responder solo al remitente
|
||||||
|
Reply to all involved people=Responder a todas las personas implicadas
|
||||||
|
Transfer message to other people=Transferir el mensaje a otras personas
|
||||||
|
Date=Fecha
|
||||||
|
From=De
|
||||||
|
Filter=Filtro
|
||||||
|
Allow multiple selection=Permitir selección múltiple
|
||||||
|
@1 of @2 selected=@1 de @2 seleccionado(s)
|
||||||
|
(Un)select all=(Des)seleccionar todos
|
||||||
|
No mail=Sin correo
|
||||||
|
Read=Leer
|
||||||
|
Ascending=Ascendente
|
||||||
|
Descending=Descendente
|
||||||
|
(No description)=(Sin descripción)
|
||||||
|
No maillist=Sin lista de correo
|
||||||
|
Receivers=Recipientes
|
||||||
|
(Un)mute sender=
|
||||||
|
Add=Añadir
|
||||||
|
Remove=Quitar
|
||||||
|
Reset=Restablecer
|
||||||
|
Restore=Restaurar
|
||||||
|
Empty=Vacío
|
||||||
|
Trash is empty=La papelera está vacía
|
||||||
|
From/To=De/Para
|
||||||
|
No contacts=Sin contactos
|
||||||
|
The method of delivery to @1 is invalid.=
|
||||||
|
The recipient @1 could not be identified.=
|
||||||
|
@1 rejected your mail.=
|
||||||
|
Chat notifications=Notificaciones de chat
|
||||||
|
Receive a message in the chat when there is a new message=Recibir un mensaje en el chat cuando hay correo nuevo
|
||||||
|
On join notifications=Notificaciones al unirse
|
||||||
|
Receive a message at login when inbox isn't empty=Recibir mensaje al conectarse si la bandeja de entrada no está vacía
|
||||||
|
HUD notifications=Notificaciones de interfaz
|
||||||
|
Show an HUD notification when inbox isn't empty=Mostrar una notificación en la interfaz cuando la bandeja de entrada no está vacía
|
||||||
|
Sound notifications=Notificaciones de sonido
|
||||||
|
Play a sound when there is a new message=Emitir un sonido cuando hay un correo nuevo
|
||||||
|
Show unread in different color=Mostrar no-leídos en diferente color
|
||||||
|
Show CC/BCC in different color=Mostrar CC/CCO en diferente color
|
||||||
|
Default sorting field=Campo a ordenar por defecto
|
||||||
|
Default sorting direction=
|
||||||
|
Move deleted messages to trash=Mover mensajes borrados a la papelera
|
||||||
|
Automatic marking read=Marcar como leído automáticamente
|
||||||
|
Mark a message as read when opened=Marcar un mensaje como leído al abrirlo
|
||||||
|
Date format=Formato de fecha
|
||||||
|
Timezone offset=
|
||||||
|
Offset to add to server time.=
|
||||||
|
Mute list=
|
||||||
|
Notifications=Notificaciones
|
||||||
|
Message list=Lista de mensajes
|
||||||
|
Fields=
|
||||||
|
Spam=
|
||||||
|
Other=Otros
|
||||||
|
Date and Time=
|
||||||
|
years=años
|
||||||
|
months=meses
|
||||||
|
weeks=semanas
|
||||||
|
days=días
|
||||||
|
hours=horas
|
||||||
|
minuts=minutos
|
||||||
|
seconds=segundos
|
||||||
|
@1 ago=hace @1
|
||||||
|
|
||||||
|
|
||||||
|
##### not used anymore #####
|
||||||
|
|
||||||
|
Version=Versión
|
|
@ -1,55 +1,123 @@
|
||||||
# textdomain: mail
|
# textdomain: mail
|
||||||
|
The mail could not be sent:=Le mail ne peut pas être envoyé :
|
||||||
|
You did not specify any valid recipient.=Vous n'avez pas spécifié de destinataire valide.
|
||||||
|
You have mail! Type /mail to read=Vous avez reçu un mail ! Entrez /mail pour le consulter
|
||||||
|
You have a new message from @1! Subject: @2=Vous avez un nouveau message de @1 ! Objet : @2
|
||||||
|
To view it, type /mail=Pour le consulter, entrez /mail
|
||||||
|
You could also use the button in your inventory.=Vous pouvez également utiliser le bouton dans votre inventaire
|
||||||
|
Original author=Auteur original
|
||||||
|
Code=Code
|
||||||
|
Internationalization=Traduction
|
||||||
|
Textures=Textures
|
||||||
|
Audio=Audio
|
||||||
|
Provided by mt-mods=Fourni par mt-mods
|
||||||
|
Version: @1=Version : @1
|
||||||
|
Licenses=Licences
|
||||||
|
Expat (code), WTFPL (textures)=Expat (code), WTFPL (textures)
|
||||||
|
Communication using this system is NOT guaranteed to be private!=La communication par ce système n'est pas garantie d'être privée !
|
||||||
|
Admins are able to view the messages of any player.=Les administrateurs peuvent voir les messages de chaque joueur.
|
||||||
|
Contributors=Contributeurs
|
||||||
|
Group by name=Grouper par nom
|
||||||
|
Group by contribution=Grouper par contribution
|
||||||
|
Note=Note
|
||||||
|
Settings=Paramètres
|
||||||
|
About=À propos
|
||||||
BCC=Cci
|
BCC=Cci
|
||||||
Cancel=Annuler
|
Cancel=Annuler
|
||||||
Save draft=Enregistrer le brouillon
|
Save draft=Enregistrer le brouillon
|
||||||
Send=Envoyer
|
Send=Envoyer
|
||||||
|
Subject=Objet
|
||||||
|
To=À
|
||||||
|
CC=Cc
|
||||||
Delete=Supprimer
|
Delete=Supprimer
|
||||||
New=Nouveau
|
New=Nouveau
|
||||||
No drafts=Pas de brouillons
|
|
||||||
Edit=Modifier
|
Edit=Modifier
|
||||||
Subject=Objet
|
|
||||||
Player name=Nom du joueur
|
|
||||||
your contacts.=vos contacts.
|
|
||||||
The contact=Ce contact
|
|
||||||
Save=Sauvegarder
|
|
||||||
That name=Ce nom
|
|
||||||
is already in=existe déjà
|
|
||||||
name cannot=nom ne peut pas
|
|
||||||
be empty.=être vide.
|
|
||||||
Back=Retour
|
Back=Retour
|
||||||
Note=Note
|
Name=Nom
|
||||||
Maillist name=Nom de la liste de diffusion
|
No drafts=Aucun brouillon
|
||||||
Desc=Desc
|
Trash=Corbeille
|
||||||
Players=Joueurs
|
|
||||||
your maillists.=vos listes de diffusion.
|
|
||||||
The maillist=Cette liste de diffusion
|
|
||||||
Mark Read=Marquer comme lu
|
|
||||||
Mark Unread=Marquer non lu
|
|
||||||
From=De
|
|
||||||
(No description)=Sans description
|
|
||||||
No maillist=Aucune liste de diffusion
|
|
||||||
CC=Cc
|
|
||||||
Read=Lire
|
|
||||||
Ascending=Croissant
|
|
||||||
Descending=Décroissant
|
|
||||||
Filter=Filtre
|
|
||||||
Allow multiple selection=Autoriser la sélection multiple
|
|
||||||
selected=sélectionnés
|
|
||||||
(Un)select all=Tout (dé)selectionner
|
|
||||||
No mail=Aucun mail
|
|
||||||
Inbox=Boîte de réception
|
Inbox=Boîte de réception
|
||||||
Sent messages=Messages envoyés
|
Outbox=Envoyés
|
||||||
Drafts=Brouillons
|
Drafts=Brouillons
|
||||||
Contacts=Contacts
|
Contacts=Contacts
|
||||||
Mail lists=Listes de diffusion
|
Mail lists=Listes de diffusion
|
||||||
About=À propos
|
Options=Options
|
||||||
Close=Fermer
|
Close=Fermer
|
||||||
(No subject)=(Sans objet)
|
(No subject)=(Sans objet)
|
||||||
Date=Date
|
Player name=Nom du joueur
|
||||||
|
That name is already in your contacts=Ce nom est déjà dans vos contacts
|
||||||
|
The contact name cannot be empty.=Le nom du contact ne peut pas être vide.
|
||||||
|
Save=Sauvegarder
|
||||||
|
Maillist name=Nom de la liste de diffusion
|
||||||
|
Desc=Desc
|
||||||
|
Players=Joueurs
|
||||||
|
That name is already in your mailing lists.=Ce nom est déjà présent dans vos listes de diffusion.
|
||||||
|
The mailing list name cannot be empty.=Le nom de la liste de diffusion ne peut pas être vide.
|
||||||
|
Mark Read=Marquer comme lu
|
||||||
|
Mark Unread=Marquer non lu
|
||||||
|
Mark Spam=Marquer comme spam
|
||||||
|
Unmark Spam=Marquer non-spam
|
||||||
Reply=Répondre
|
Reply=Répondre
|
||||||
Reply all=Répondre à tous
|
Reply all=Répondre à tous
|
||||||
Forward=Transférer
|
Forward=Transférer
|
||||||
|
Reply only to the sender=Répondre uniquement à l'expéditeur
|
||||||
|
Reply to all involved people=Répondre à toutes les personnes concernées
|
||||||
|
Transfer message to other people=Transférer le message à d'autres personnes
|
||||||
|
Date=Date
|
||||||
|
From=De
|
||||||
|
Filter=Filtre
|
||||||
|
Allow multiple selection=Autoriser la sélection multiple
|
||||||
|
@1 of @2 selected=@1 sur @2 sélectionnés
|
||||||
|
(Un)select all=Tout (dé)sélectionner
|
||||||
|
No mail=Aucun mail
|
||||||
|
Read=Lire
|
||||||
|
Ascending=Croissant
|
||||||
|
Descending=Décroissant
|
||||||
|
(No description)=(Sans description)
|
||||||
|
No maillist=Aucune liste de diffusion
|
||||||
|
Receivers=Destinataires
|
||||||
|
(Un)mute sender=(Dé)mettre en sourdine
|
||||||
Add=Ajouter
|
Add=Ajouter
|
||||||
Remove=Enlever
|
Remove=Enlever
|
||||||
Name=Nom
|
Reset=Réinitialiser
|
||||||
To=À
|
Restore=Restaurer
|
||||||
|
Empty=Vider
|
||||||
|
Trash is empty=La corbeille est vide
|
||||||
|
From/To=De/À
|
||||||
|
No contacts=Aucun contact
|
||||||
|
The method of delivery to @1 is invalid.=La méthode d'expédition à @1 est invalide.
|
||||||
|
The recipient @1 could not be identified.=Le destinataire @1 n'a pas pu être identifié.
|
||||||
|
@1 rejected your mail.=@1 a rejeté votre mail.
|
||||||
|
Chat notifications=Notifications dans le tchat
|
||||||
|
Receive a message in the chat when there is a new message=Recevoir un message dans le tchat lorsqu'un nouveau message est reçu
|
||||||
|
On join notifications=Notifications à la connexion
|
||||||
|
Receive a message at login when inbox isn't empty=Recevoir un message à la connexion lorsque la boîte de réception n'est pas vide
|
||||||
|
HUD notifications=Notifications ATH
|
||||||
|
Show an HUD notification when inbox isn't empty=Indiquer dans l'ATH que la boîte de réception n'est pas vide
|
||||||
|
Sound notifications=Notifications sonores
|
||||||
|
Play a sound when there is a new message=Jouer un son lorsqu'un nouveau message est reçu
|
||||||
|
Show unread in different color=Coloriser les non lus
|
||||||
|
Show CC/BCC in different color=Coloriser les Cc/Cci
|
||||||
|
Default sorting field=Champ de tri par défaut
|
||||||
|
Default sorting direction=Direction de tri par défaut
|
||||||
|
Move deleted messages to trash=Supprimer les messages dans la corbeille
|
||||||
|
Automatic marking read=Lu automatique
|
||||||
|
Mark a message as read when opened=Marquer un message comme lu lorsqu'il est ouvert
|
||||||
|
Date format=Format de la date
|
||||||
|
Timezone offset=Compensation horaire
|
||||||
|
Offset to add to server time.=Écart de temps à ajouter à l'heure du serveur.
|
||||||
|
Mute list=Liste de sourdine
|
||||||
|
Notifications=Notifications
|
||||||
|
Message list=Liste de messages
|
||||||
|
Fields=Champs
|
||||||
|
Spam=Spam
|
||||||
|
Other=Autre
|
||||||
|
Date and Time=Date et Heure
|
||||||
|
years=années
|
||||||
|
months=mois
|
||||||
|
weeks=semaines
|
||||||
|
days=jours
|
||||||
|
hours=heures
|
||||||
|
minuts=minutes
|
||||||
|
seconds=secondes
|
||||||
|
@1 ago=Il y a @1
|
||||||
|
|
128
locale/mail.hu.tr
Normal file
128
locale/mail.hu.tr
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
# textdomain: mail
|
||||||
|
The mail could not be sent:=
|
||||||
|
You did not specify any valid recipient.=
|
||||||
|
You have mail! Type /mail to read=Van egy leveled! Írd /mail az olvasáshoz
|
||||||
|
You have a new message from @1! Subject: @2=Van egy új üzeneted @1-től Cím: @2
|
||||||
|
To view it, type /mail=Ahhoz hogy megnézd, írd /mail
|
||||||
|
You could also use the button in your inventory.=A gombot is tudod használni az inventoridban.
|
||||||
|
Original author=
|
||||||
|
Code=
|
||||||
|
Internationalization=
|
||||||
|
Textures=
|
||||||
|
Audio=
|
||||||
|
Provided by mt-mods=Feltéve, hogy az én mt-mod-om
|
||||||
|
Version: @1=
|
||||||
|
Licenses=License
|
||||||
|
Expat (code), WTFPL (textures)=Expat (kód), WTFPL (textúrák)
|
||||||
|
Communication using this system is NOT guaranteed to be private!=A systemben lévő komunikáció nem garantáltan privát!
|
||||||
|
Admins are able to view the messages of any player.=Az adminok megtudják nézni minden játékos üzenetjét.
|
||||||
|
Contributors=Közreműködöttek
|
||||||
|
Group by name=
|
||||||
|
Group by contribution=
|
||||||
|
Note=Jegyzet
|
||||||
|
Settings=Beállítások
|
||||||
|
About=Róla
|
||||||
|
BCC=BCC
|
||||||
|
Cancel=Mégse
|
||||||
|
Save draft=mentés piszkozatként
|
||||||
|
Send=Küldés
|
||||||
|
Subject=Cím
|
||||||
|
To=Neki
|
||||||
|
CC=CC
|
||||||
|
Delete=Törlés
|
||||||
|
New=Új
|
||||||
|
Edit=Szerkesztés
|
||||||
|
Back=Visza
|
||||||
|
Name=Név
|
||||||
|
No drafts=Nincsenek piszkozatok
|
||||||
|
Trash=
|
||||||
|
Inbox=PostaLáda
|
||||||
|
Outbox=Elküldött
|
||||||
|
Drafts=Piszkozatok
|
||||||
|
Contacts=Contaktok
|
||||||
|
Mail lists=Levelező lista
|
||||||
|
Options=Lehetőségek
|
||||||
|
Close=Bezár
|
||||||
|
(No subject)=(nincs cím)
|
||||||
|
Player name=Játékos neve
|
||||||
|
That name is already in your contacts=A név már a kontaktok között van
|
||||||
|
The contact name cannot be empty.=A contakt neve nem lehet üres.
|
||||||
|
Save=Mentés
|
||||||
|
Maillist name=Levelező lista neve
|
||||||
|
Desc=Desc
|
||||||
|
Players=Játékosok
|
||||||
|
That name is already in your mailing lists.=A név már benne van a levelező listában
|
||||||
|
The mailing list name cannot be empty.=A levelező lista neve nem lehet üres
|
||||||
|
Mark Read=Jelöld olvasottként
|
||||||
|
Mark Unread=Jelöld olvasatlanul
|
||||||
|
Mark Spam=
|
||||||
|
Unmark Spam=
|
||||||
|
Reply=Válasz
|
||||||
|
Reply all=Válaszmindenkinek
|
||||||
|
Forward=Továbbítás
|
||||||
|
Reply only to the sender=
|
||||||
|
Reply to all involved people=
|
||||||
|
Transfer message to other people=
|
||||||
|
Date=Dátum
|
||||||
|
From=Tőle
|
||||||
|
Filter=Filterek
|
||||||
|
Allow multiple selection=
|
||||||
|
@1 of @2 selected=
|
||||||
|
(Un)select all=(ne válaszd ki) mindegyik választása
|
||||||
|
No mail=Nincs levél
|
||||||
|
Read=Olvasott
|
||||||
|
Ascending=Emelkedő
|
||||||
|
Descending=Sűlyedő
|
||||||
|
(No description)=(Nincs leírás)
|
||||||
|
No maillist=Nincs levelező lista
|
||||||
|
Receivers=
|
||||||
|
(Un)mute sender=
|
||||||
|
Add=Hozzáadás
|
||||||
|
Remove=Elvétel
|
||||||
|
Reset=Viszaállítás
|
||||||
|
Restore=
|
||||||
|
Empty=
|
||||||
|
Trash is empty=
|
||||||
|
From/To=Tól(től)/neki
|
||||||
|
No contacts=
|
||||||
|
The method of delivery to @1 is invalid.=
|
||||||
|
The recipient @1 could not be identified.=
|
||||||
|
@1 rejected your mail.=
|
||||||
|
Chat notifications=Chates értesítések
|
||||||
|
Receive a message in the chat when there is a new message=
|
||||||
|
On join notifications=Belépési értesírés
|
||||||
|
Receive a message at login when inbox isn't empty=
|
||||||
|
HUD notifications= HUD értesítés
|
||||||
|
Show an HUD notification when inbox isn't empty=
|
||||||
|
Sound notifications=Hang értesítés
|
||||||
|
Play a sound when there is a new message=
|
||||||
|
Show unread in different color=Mutasd a nem olvasottakat más színnel
|
||||||
|
Show CC/BCC in different color=Mutasd a CC-t/BCC-t más színnel
|
||||||
|
Default sorting field=Alap válogató terület
|
||||||
|
Default sorting direction=
|
||||||
|
Move deleted messages to trash=
|
||||||
|
Automatic marking read=
|
||||||
|
Mark a message as read when opened=
|
||||||
|
Date format=
|
||||||
|
Timezone offset=
|
||||||
|
Offset to add to server time.=
|
||||||
|
Mute list=
|
||||||
|
Notifications=Értesítések
|
||||||
|
Message list=Üzenetek listája
|
||||||
|
Fields=
|
||||||
|
Spam=
|
||||||
|
Other=
|
||||||
|
Date and Time=
|
||||||
|
years=
|
||||||
|
months=
|
||||||
|
weeks=
|
||||||
|
days=
|
||||||
|
hours=
|
||||||
|
minuts=
|
||||||
|
seconds=
|
||||||
|
@1 ago=
|
||||||
|
|
||||||
|
|
||||||
|
##### not used anymore #####
|
||||||
|
|
||||||
|
Version=Verzió
|
128
locale/mail.id.tr
Normal file
128
locale/mail.id.tr
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
# textdomain: mail
|
||||||
|
The mail could not be sent:=
|
||||||
|
You did not specify any valid recipient.=
|
||||||
|
You have mail! Type /mail to read=Anda memiliki surel! ketik /mail untuk membaca
|
||||||
|
You have a new message from @1! Subject: @2=Anda memiliki pesan baru dari @1! Subjek: @2
|
||||||
|
To view it, type /mail=Untuk melihatnya, ketik /mail
|
||||||
|
You could also use the button in your inventory.=Anda juga dapat menggunakan tombol dalam inventaris Anda.
|
||||||
|
Original author=
|
||||||
|
Code=
|
||||||
|
Internationalization=
|
||||||
|
Textures=
|
||||||
|
Audio=
|
||||||
|
Provided by mt-mods=Disediakan oleh mt-mods
|
||||||
|
Version: @1=
|
||||||
|
Licenses=Lisensi
|
||||||
|
Expat (code), WTFPL (textures)=Expat (kode), WTFPL (tekstur)
|
||||||
|
Communication using this system is NOT guaranteed to be private!=Komunikasi dengan sistem ini TIDAK dijamin bersifat pribadi!
|
||||||
|
Admins are able to view the messages of any player.=Admin dapat melihat pesan dari setiap pemain.
|
||||||
|
Contributors=Kontributor
|
||||||
|
Group by name=
|
||||||
|
Group by contribution=
|
||||||
|
Note=Catatan
|
||||||
|
Settings=Pengaturan
|
||||||
|
About=Tentang
|
||||||
|
BCC=BCC
|
||||||
|
Cancel=Batal
|
||||||
|
Save draft=Simpan Draf
|
||||||
|
Send=Kirim
|
||||||
|
Subject=Subjek
|
||||||
|
To=Kpd
|
||||||
|
CC=CC
|
||||||
|
Delete=Hapus
|
||||||
|
New=Baru
|
||||||
|
Edit=Sunting
|
||||||
|
Back=Kembali
|
||||||
|
Name=Nama
|
||||||
|
No drafts=Tidak ada draf
|
||||||
|
Trash=Sampah
|
||||||
|
Inbox=Kotak Masuk
|
||||||
|
Outbox=Kotak Keluar
|
||||||
|
Drafts=Draf
|
||||||
|
Contacts=Kontak
|
||||||
|
Mail lists=Milis
|
||||||
|
Options=Pengaturan
|
||||||
|
Close=Tutup
|
||||||
|
(No subject)=(Tanpa subjek)
|
||||||
|
Player name=Nama pemain
|
||||||
|
That name is already in your contacts=Nama itu sudah ada dalam kontak Anda
|
||||||
|
The contact name cannot be empty.=Nama kontak tidak boleh kosong.
|
||||||
|
Save=Simpan
|
||||||
|
Maillist name=Nama milis
|
||||||
|
Desc=Deskripsi
|
||||||
|
Players=Pemain
|
||||||
|
That name is already in your mailing lists.=Nama tersebut sudah ada dalam milis Anda.
|
||||||
|
The mailing list name cannot be empty.=Nama milis tidak boleh kosong.
|
||||||
|
Mark Read=Tndai Sdh Dibaca
|
||||||
|
Mark Unread=Tndai Blm Dibaca
|
||||||
|
Mark Spam=
|
||||||
|
Unmark Spam=
|
||||||
|
Reply=Balas
|
||||||
|
Reply all=Balas Semua
|
||||||
|
Forward=Teruskan
|
||||||
|
Reply only to the sender=Balas hanya kepada pengirim
|
||||||
|
Reply to all involved people=Balas kepada semua orang yang terlibat
|
||||||
|
Transfer message to other people=Teruskan pesan kepada orang lain
|
||||||
|
Date=Tanggal
|
||||||
|
From=Dari
|
||||||
|
Filter=Saring
|
||||||
|
Allow multiple selection=Izinkan beberapa pilihan
|
||||||
|
@1 of @2 selected=@1 dari @2 dipilih
|
||||||
|
(Un)select all=Batal/Pilih Semua
|
||||||
|
No mail=Tidak ada surat
|
||||||
|
Read=Baca
|
||||||
|
Ascending=Menaik
|
||||||
|
Descending=Menurun
|
||||||
|
(No description)=(Tidak ada deskripsi)
|
||||||
|
No maillist=Tidak ada milis
|
||||||
|
Receivers=Penerima
|
||||||
|
(Un)mute sender=
|
||||||
|
Add=Tambah
|
||||||
|
Remove=Hapus
|
||||||
|
Reset=Atur Ulang
|
||||||
|
Restore=Kembalikan
|
||||||
|
Empty=Kosong
|
||||||
|
Trash is empty=Sampah kosong
|
||||||
|
From/To=Dari/Kpd
|
||||||
|
No contacts=Tidak ada kontak
|
||||||
|
The method of delivery to @1 is invalid.=
|
||||||
|
The recipient @1 could not be identified.=
|
||||||
|
@1 rejected your mail.=
|
||||||
|
Chat notifications=Pemberitahuan obrolan
|
||||||
|
Receive a message in the chat when there is a new message=Terima pesan dalam obrolan ketika ada pesan baru
|
||||||
|
On join notifications=Pemberitahuan saat bergabung
|
||||||
|
Receive a message at login when inbox isn't empty=Terima pesan saat masuk log ketika kotak masuk tidak kosong
|
||||||
|
HUD notifications=Pemberitahuan HUD
|
||||||
|
Show an HUD notification when inbox isn't empty=Tampilkan pemberitahuan HUD saat kotak masuk tidak kosong
|
||||||
|
Sound notifications=Pemberitahuan suara
|
||||||
|
Play a sound when there is a new message=Putar suara saat ada pesan baru
|
||||||
|
Show unread in different color=Tampilkan belum dibaca dengan warna berbeda
|
||||||
|
Show CC/BCC in different color=Tampilkan CC/BCC dengan warna berbeda
|
||||||
|
Default sorting field=Kolom pengurutan bawaan
|
||||||
|
Default sorting direction=Arah pengurutan bawaan
|
||||||
|
Move deleted messages to trash=Pindahkan pesan yang dihapus ke sampah
|
||||||
|
Automatic marking read=Penandaan otomatis sudah dibaca
|
||||||
|
Mark a message as read when opened=Tandai pesan sebagai sudah dibaca saat dibuka
|
||||||
|
Date format=Format tanggal
|
||||||
|
Timezone offset=
|
||||||
|
Offset to add to server time.=
|
||||||
|
Mute list=
|
||||||
|
Notifications=Pemberitahuan
|
||||||
|
Message list=Daftar Pesan
|
||||||
|
Fields=
|
||||||
|
Spam=
|
||||||
|
Other=Lain-Lain
|
||||||
|
Date and Time=
|
||||||
|
years=tahun
|
||||||
|
months=bulan
|
||||||
|
weeks=pekan
|
||||||
|
days=hari
|
||||||
|
hours=jam
|
||||||
|
minuts=menit
|
||||||
|
seconds=detik
|
||||||
|
@1 ago=@1 yang lalu
|
||||||
|
|
||||||
|
|
||||||
|
##### not used anymore #####
|
||||||
|
|
||||||
|
Version=Versi
|
123
locale/mail.pt_BR.tr
Normal file
123
locale/mail.pt_BR.tr
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
# textdomain: mail
|
||||||
|
The mail could not be sent:=
|
||||||
|
You did not specify any valid recipient.=
|
||||||
|
You have mail! Type /mail to read=Você recebeu e-mail! Tecle /mail para ler
|
||||||
|
You have a new message from @1! Subject: @2=Você tem uma mensagem de @1! Assunto: @2
|
||||||
|
To view it, type /mail=Para visualizar a mensagem, digite /mail
|
||||||
|
You could also use the button in your inventory.=Você também pode usar o botão do seu inventário.
|
||||||
|
Original author=
|
||||||
|
Code=
|
||||||
|
Internationalization=
|
||||||
|
Textures=
|
||||||
|
Audio=
|
||||||
|
Provided by mt-mods=
|
||||||
|
Version: @1=
|
||||||
|
Licenses=
|
||||||
|
Expat (code), WTFPL (textures)=
|
||||||
|
Communication using this system is NOT guaranteed to be private!=A comunicação usando este sistema não possui garantia de privacidade
|
||||||
|
Admins are able to view the messages of any player.=Administradores poderão ler as mensagens de qualquer jogador
|
||||||
|
Contributors=
|
||||||
|
Group by name=
|
||||||
|
Group by contribution=
|
||||||
|
Note=Nota
|
||||||
|
Settings=Ajustes
|
||||||
|
About=Sobre
|
||||||
|
BCC=BCC
|
||||||
|
Cancel=Cancelar
|
||||||
|
Save draft=Salvar rascunho
|
||||||
|
Send=Enviar
|
||||||
|
Subject=Assunto
|
||||||
|
To=Para
|
||||||
|
CC=CC
|
||||||
|
Delete=Apagar
|
||||||
|
New=Novo
|
||||||
|
Edit=Editar
|
||||||
|
Back=Voltar
|
||||||
|
Name=Nome
|
||||||
|
No drafts=Sem rascunhos
|
||||||
|
Trash=
|
||||||
|
Inbox=Entrada
|
||||||
|
Outbox=Enviadas
|
||||||
|
Drafts=Rascunhos
|
||||||
|
Contacts=Contatos
|
||||||
|
Mail lists=Lista de correios
|
||||||
|
Options=Opções
|
||||||
|
Close=Fechar
|
||||||
|
(No subject)=(Sem assunto)
|
||||||
|
Player name=Nome do jogador
|
||||||
|
That name is already in your contacts=Esse nome já consta em sua lista de contatos
|
||||||
|
The contact name cannot be empty.=Informe o nome do destinatário
|
||||||
|
Save=Salvar
|
||||||
|
Maillist name=Nome da lista de discussão
|
||||||
|
Desc=Descrição
|
||||||
|
Players=Jogador
|
||||||
|
That name is already in your mailing lists.=Esse nome ja está sendo usado em sua lista de discussões
|
||||||
|
The mailing list name cannot be empty.=O nome da lista de discussões deve ser informado
|
||||||
|
Mark Read=Marcar como lido
|
||||||
|
Mark Unread=Marcar como não lido
|
||||||
|
Mark Spam=
|
||||||
|
Unmark Spam=
|
||||||
|
Reply=Responder
|
||||||
|
Reply all=Responder Todos
|
||||||
|
Forward=Encaminhar
|
||||||
|
Reply only to the sender=
|
||||||
|
Reply to all involved people=
|
||||||
|
Transfer message to other people=
|
||||||
|
Date=Data
|
||||||
|
From=De
|
||||||
|
Filter=Filtrar
|
||||||
|
Allow multiple selection=Permitir selecionar vários
|
||||||
|
@1 of @2 selected=
|
||||||
|
(Un)select all=Desmarcar todos
|
||||||
|
No mail=Sem e-mails no momento
|
||||||
|
Read=Ler
|
||||||
|
Ascending=Ascendente
|
||||||
|
Descending=Descendente
|
||||||
|
(No description)=(sem descrição)
|
||||||
|
No maillist=Sem lista de discussão
|
||||||
|
Receivers=
|
||||||
|
(Un)mute sender=
|
||||||
|
Add=Adicionar
|
||||||
|
Remove=Remover
|
||||||
|
Reset=
|
||||||
|
Restore=
|
||||||
|
Empty=
|
||||||
|
Trash is empty=
|
||||||
|
From/To=De/Para
|
||||||
|
No contacts=
|
||||||
|
The method of delivery to @1 is invalid.=
|
||||||
|
The recipient @1 could not be identified.=
|
||||||
|
@1 rejected your mail.=
|
||||||
|
Chat notifications=Notificação de conversa
|
||||||
|
Receive a message in the chat when there is a new message=
|
||||||
|
On join notifications=Notificação ao entrar
|
||||||
|
Receive a message at login when inbox isn't empty=
|
||||||
|
HUD notifications=Notificação no HUD
|
||||||
|
Show an HUD notification when inbox isn't empty=
|
||||||
|
Sound notifications=
|
||||||
|
Play a sound when there is a new message=
|
||||||
|
Show unread in different color=Exibir mensagens não lidas em uma cor diferente
|
||||||
|
Show CC/BCC in different color=Exibir mensagens com copia em uma cor diferente
|
||||||
|
Default sorting field=Ordenamento de campo padrão
|
||||||
|
Default sorting direction=
|
||||||
|
Move deleted messages to trash=
|
||||||
|
Automatic marking read=
|
||||||
|
Mark a message as read when opened=
|
||||||
|
Date format=
|
||||||
|
Timezone offset=
|
||||||
|
Offset to add to server time.=
|
||||||
|
Mute list=
|
||||||
|
Notifications=Notificações
|
||||||
|
Message list=Lista de mensagens
|
||||||
|
Fields=
|
||||||
|
Spam=
|
||||||
|
Other=
|
||||||
|
Date and Time=
|
||||||
|
years=
|
||||||
|
months=
|
||||||
|
weeks=
|
||||||
|
days=
|
||||||
|
hours=
|
||||||
|
minuts=
|
||||||
|
seconds=
|
||||||
|
@1 ago=
|
123
locale/mail.ru.tr
Normal file
123
locale/mail.ru.tr
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
# textdomain: mail
|
||||||
|
The mail could not be sent:=Невозможно отправить почту:
|
||||||
|
You did not specify any valid recipient.=Вы не указали получателя.
|
||||||
|
You have mail! Type /mail to read=У вас есть почта! Наберите /mail, чтобы прочитать
|
||||||
|
You have a new message from @1! Subject: @2=У вас новое сообщение от @1! Тема: @2
|
||||||
|
To view it, type /mail=Чтобы посмотреть, наберите /mail
|
||||||
|
You could also use the button in your inventory.=Вы также можете использовать кнопку в Вашем инвентаре.
|
||||||
|
Original author=Автор оригинала
|
||||||
|
Code=Код
|
||||||
|
Internationalization=Перевод
|
||||||
|
Textures=Текстуры
|
||||||
|
Audio=Аудио
|
||||||
|
Provided by mt-mods=Предоставлено mt-mods
|
||||||
|
Version: @1=Версия: @1
|
||||||
|
Licenses=Лицензии
|
||||||
|
Expat (code), WTFPL (textures)=Expat (код), WTFPL (текстуры)
|
||||||
|
Communication using this system is NOT guaranteed to be private!=Конфиденциальность общения с использованием этой системы НЕ гарантируется!
|
||||||
|
Admins are able to view the messages of any player.=Админ может читать сообщения любых игроков.
|
||||||
|
Contributors=Участники
|
||||||
|
Group by name=Группировать по имени
|
||||||
|
Group by contribution=Группировать по участию
|
||||||
|
Note=Заметка
|
||||||
|
Settings=Настройки
|
||||||
|
About=О...
|
||||||
|
BCC=С.копия
|
||||||
|
Cancel=Отмена
|
||||||
|
Save draft=Сохр. черновик
|
||||||
|
Send=Отправить
|
||||||
|
Subject=Тема
|
||||||
|
To=Кому
|
||||||
|
CC=Копия
|
||||||
|
Delete=Удалить
|
||||||
|
New=Новое
|
||||||
|
Edit=Изменить
|
||||||
|
Back=Назад
|
||||||
|
Name=Имя
|
||||||
|
No drafts=Нет черновиков
|
||||||
|
Trash=Корзина
|
||||||
|
Inbox=Входящие
|
||||||
|
Outbox=Исходящие
|
||||||
|
Drafts=Черновики
|
||||||
|
Contacts=Контакты
|
||||||
|
Mail lists=Списки рассылки
|
||||||
|
Options=Опции
|
||||||
|
Close=Закрыть
|
||||||
|
(No subject)=(без темы)
|
||||||
|
Player name=Имя игрока
|
||||||
|
That name is already in your contacts=Это имя уже есть в Ваших контактах
|
||||||
|
The contact name cannot be empty.=Имя контакта не может быть пустым.
|
||||||
|
Save=Сохранить
|
||||||
|
Maillist name=Название списка
|
||||||
|
Desc=Описание
|
||||||
|
Players=Игроки
|
||||||
|
That name is already in your mailing lists.=Это имя уже есть в ваших списках рассылки.
|
||||||
|
The mailing list name cannot be empty.=Название списка не может быть пустым.
|
||||||
|
Mark Read=Отм. прочитано
|
||||||
|
Mark Unread=Отм. непрочитано
|
||||||
|
Mark Spam=Отм. спам
|
||||||
|
Unmark Spam=Снять отм. спам
|
||||||
|
Reply=Ответить
|
||||||
|
Reply all=Ответить всем
|
||||||
|
Forward=Переслать
|
||||||
|
Reply only to the sender=Ответить только отправителю
|
||||||
|
Reply to all involved people=Ответить всем участникам
|
||||||
|
Transfer message to other people=Переслать сообщение другим игрокам
|
||||||
|
Date=Дата
|
||||||
|
From=От
|
||||||
|
Filter=Фильтр
|
||||||
|
Allow multiple selection=Разрешить выбор нескольких
|
||||||
|
@1 of @2 selected=@1 из @2 выбраны
|
||||||
|
(Un)select all=Снять выбор со всех
|
||||||
|
No mail=Нет почты
|
||||||
|
Read=Прочитано
|
||||||
|
Ascending=Возрастание
|
||||||
|
Descending=Убывание
|
||||||
|
(No description)=(Нет описания)
|
||||||
|
No maillist=Не список рассылки
|
||||||
|
Receivers=Получатели
|
||||||
|
(Un)mute sender=Вкл. звук для отправителя
|
||||||
|
Add=Добавить
|
||||||
|
Remove=Удалить
|
||||||
|
Reset=Сбросить
|
||||||
|
Restore=Восстановить
|
||||||
|
Empty=Очистить
|
||||||
|
Trash is empty=Корзина пуста
|
||||||
|
From/To=От/Кому
|
||||||
|
No contacts=Нет контактов
|
||||||
|
The method of delivery to @1 is invalid.=Метод доставки для @1 не действителен.
|
||||||
|
The recipient @1 could not be identified.=Невозможно идентифицировать получателя @1.
|
||||||
|
@1 rejected your mail.=@1 отклонил ваше письмо.
|
||||||
|
Chat notifications=Уведомления в чате
|
||||||
|
Receive a message in the chat when there is a new message=Получать сообщение в чате, когда приходит новое сообщение
|
||||||
|
On join notifications=Уведомления при присоединении
|
||||||
|
Receive a message at login when inbox isn't empty=Получать сообщение при входе, когда есть письма во Входящих
|
||||||
|
HUD notifications=HUD уведомления
|
||||||
|
Show an HUD notification when inbox isn't empty=Показывать уведомление HUD, если папка «Входящие» не пуста
|
||||||
|
Sound notifications=Звуковые уведомления
|
||||||
|
Play a sound when there is a new message=Проигрывать звук, когда приходит новое сообщение
|
||||||
|
Show unread in different color=Показывать не прочтенные други цветом
|
||||||
|
Show CC/BCC in different color=Показывать Копию/Скрытую копию другим цветом
|
||||||
|
Default sorting field=Поле для сортировки по умолчанию
|
||||||
|
Default sorting direction=Направление сортировки по умолчанию
|
||||||
|
Move deleted messages to trash=Перемещать удаленные сообщения в корзину
|
||||||
|
Automatic marking read=Автоматически отмечать прочтение
|
||||||
|
Mark a message as read when opened=Отмечать сообщение как прочитанное при открытии
|
||||||
|
Date format=Формат даты
|
||||||
|
Timezone offset=Временная зона
|
||||||
|
Offset to add to server time.=Добавлять ко времени сервера
|
||||||
|
Mute list=Заглушить список
|
||||||
|
Notifications=Уведомления
|
||||||
|
Message list=Список сообщений
|
||||||
|
Fields=Поля
|
||||||
|
Spam=Спам
|
||||||
|
Other=Другое
|
||||||
|
Date and Time=Дата и Время
|
||||||
|
years=лет
|
||||||
|
months=месяцев
|
||||||
|
weeks=недель
|
||||||
|
days=дней
|
||||||
|
hours=часов
|
||||||
|
minuts=минут
|
||||||
|
seconds=секунд
|
||||||
|
@1 ago=@1 назад
|
123
locale/mail.uk.tr
Normal file
123
locale/mail.uk.tr
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
# textdomain: mail
|
||||||
|
The mail could not be sent:=Неможливо відправити пошту:
|
||||||
|
You did not specify any valid recipient.=Ви не вказали отримувача.
|
||||||
|
You have mail! Type /mail to read=У вас є пошта! Введіть /mail для прочитання
|
||||||
|
You have a new message from @1! Subject: @2=У вас нове повідомлення від @1! Тема: @2
|
||||||
|
To view it, type /mail=Введіть /mail аби прочитати це
|
||||||
|
You could also use the button in your inventory.=Також ви можете використовувати кнопку в вашому інвентарі.
|
||||||
|
Original author=Автор оригіналу
|
||||||
|
Code=Код
|
||||||
|
Internationalization=Переклад
|
||||||
|
Textures=Текстури
|
||||||
|
Audio=Аудіо
|
||||||
|
Provided by mt-mods=Надано mt-mods
|
||||||
|
Version: @1=Версія: @1
|
||||||
|
Licenses=Ліцензії
|
||||||
|
Expat (code), WTFPL (textures)=Expat (код), WTFPL (текстури)
|
||||||
|
Communication using this system is NOT guaranteed to be private!=Конфіденційність використання цієї системи НЕ гарантовано є приватною!
|
||||||
|
Admins are able to view the messages of any player.=Адмін може читати повідомлення всіх гравців.
|
||||||
|
Contributors=Учасники
|
||||||
|
Group by name=Групувати по імені
|
||||||
|
Group by contribution=Групувати по участю
|
||||||
|
Note=Замітка
|
||||||
|
Settings=Налаштування
|
||||||
|
About=Про...
|
||||||
|
BCC=ВСС
|
||||||
|
Cancel=Скасувати
|
||||||
|
Save draft=Збер.чернетку
|
||||||
|
Send=Відправити
|
||||||
|
Subject=Тема
|
||||||
|
To=Кому
|
||||||
|
CC=Копія
|
||||||
|
Delete=Видалити
|
||||||
|
New=Створити
|
||||||
|
Edit=Редагувати
|
||||||
|
Back=Назад
|
||||||
|
Name=Ім'я
|
||||||
|
No drafts=Немає чернеток
|
||||||
|
Trash=Кошик
|
||||||
|
Inbox=Вхідні
|
||||||
|
Outbox=Вихідні
|
||||||
|
Drafts=Чернетки
|
||||||
|
Contacts=Контакти
|
||||||
|
Mail lists=Списки розсилки
|
||||||
|
Options=Опції
|
||||||
|
Close=Закрити
|
||||||
|
(No subject)=(без теми)
|
||||||
|
Player name=Ім'я гравця
|
||||||
|
That name is already in your contacts=Це ім'я вже збережено у ваших контактах
|
||||||
|
The contact name cannot be empty.=Ім'я контакта не може бути пустим.
|
||||||
|
Save=Зберегти
|
||||||
|
Maillist name=Назва списку
|
||||||
|
Desc=Опис
|
||||||
|
Players=Гравці
|
||||||
|
That name is already in your mailing lists.=Це ім'я вже є у ваших списках розсилки.
|
||||||
|
The mailing list name cannot be empty.=Назва списка не може бути пустою.
|
||||||
|
Mark Read=Прочитано
|
||||||
|
Mark Unread=Непрочитано
|
||||||
|
Mark Spam=Відм. спам
|
||||||
|
Unmark Spam=Скас. спам
|
||||||
|
Reply=Відповісти
|
||||||
|
Reply all=Відповісти усім
|
||||||
|
Forward=Переслати
|
||||||
|
Reply only to the sender=Відповісти лише відправнику
|
||||||
|
Reply to all involved people=Відповісти усім учасникам
|
||||||
|
Transfer message to other people=Переслати це повідомлення іншим людям
|
||||||
|
Date=Дата
|
||||||
|
From=Від
|
||||||
|
Filter=Фільтр
|
||||||
|
Allow multiple selection=Дозволити вибір декількох
|
||||||
|
@1 of @2 selected=@1 з @2 вибрані
|
||||||
|
(Un)select all=Зняти вибір з усіх
|
||||||
|
No mail=Немає пошти
|
||||||
|
Read=Прочитано
|
||||||
|
Ascending=Зростання
|
||||||
|
Descending=Зменшення
|
||||||
|
(No description)=(Немає опису)
|
||||||
|
No maillist=Немає списків розсилки
|
||||||
|
Receivers=Отримувачі
|
||||||
|
(Un)mute sender=Увімк. звук для відправника
|
||||||
|
Add=Додати
|
||||||
|
Remove=Видалити
|
||||||
|
Reset=Скинути
|
||||||
|
Restore=Відновити
|
||||||
|
Empty=Очистити
|
||||||
|
Trash is empty=Кошик пустий
|
||||||
|
From/To=Від/До
|
||||||
|
No contacts=Немає контактів
|
||||||
|
The method of delivery to @1 is invalid.=Метод доставки для @1 не дійсний.
|
||||||
|
The recipient @1 could not be identified.=Не знайдено @1.
|
||||||
|
@1 rejected your mail.=@1 відхилив ваше лист.
|
||||||
|
Chat notifications=Повідомлення у чаті
|
||||||
|
Receive a message in the chat when there is a new message=Отримувати повідомленння у чаті при отриманні нового повідомлення
|
||||||
|
On join notifications=Повідомлення при приєднанні
|
||||||
|
Receive a message at login when inbox isn't empty=Отримувати повідомлення при приєднанні коли у теці «Вхідні» є нові листи
|
||||||
|
HUD notifications=HUD повідомлення
|
||||||
|
Show an HUD notification when inbox isn't empty=Показувати HUD повідомлення коли у теці «Вхідні» є нові листи
|
||||||
|
Sound notifications=Звукові повідомлення
|
||||||
|
Play a sound when there is a new message=Програвати звук при новому повідомленні
|
||||||
|
Show unread in different color=Показувати непрочитані іншим кольором
|
||||||
|
Show CC/BCC in different color=Показувати копію/приховану копію іншим кольором
|
||||||
|
Default sorting field=Поле для сортування за замовч.
|
||||||
|
Default sorting direction=Напрям сортування за замовч.
|
||||||
|
Move deleted messages to trash=Переміщати видалені повідомлення до кошика
|
||||||
|
Automatic marking read=Автоматично відмічати прочитані
|
||||||
|
Mark a message as read when opened=Відмічати повідомлення як прочитане, коли відкрито
|
||||||
|
Date format=Формат дати
|
||||||
|
Timezone offset=Часовий пояс
|
||||||
|
Offset to add to server time.=Додавати до часу сервера.
|
||||||
|
Mute list=Заглушити список
|
||||||
|
Notifications=Повідомлення
|
||||||
|
Message list=Список повідомлень
|
||||||
|
Fields=Поля
|
||||||
|
Spam=Спам
|
||||||
|
Other=Інше
|
||||||
|
Date and Time=Дата й час
|
||||||
|
years=років
|
||||||
|
months=місяців
|
||||||
|
weeks=тижнів
|
||||||
|
days=днів
|
||||||
|
hours=годин
|
||||||
|
minuts=хвилин
|
||||||
|
seconds=секунд
|
||||||
|
@1 ago=@1 тому
|
129
locale/mail.zh_CN.tr
Normal file
129
locale/mail.zh_CN.tr
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
# textdomain: mail
|
||||||
|
The mail could not be sent:=无法发送邮件:
|
||||||
|
You did not specify any valid recipient.=
|
||||||
|
You have mail! Type /mail to read=您有新邮件,请使用 /mail 查看。
|
||||||
|
You have a new message from @1! Subject: @2=您有一封来自 @1 的新邮件,主题为“@2”。
|
||||||
|
To view it, type /mail=请使用 /mail 命令查看。
|
||||||
|
You could also use the button in your inventory.=您也可以使用物品清单里的按键。
|
||||||
|
Original author=
|
||||||
|
Code=
|
||||||
|
Internationalization=
|
||||||
|
Textures=
|
||||||
|
Audio=
|
||||||
|
Provided by mt-mods=由 mt-mods 提供
|
||||||
|
Version: @1=
|
||||||
|
Licenses=许可证
|
||||||
|
Expat (code), WTFPL (textures)=Expat(代码),WTFPL(材质)
|
||||||
|
Communication using this system is NOT guaranteed to be private!=这个系统不适用于私密沟通!
|
||||||
|
Admins are able to view the messages of any player.=管理员可以查看所有玩家的邮件。
|
||||||
|
Contributors=贡献者
|
||||||
|
Group by name=
|
||||||
|
Group by contribution=
|
||||||
|
Note=备注
|
||||||
|
Settings=设置
|
||||||
|
About=关于
|
||||||
|
BCC=密送
|
||||||
|
Cancel=取消
|
||||||
|
Save draft=保存草稿
|
||||||
|
Send=发送
|
||||||
|
Subject=主题
|
||||||
|
To=收件人
|
||||||
|
CC=抄送
|
||||||
|
Delete=删除
|
||||||
|
New=新
|
||||||
|
Edit=编辑
|
||||||
|
Back=返回
|
||||||
|
Name=名字
|
||||||
|
#if new means new mail, it would be New=新邮件
|
||||||
|
No drafts=没有草稿
|
||||||
|
Trash=垃圾箱
|
||||||
|
Inbox=收件箱
|
||||||
|
Outbox=已发送
|
||||||
|
Drafts=草稿
|
||||||
|
Contacts=通讯录
|
||||||
|
Mail lists=建组
|
||||||
|
Options=选项
|
||||||
|
Close=关闭
|
||||||
|
(No subject)=(无主题)
|
||||||
|
Player name=玩家名字
|
||||||
|
That name is already in your contacts=这个玩家已经在您的通讯录里。
|
||||||
|
The contact name cannot be empty.=联系人名字不能为空。
|
||||||
|
Save=保存
|
||||||
|
Maillist name=邮件列表名称
|
||||||
|
Desc=描述
|
||||||
|
Players=玩家
|
||||||
|
That name is already in your mailing lists.=这个玩家已经在您的邮件列表里。
|
||||||
|
The mailing list name cannot be empty.=邮件列表名称不能为空。
|
||||||
|
Mark Read=标记为已读
|
||||||
|
Mark Unread=标记为未读
|
||||||
|
Mark Spam=标记为垃圾邮件
|
||||||
|
Unmark Spam=取消标记为垃圾邮件
|
||||||
|
Reply=回复
|
||||||
|
Reply all=回复所有
|
||||||
|
Forward=转发
|
||||||
|
Reply only to the sender=只回复给发件人
|
||||||
|
Reply to all involved people=回复给所有人
|
||||||
|
Transfer message to other people=将邮件转发给其他人
|
||||||
|
Date=时间
|
||||||
|
From=发件人
|
||||||
|
Filter=筛选
|
||||||
|
Allow multiple selection=允许多选
|
||||||
|
@1 of @2 selected=已选中 @2 项中的 @1 项
|
||||||
|
(Un)select all=(取消)选中所有
|
||||||
|
No mail=无邮件
|
||||||
|
Read=浏览
|
||||||
|
Ascending=升序
|
||||||
|
Descending=降序
|
||||||
|
(No description)=(无描述)
|
||||||
|
No maillist=无邮件列表
|
||||||
|
Receivers=收件人
|
||||||
|
(Un)mute sender=屏蔽或取消屏蔽发件人
|
||||||
|
Add=添加
|
||||||
|
Remove=移除
|
||||||
|
Reset=重置
|
||||||
|
Restore=恢复
|
||||||
|
Empty=空的
|
||||||
|
Trash is empty=垃圾箱为空
|
||||||
|
From/To=发件人或收件人
|
||||||
|
No contacts=无联系人
|
||||||
|
The method of delivery to @1 is invalid.=无法将邮件发送给 @1。
|
||||||
|
The recipient @1 could not be identified.=无法找到收件人“@1”。
|
||||||
|
@1 rejected your mail.=@1 不接收您的邮件。
|
||||||
|
Chat notifications=在聊天记录中显示通知
|
||||||
|
Receive a message in the chat when there is a new message=收到新邮件时在聊天记录中显示通知。
|
||||||
|
On join notifications=加入服务器时显示通知
|
||||||
|
Receive a message at login when inbox isn't empty=加入服务器且由新邮件时显示通知。
|
||||||
|
HUD notifications=HUD 通知
|
||||||
|
Show an HUD notification when inbox isn't empty=收到新邮件时通过 HUD 显示通知。
|
||||||
|
Sound notifications=提示音
|
||||||
|
Play a sound when there is a new message=收到新邮件时播放提示音
|
||||||
|
Show unread in different color=使用不同的颜色标记未读邮件
|
||||||
|
Show CC/BCC in different color=使用不同的颜色标记抄送和密送邮件
|
||||||
|
Default sorting field=排序依据
|
||||||
|
Default sorting direction=排序方向
|
||||||
|
Move deleted messages to trash=将已删除的邮件移至垃圾箱
|
||||||
|
Automatic marking read=自动将邮件标记为已读
|
||||||
|
Mark a message as read when opened=打开邮件时自动将邮件标记为已读
|
||||||
|
Date format=日期格式
|
||||||
|
Timezone offset=
|
||||||
|
Offset to add to server time.=
|
||||||
|
Mute list=屏蔽列表
|
||||||
|
Notifications=通知
|
||||||
|
Message list=邮件列表
|
||||||
|
Fields=
|
||||||
|
Spam=垃圾邮件
|
||||||
|
Other=其它
|
||||||
|
Date and Time=
|
||||||
|
years=年
|
||||||
|
months=月
|
||||||
|
weeks=周
|
||||||
|
days=天
|
||||||
|
hours=小时
|
||||||
|
minuts=分钟
|
||||||
|
seconds=秒
|
||||||
|
@1 ago=@1前
|
||||||
|
|
||||||
|
|
||||||
|
##### not used anymore #####
|
||||||
|
|
||||||
|
Version=版本
|
|
@ -1,55 +1,128 @@
|
||||||
# textdomain: mail
|
# textdomain: mail
|
||||||
|
The mail could not be sent:=無法發送郵件:
|
||||||
|
You did not specify any valid recipient.=
|
||||||
|
You have mail! Type /mail to read=您有新郵件,請使用 /mail 查看。
|
||||||
|
You have a new message from @1! Subject: @2=您有一封來自 @1 的新郵件,主題為“@2”。
|
||||||
|
To view it, type /mail=請使用 /mail 指令查看。
|
||||||
|
You could also use the button in your inventory.=您也可以使用物品欄裡的按鍵。
|
||||||
|
Original author=
|
||||||
|
Code=
|
||||||
|
Internationalization=
|
||||||
|
Textures=
|
||||||
|
Audio=
|
||||||
|
Provided by mt-mods=由 mt-mods 提供
|
||||||
|
Version: @1=
|
||||||
|
Licenses=許可證
|
||||||
|
Expat (code), WTFPL (textures)=Expat(源碼),WTFPL(材質)
|
||||||
|
Communication using this system is NOT guaranteed to be private!=此系統不適合私密交流!
|
||||||
|
Admins are able to view the messages of any player.=管理員可以查看所有玩家的郵件。
|
||||||
|
Contributors=貢獻者
|
||||||
|
Group by name=
|
||||||
|
Group by contribution=
|
||||||
|
Note=備註
|
||||||
|
Settings=設置
|
||||||
|
About=關於
|
||||||
BCC=密件副本
|
BCC=密件副本
|
||||||
Cancel=取消
|
Cancel=取消
|
||||||
Save draft=儲存草稿
|
Save draft=儲存草稿
|
||||||
Send=發送
|
Send=發送
|
||||||
|
Subject=主旨
|
||||||
|
To=收件人
|
||||||
|
CC=副本
|
||||||
Delete=刪除
|
Delete=刪除
|
||||||
New=新建
|
New=新建
|
||||||
No drafts=沒有草稿
|
|
||||||
Edit=編輯
|
Edit=編輯
|
||||||
Subject=主旨
|
|
||||||
Player name=玩家名稱
|
|
||||||
your contacts.=
|
|
||||||
The contact=
|
|
||||||
Save=儲存
|
|
||||||
That name=
|
|
||||||
is already in=
|
|
||||||
name cannot=
|
|
||||||
be empty.=
|
|
||||||
Back=返回
|
Back=返回
|
||||||
Note=備註
|
Name=名稱
|
||||||
Maillist name=郵件列表名稱
|
No drafts=沒有草稿
|
||||||
Desc=描述
|
Trash=垃圾箱
|
||||||
Players=玩家
|
|
||||||
your maillists.=
|
|
||||||
The maillist=
|
|
||||||
Mark Read=標記已讀
|
|
||||||
Mark Unread=標記未讀
|
|
||||||
From=寄件者
|
|
||||||
(No description)=(沒有描述)
|
|
||||||
No maillist=沒有郵件列表
|
|
||||||
CC=副本
|
|
||||||
Read=閱讀
|
|
||||||
Ascending=
|
|
||||||
Descending=
|
|
||||||
Filter=
|
|
||||||
Allow multiple selection=
|
|
||||||
selected=
|
|
||||||
(Un)select all=
|
|
||||||
No mail=沒有郵件
|
|
||||||
Inbox=收件箱
|
Inbox=收件箱
|
||||||
Sent messages=寄件備份
|
Outbox=寄件備份
|
||||||
Drafts=草稿
|
Drafts=草稿
|
||||||
Contacts=聯繫人
|
Contacts=聯繫人
|
||||||
Mail lists=郵件列表
|
Mail lists=郵件列表
|
||||||
About=關於
|
Options=選項
|
||||||
Close=關閉
|
Close=關閉
|
||||||
(No subject)=(沒有主旨)
|
(No subject)=(沒有主旨)
|
||||||
Date=日期
|
Player name=玩家名稱
|
||||||
|
That name is already in your contacts=玩家已經在您的通訊錄中。
|
||||||
|
The contact name cannot be empty.=聯繫人名字不能為空。
|
||||||
|
Save=儲存
|
||||||
|
Maillist name=郵件列表名稱
|
||||||
|
Desc=描述
|
||||||
|
Players=玩家
|
||||||
|
That name is already in your mailing lists.=玩家已經在您的郵件列表中。
|
||||||
|
The mailing list name cannot be empty.=郵件列表名稱不能為空。
|
||||||
|
Mark Read=標記已讀
|
||||||
|
Mark Unread=標記未讀
|
||||||
|
Mark Spam=標記垃圾郵件
|
||||||
|
Unmark Spam=取消標記垃圾郵件
|
||||||
Reply=回覆
|
Reply=回覆
|
||||||
Reply all=回覆所有人
|
Reply all=回覆所有人
|
||||||
Forward=轉寄
|
Forward=轉寄
|
||||||
|
Reply only to the sender=僅回覆給寄件人
|
||||||
|
Reply to all involved people=回覆給所有人
|
||||||
|
Transfer message to other people=將郵件轉發給所有人
|
||||||
|
Date=日期
|
||||||
|
From=寄件人
|
||||||
|
Filter=篩選
|
||||||
|
Allow multiple selection=允許多選
|
||||||
|
@1 of @2 selected=已選擇 @2 項中的 @1 項。
|
||||||
|
(Un)select all=(取消)選中所有
|
||||||
|
No mail=沒有郵件
|
||||||
|
Read=閱讀
|
||||||
|
Ascending=
|
||||||
|
Descending=
|
||||||
|
(No description)=(沒有描述)
|
||||||
|
No maillist=沒有郵件列表
|
||||||
|
Receivers=收件人
|
||||||
|
(Un)mute sender=(取消)屏蔽寄件人
|
||||||
Add=加入
|
Add=加入
|
||||||
Remove=移除
|
Remove=移除
|
||||||
Name=名稱
|
Reset=重置
|
||||||
To=收件人
|
Restore=恢復
|
||||||
|
Empty=空
|
||||||
|
Trash is empty=垃圾箱為空
|
||||||
|
From/To=寄件人或收件人
|
||||||
|
No contacts=沒有聯繫人
|
||||||
|
The method of delivery to @1 is invalid.=無法將郵件發送給 @1。
|
||||||
|
The recipient @1 could not be identified.=無法找到收件人“@1”。
|
||||||
|
@1 rejected your mail.=@1 不接收您的郵件
|
||||||
|
Chat notifications=在聊天室中顯示通知
|
||||||
|
Receive a message in the chat when there is a new message=收到新郵件時在聊天室中顯示通知。
|
||||||
|
On join notifications=加入伺服器時顯示通知
|
||||||
|
Receive a message at login when inbox isn't empty=加入伺服器且有新郵件時顯示通知。
|
||||||
|
HUD notifications=HUD 通知
|
||||||
|
Show an HUD notification when inbox isn't empty=收到新郵件時在 HUD 中顯示通知。
|
||||||
|
Sound notifications=提示聲
|
||||||
|
Play a sound when there is a new message=收到新郵件時播放提示聲
|
||||||
|
Show unread in different color=使用不同的顏色標記未讀郵件
|
||||||
|
Show CC/BCC in different color=使用不同的顏色標記副本和密件副本
|
||||||
|
Default sorting field=排序方式
|
||||||
|
Default sorting direction=排序順序
|
||||||
|
Move deleted messages to trash=將已刪除的郵件移至垃圾箱
|
||||||
|
Automatic marking read=自動將郵件標記已讀
|
||||||
|
Mark a message as read when opened=打開郵件時自動將郵件標記已讀
|
||||||
|
Date format=日期格式
|
||||||
|
Timezone offset=
|
||||||
|
Offset to add to server time.=
|
||||||
|
Mute list=屏蔽列表
|
||||||
|
Notifications=通知
|
||||||
|
Message list=郵件列表
|
||||||
|
Fields=
|
||||||
|
Spam=垃圾郵件
|
||||||
|
Other=其他
|
||||||
|
Date and Time=
|
||||||
|
years=年
|
||||||
|
months=月
|
||||||
|
weeks=周
|
||||||
|
days=日
|
||||||
|
hours=小時
|
||||||
|
minuts=分鐘
|
||||||
|
seconds=秒
|
||||||
|
@1 ago=@1前
|
||||||
|
|
||||||
|
|
||||||
|
##### not used anymore #####
|
||||||
|
|
||||||
|
Version=版本
|
||||||
|
|
|
@ -1,55 +1,123 @@
|
||||||
# textdomain: mail
|
# textdomain: mail
|
||||||
|
The mail could not be sent:=
|
||||||
|
You did not specify any valid recipient.=
|
||||||
|
You have mail! Type /mail to read=
|
||||||
|
You have a new message from @1! Subject: @2=
|
||||||
|
To view it, type /mail=
|
||||||
|
You could also use the button in your inventory.=
|
||||||
|
Original author=
|
||||||
|
Code=
|
||||||
|
Internationalization=
|
||||||
|
Textures=
|
||||||
|
Audio=
|
||||||
|
Provided by mt-mods=
|
||||||
|
Version: @1=
|
||||||
|
Licenses=
|
||||||
|
Expat (code), WTFPL (textures)=
|
||||||
|
Communication using this system is NOT guaranteed to be private!=
|
||||||
|
Admins are able to view the messages of any player.=
|
||||||
|
Contributors=
|
||||||
|
Group by name=
|
||||||
|
Group by contribution=
|
||||||
|
Note=
|
||||||
|
Settings=
|
||||||
|
About=
|
||||||
BCC=
|
BCC=
|
||||||
Cancel=
|
Cancel=
|
||||||
Save draft=
|
Save draft=
|
||||||
Send=
|
Send=
|
||||||
|
Subject=
|
||||||
|
To=
|
||||||
|
CC=
|
||||||
Delete=
|
Delete=
|
||||||
New=
|
New=
|
||||||
No drafts=
|
|
||||||
Edit=
|
Edit=
|
||||||
Subject=
|
|
||||||
Player name=
|
|
||||||
your contacts.=
|
|
||||||
The contact=
|
|
||||||
Save=
|
|
||||||
That name=
|
|
||||||
is already in=
|
|
||||||
name cannot=
|
|
||||||
be empty.=
|
|
||||||
Back=
|
Back=
|
||||||
Note=
|
Name=
|
||||||
Maillist name=
|
No drafts=
|
||||||
Desc=
|
Trash=
|
||||||
Players=
|
|
||||||
your maillists.=
|
|
||||||
The maillist=
|
|
||||||
Mark Read=
|
|
||||||
Mark Unread=
|
|
||||||
From=
|
|
||||||
(No description)=
|
|
||||||
No maillist=
|
|
||||||
CC=
|
|
||||||
Read=
|
|
||||||
Ascending=
|
|
||||||
Descending=
|
|
||||||
Filter=
|
|
||||||
Allow multiple selection=
|
|
||||||
selected=
|
|
||||||
(Un)select all=
|
|
||||||
No mail=
|
|
||||||
Inbox=
|
Inbox=
|
||||||
Sent messages=
|
Outbox=
|
||||||
Drafts=
|
Drafts=
|
||||||
Contacts=
|
Contacts=
|
||||||
Mail lists=
|
Mail lists=
|
||||||
About=
|
Options=
|
||||||
Close=
|
Close=
|
||||||
(No subject)=
|
(No subject)=
|
||||||
Date=
|
Player name=
|
||||||
|
That name is already in your contacts=
|
||||||
|
The contact name cannot be empty.=
|
||||||
|
Save=
|
||||||
|
Maillist name=
|
||||||
|
Desc=
|
||||||
|
Players=
|
||||||
|
That name is already in your mailing lists.=
|
||||||
|
The mailing list name cannot be empty.=
|
||||||
|
Mark Read=
|
||||||
|
Mark Unread=
|
||||||
|
Mark Spam=
|
||||||
|
Unmark Spam=
|
||||||
Reply=
|
Reply=
|
||||||
Reply all=
|
Reply all=
|
||||||
Forward=
|
Forward=
|
||||||
|
Reply only to the sender=
|
||||||
|
Reply to all involved people=
|
||||||
|
Transfer message to other people=
|
||||||
|
Date=
|
||||||
|
From=
|
||||||
|
Filter=
|
||||||
|
Allow multiple selection=
|
||||||
|
@1 of @2 selected=
|
||||||
|
(Un)select all=
|
||||||
|
No mail=
|
||||||
|
Read=
|
||||||
|
Ascending=
|
||||||
|
Descending=
|
||||||
|
(No description)=
|
||||||
|
No maillist=
|
||||||
|
Receivers=
|
||||||
|
(Un)mute sender=
|
||||||
Add=
|
Add=
|
||||||
Remove=
|
Remove=
|
||||||
Name=
|
Reset=
|
||||||
To=
|
Restore=
|
||||||
|
Empty=
|
||||||
|
Trash is empty=
|
||||||
|
From/To=
|
||||||
|
No contacts=
|
||||||
|
The method of delivery to @1 is invalid.=
|
||||||
|
The recipient @1 could not be identified.=
|
||||||
|
@1 rejected your mail.=
|
||||||
|
Chat notifications=
|
||||||
|
Receive a message in the chat when there is a new message=
|
||||||
|
On join notifications=
|
||||||
|
Receive a message at login when inbox isn't empty=
|
||||||
|
HUD notifications=
|
||||||
|
Show an HUD notification when inbox isn't empty=
|
||||||
|
Sound notifications=
|
||||||
|
Play a sound when there is a new message=
|
||||||
|
Show unread in different color=
|
||||||
|
Show CC/BCC in different color=
|
||||||
|
Default sorting field=
|
||||||
|
Default sorting direction=
|
||||||
|
Move deleted messages to trash=
|
||||||
|
Automatic marking read=
|
||||||
|
Mark a message as read when opened=
|
||||||
|
Date format=
|
||||||
|
Timezone offset=
|
||||||
|
Offset to add to server time.=
|
||||||
|
Mute list=
|
||||||
|
Notifications=
|
||||||
|
Message list=
|
||||||
|
Fields=
|
||||||
|
Spam=
|
||||||
|
Other=
|
||||||
|
Date and Time=
|
||||||
|
years=
|
||||||
|
months=
|
||||||
|
weeks=
|
||||||
|
days=
|
||||||
|
hours=
|
||||||
|
minuts=
|
||||||
|
seconds=
|
||||||
|
@1 ago=
|
||||||
|
|
157
migrate.lua
157
migrate.lua
|
@ -1,13 +1,13 @@
|
||||||
|
|
||||||
local STORAGE_VERSION_KEY = "@@version"
|
local STORAGE_VERSION_KEY = "@@version"
|
||||||
|
local CURRENT_VERSION = 3.1
|
||||||
|
|
||||||
local function migrate_v1_to_v3()
|
local function migrate_v1_to_v3()
|
||||||
local file = io.open(minetest.get_worldpath().."/mail.db", "r")
|
local file = io.open(core.get_worldpath().."/mail.db", "r")
|
||||||
assert(file)
|
assert(file)
|
||||||
print("[mail] Migration from v1 to v3 database")
|
print("[mail] Migration from v1 to v3 database")
|
||||||
|
|
||||||
local data = file:read("*a")
|
local data = file:read("*a")
|
||||||
local oldmails = minetest.deserialize(data)
|
local oldmails = core.deserialize(data)
|
||||||
file:close()
|
file:close()
|
||||||
|
|
||||||
for name, oldmessages in pairs(oldmails) do
|
for name, oldmessages in pairs(oldmails) do
|
||||||
|
@ -28,7 +28,7 @@ local function migrate_v1_to_v3()
|
||||||
|
|
||||||
-- rename file
|
-- rename file
|
||||||
print("[mail,v1] migration done, renaming old mail.db")
|
print("[mail,v1] migration done, renaming old mail.db")
|
||||||
os.rename(minetest.get_worldpath().."/mail.db", minetest.get_worldpath().."/mail.db.old")
|
os.rename(core.get_worldpath().."/mail.db", core.get_worldpath().."/mail.db.old")
|
||||||
end
|
end
|
||||||
|
|
||||||
local function read_json_file(path)
|
local function read_json_file(path)
|
||||||
|
@ -36,7 +36,7 @@ local function read_json_file(path)
|
||||||
local content = {}
|
local content = {}
|
||||||
if file then
|
if file then
|
||||||
local json = file:read("*a")
|
local json = file:read("*a")
|
||||||
content = minetest.parse_json(json or "[]") or {}
|
content = core.parse_json(json or "[]") or {}
|
||||||
file:close()
|
file:close()
|
||||||
end
|
end
|
||||||
return content
|
return content
|
||||||
|
@ -44,13 +44,13 @@ end
|
||||||
|
|
||||||
-- migrate from v2 to v3 database
|
-- migrate from v2 to v3 database
|
||||||
local function migrate_v2_to_v3()
|
local function migrate_v2_to_v3()
|
||||||
local maildir = minetest.get_worldpath().."/mails"
|
local maildir = core.get_worldpath().."/mails"
|
||||||
minetest.mkdir(maildir) -- if necessary (eg. first login)
|
core.mkdir(maildir) -- if necessary (eg. first login)
|
||||||
print("[mail] Migration from v2 to v3 database")
|
print("[mail] Migration from v2 to v3 database")
|
||||||
|
|
||||||
-- defer execution until auth-handler ready (first server-step)
|
-- defer execution until auth-handler ready (first server-step)
|
||||||
minetest.after(0, function()
|
core.after(0, function()
|
||||||
for playername, _ in minetest.get_auth_handler().iterate() do
|
for playername, _ in core.get_auth_handler().iterate() do
|
||||||
local entry = mail.get_storage_entry(playername)
|
local entry = mail.get_storage_entry(playername)
|
||||||
|
|
||||||
local player_contacts = read_json_file(maildir .. "/contacts/" .. playername .. ".json")
|
local player_contacts = read_json_file(maildir .. "/contacts/" .. playername .. ".json")
|
||||||
|
@ -80,20 +80,149 @@ local function migrate_v2_to_v3()
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
local function search_box(playername, box, uuid)
|
||||||
|
local e = mail.get_storage_entry(playername)
|
||||||
|
for _, m in ipairs(e[box]) do
|
||||||
|
if m.id == uuid then
|
||||||
|
return { time = m.time, from = m.from, to = m.to, cc = m.cc, bcc = m.bcc, subject = m.subject, body = m.body } end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function search_boxes(playername, boxes, uuid)
|
||||||
|
local result
|
||||||
|
for _, b in ipairs(boxes) do
|
||||||
|
result = search_box(playername, b, uuid)
|
||||||
|
if result then return result end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function is_uuid_existing(uuid)
|
||||||
|
local boxes = {"inbox", "outbox", "drafts", "trash"}
|
||||||
|
if mail.storage.get_keys then
|
||||||
|
for _, k in ipairs(mail.storage:get_keys()) do
|
||||||
|
if string.sub(k,1,5) == "mail/" then
|
||||||
|
local p = string.sub(k, 6)
|
||||||
|
local result = search_boxes(p, boxes, uuid)
|
||||||
|
if result then return result end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for p, _ in core.get_auth_handler().iterate() do
|
||||||
|
local result = search_boxes(p, boxes, uuid)
|
||||||
|
if result then return result end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function are_message_sames(a, b)
|
||||||
|
return a.time == b.time
|
||||||
|
and a.from == b.from
|
||||||
|
and a.to == b.to
|
||||||
|
and a.cc == b.cc
|
||||||
|
and a.bcc == b.bcc
|
||||||
|
and a.subject == b.subject
|
||||||
|
and a.body == b.body
|
||||||
|
end
|
||||||
|
|
||||||
|
local function replace_other_player_message_uuid(p, m, uuid, new_uuid)
|
||||||
|
local er = mail.get_storage_entry(p)
|
||||||
|
for _, r in ipairs(er.inbox) do
|
||||||
|
if r.id == uuid and not are_message_sames(m, r) then
|
||||||
|
r.id = new_uuid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for _, r in ipairs(er.outbox) do
|
||||||
|
if r.id == uuid and not are_message_sames(m, r) then
|
||||||
|
r.id = new_uuid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for _, r in ipairs(er.drafts) do
|
||||||
|
if r.id == uuid and not are_message_sames(m, r) then
|
||||||
|
r.id = new_uuid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for _, r in ipairs(er.trash) do
|
||||||
|
if r.id == uuid and not are_message_sames(m, r) then
|
||||||
|
r.id = new_uuid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
mail.set_storage_entry(p, er)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function fix_box_duplicate_uuids(playername, box)
|
||||||
|
local e = mail.get_storage_entry(playername)
|
||||||
|
for _, m in ipairs(e[box]) do
|
||||||
|
local uuid = m.id
|
||||||
|
local exists = is_uuid_existing(uuid)
|
||||||
|
if exists and not are_message_sames(exists, m) then
|
||||||
|
local new_uuid = mail.new_uuid() -- generates a new uuid to replace doublons
|
||||||
|
if mail.storage.get_keys then
|
||||||
|
for _, k in ipairs(mail.storage:get_keys()) do
|
||||||
|
if string.sub(k,1,5) == "mail/" then
|
||||||
|
local p = string.sub(k, 6)
|
||||||
|
replace_other_player_message_uuid(p, m, uuid, new_uuid)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for p, _ in core.get_auth_handler().iterate() do
|
||||||
|
replace_other_player_message_uuid(p, m, uuid, new_uuid)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function fix_player_duplicate_uuids(playername)
|
||||||
|
fix_box_duplicate_uuids(playername, "inbox")
|
||||||
|
fix_box_duplicate_uuids(playername, "outbox")
|
||||||
|
fix_box_duplicate_uuids(playername, "drafts")
|
||||||
|
fix_box_duplicate_uuids(playername, "trash")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- repair database for uuid doublons
|
||||||
|
local function repair_storage()
|
||||||
|
-- iterate through players
|
||||||
|
-- get_keys() was introduced in 5.7
|
||||||
|
if mail.storage.get_keys then
|
||||||
|
for _, k in ipairs(mail.storage:get_keys()) do
|
||||||
|
if string.sub(k,1,5) == "mail/" then
|
||||||
|
local p = string.sub(k, 6)
|
||||||
|
fix_player_duplicate_uuids(p)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
core.after(0, function()
|
||||||
|
for p, _ in core.get_auth_handler().iterate() do
|
||||||
|
fix_player_duplicate_uuids(p)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function mail.migrate()
|
function mail.migrate()
|
||||||
-- check for v2 storage first, v1-migration might have set the v3-flag already
|
-- check for v2 storage first, v1-migration might have set the v3-flag already
|
||||||
local version = mail.storage:get_int(STORAGE_VERSION_KEY)
|
local version = mail.storage:get_float(STORAGE_VERSION_KEY)
|
||||||
if version < 3 then
|
if version < math.floor(CURRENT_VERSION) then
|
||||||
-- v2 to v3
|
-- v2 to v3
|
||||||
migrate_v2_to_v3()
|
migrate_v2_to_v3()
|
||||||
mail.storage:set_int(STORAGE_VERSION_KEY, 3)
|
mail.storage:set_float(STORAGE_VERSION_KEY, CURRENT_VERSION)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- check for v1 storage
|
-- check for v1 storage
|
||||||
local v1_file = io.open(minetest.get_worldpath().."/mail.db", "r")
|
local v1_file = io.open(core.get_worldpath().."/mail.db", "r")
|
||||||
if v1_file then
|
if v1_file then
|
||||||
-- v1 to v3
|
-- v1 to v3
|
||||||
migrate_v1_to_v3()
|
migrate_v1_to_v3()
|
||||||
mail.storage:set_int(STORAGE_VERSION_KEY, 3)
|
mail.storage:set_float(STORAGE_VERSION_KEY, CURRENT_VERSION)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- repair storage for uuid doublons
|
||||||
|
if version < CURRENT_VERSION then
|
||||||
|
repair_storage()
|
||||||
|
mail.storage:set_float(STORAGE_VERSION_KEY, CURRENT_VERSION)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
3
mod.conf
3
mod.conf
|
@ -1,3 +1,4 @@
|
||||||
name = mail
|
name = mail
|
||||||
description = ingame mail-system
|
description = ingame mail-system
|
||||||
optional_depends = canonical_name,default,mtt,unified_inventory
|
|
||||||
|
optional_depends = canonical_name,default,mtt,unified_inventory,sfinv_buttons,beerchat
|
||||||
|
|
2
mtt.lua
2
mtt.lua
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
mtt.register("setup", function(callback)
|
mtt.register("setup", function(callback)
|
||||||
-- create test players
|
-- create test players
|
||||||
local auth_handler = minetest.get_auth_handler()
|
local auth_handler = core.get_auth_handler()
|
||||||
auth_handler.set_password("player1", "")
|
auth_handler.set_password("player1", "")
|
||||||
auth_handler.set_password("player2", "")
|
auth_handler.set_password("player2", "")
|
||||||
auth_handler.set_password("player3", "")
|
auth_handler.set_password("player3", "")
|
||||||
|
|
14
onjoin.lua
14
onjoin.lua
|
@ -1,5 +1,8 @@
|
||||||
minetest.register_on_joinplayer(function(player)
|
-- translation
|
||||||
minetest.after(2, function(name)
|
local S = mail.S
|
||||||
|
|
||||||
|
core.register_on_joinplayer(function(player)
|
||||||
|
core.after(2, function(name)
|
||||||
local entry = mail.get_storage_entry(name)
|
local entry = mail.get_storage_entry(name)
|
||||||
local messages = entry.inbox
|
local messages = entry.inbox
|
||||||
mail.hud_update(name, messages)
|
mail.hud_update(name, messages)
|
||||||
|
@ -12,10 +15,9 @@ minetest.register_on_joinplayer(function(player)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if unreadcount > 0 then
|
if unreadcount > 0 and mail.get_setting(name, "onjoin_notifications") then
|
||||||
minetest.chat_send_player(name,
|
core.chat_send_player(name,
|
||||||
minetest.colorize("#00f529", "(" .. unreadcount .. ") You have mail! Type /mail to read"))
|
core.colorize(mail.get_color("new"), "(" .. unreadcount .. ") " .. S("You have mail! Type /mail to read")))
|
||||||
|
|
||||||
end
|
end
|
||||||
end, player:get_player_name())
|
end, player:get_player_name())
|
||||||
end)
|
end)
|
||||||
|
|
53
player_recipients.lua
Normal file
53
player_recipients.lua
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
-- translation
|
||||||
|
local S = mail.S
|
||||||
|
|
||||||
|
local has_canonical_name = core.get_modpath("canonical_name")
|
||||||
|
|
||||||
|
mail.register_on_player_receive(function(name, msg)
|
||||||
|
-- add to inbox
|
||||||
|
local entry = mail.get_storage_entry(name)
|
||||||
|
table.insert(entry.inbox, msg)
|
||||||
|
mail.set_storage_entry(name, entry)
|
||||||
|
|
||||||
|
-- notify recipients that happen to be online
|
||||||
|
local mail_alert = S("You have a new message from @1! Subject: @2", msg.from, msg.subject) ..
|
||||||
|
"\n" .. S("To view it, type /mail")
|
||||||
|
local inventory_alert = S("You could also use the button in your inventory.")
|
||||||
|
local player = core.get_player_by_name(name)
|
||||||
|
if player then
|
||||||
|
if mail.get_setting(name, "chat_notifications") == true then
|
||||||
|
core.chat_send_player(name, mail_alert)
|
||||||
|
if core.get_modpath("unified_inventory") or core.get_modpath("sfinv_buttons") then
|
||||||
|
core.chat_send_player(name, inventory_alert)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if mail.get_setting(name, "sound_notifications") == true then
|
||||||
|
core.sound_play("mail_notif", {to_player=name})
|
||||||
|
end
|
||||||
|
local receiver_entry = mail.get_storage_entry(name)
|
||||||
|
local receiver_messages = receiver_entry.inbox
|
||||||
|
mail.hud_update(name, receiver_messages)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
mail.register_recipient_handler(function(_, pname)
|
||||||
|
if not core.player_exists(pname) then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
return true, function(msg)
|
||||||
|
for _, on_player_receive in ipairs(mail.registered_on_player_receives) do
|
||||||
|
if on_player_receive(pname, msg) then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
if has_canonical_name then
|
||||||
|
mail.register_recipient_handler(function(_, name)
|
||||||
|
local realname = canonical_name.get(name)
|
||||||
|
if realname then
|
||||||
|
return true, realname
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
BIN
screenshot_1.2.0.png
Normal file
BIN
screenshot_1.2.0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 219 KiB |
BIN
screenshot_1.4.0_1.png
Normal file
BIN
screenshot_1.4.0_1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 722 KiB |
BIN
screenshot_1.4.0_2.png
Normal file
BIN
screenshot_1.4.0_2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 802 KiB |
BIN
sounds/mail_notif.ogg
Normal file
BIN
sounds/mail_notif.ogg
Normal file
Binary file not shown.
343
storage.lua
343
storage.lua
|
@ -8,26 +8,71 @@ local function populate_entry(e)
|
||||||
e.inbox = e.inbox or {}
|
e.inbox = e.inbox or {}
|
||||||
e.outbox = e.outbox or {}
|
e.outbox = e.outbox or {}
|
||||||
e.drafts = e.drafts or {}
|
e.drafts = e.drafts or {}
|
||||||
|
e.trash = e.trash or {}
|
||||||
e.lists = e.lists or {}
|
e.lists = e.lists or {}
|
||||||
|
e.settings = e.settings or {}
|
||||||
return e
|
return e
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local cache = {}
|
||||||
|
|
||||||
|
-- retrieve the storage entry for the player
|
||||||
function mail.get_storage_entry(playername)
|
function mail.get_storage_entry(playername)
|
||||||
local str = mail.storage:get_string(STORAGE_PREFIX .. playername)
|
local key = STORAGE_PREFIX .. playername
|
||||||
|
if cache[key] then
|
||||||
|
-- use cached entry
|
||||||
|
return cache[key]
|
||||||
|
end
|
||||||
|
|
||||||
|
local str = mail.storage:get_string(key)
|
||||||
|
local entry
|
||||||
if str == "" then
|
if str == "" then
|
||||||
-- new entry
|
-- new entry
|
||||||
return populate_entry()
|
entry = populate_entry()
|
||||||
else
|
else
|
||||||
-- deserialize existing entry
|
-- deserialize existing entry
|
||||||
local e = minetest.parse_json(str)
|
local e = core.parse_json(str)
|
||||||
return populate_entry(e)
|
entry = populate_entry(e)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- cache for next time
|
||||||
|
cache[key] = entry
|
||||||
|
return entry
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- entries queued for saving
|
||||||
|
local save_queued_entries = {}
|
||||||
|
|
||||||
|
-- save the storage entry for the player
|
||||||
function mail.set_storage_entry(playername, entry)
|
function mail.set_storage_entry(playername, entry)
|
||||||
mail.storage:set_string(STORAGE_PREFIX .. playername, minetest.write_json(entry))
|
local key = STORAGE_PREFIX .. playername
|
||||||
|
-- cache
|
||||||
|
cache[key] = entry
|
||||||
|
-- enqueue for writing
|
||||||
|
save_queued_entries[key] = entry
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function save_worker()
|
||||||
|
for key, entry in pairs(save_queued_entries) do
|
||||||
|
-- write to backend
|
||||||
|
mail.storage:set_string(key, core.write_json(entry))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- clear queue
|
||||||
|
save_queued_entries = {}
|
||||||
|
|
||||||
|
-- clear cached entries
|
||||||
|
cache = {}
|
||||||
|
|
||||||
|
-- save every second
|
||||||
|
core.after(1, save_worker)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- start save-worker loop
|
||||||
|
save_worker()
|
||||||
|
-- save on shutdown
|
||||||
|
core.register_on_shutdown(save_worker)
|
||||||
|
|
||||||
-- get a mail by id from the players in- or outbox
|
-- get a mail by id from the players in- or outbox
|
||||||
function mail.get_message(playername, msg_id)
|
function mail.get_message(playername, msg_id)
|
||||||
local entry = mail.get_storage_entry(playername)
|
local entry = mail.get_storage_entry(playername)
|
||||||
|
@ -41,6 +86,43 @@ function mail.get_message(playername, msg_id)
|
||||||
return msg
|
return msg
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
for _, msg in ipairs(entry.drafts) do
|
||||||
|
if msg.id == msg_id then
|
||||||
|
return msg
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for _, msg in ipairs(entry.trash) do
|
||||||
|
if msg.id == msg_id then
|
||||||
|
return msg
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- get player boxes where a message appears
|
||||||
|
function mail.get_message_boxes(playername, msg_id)
|
||||||
|
local entry = mail.get_storage_entry(playername)
|
||||||
|
local boxes = {}
|
||||||
|
for _, msg in ipairs(entry.inbox) do
|
||||||
|
if msg.id == msg_id then
|
||||||
|
table.insert(boxes, "inbox")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for _, msg in ipairs(entry.outbox) do
|
||||||
|
if msg.id == msg_id then
|
||||||
|
table.insert(boxes, "outbox")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for _, msg in ipairs(entry.drafts) do
|
||||||
|
if msg.id == msg_id then
|
||||||
|
table.insert(boxes, "drafts")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for _, msg in ipairs(entry.trash) do
|
||||||
|
if msg.id == msg_id then
|
||||||
|
table.insert(boxes, "trash")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return boxes
|
||||||
end
|
end
|
||||||
|
|
||||||
local function safe_find(str, sub)
|
local function safe_find(str, sub)
|
||||||
|
@ -72,16 +154,86 @@ function mail.sort_messages(messages, sortfield, descending, filter)
|
||||||
return results
|
return results
|
||||||
end
|
end
|
||||||
|
|
||||||
-- marks a mail read by its id
|
local function mark_property(playername, property, msg_ids, value, hud_update)
|
||||||
function mail.mark_read(playername, msg_ids)
|
|
||||||
local entry = mail.get_storage_entry(playername)
|
local entry = mail.get_storage_entry(playername)
|
||||||
if type(msg_ids) ~= "table" then -- if this is not a table
|
if type(msg_ids) ~= "table" then -- if this is not a table
|
||||||
msg_ids = { msg_ids }
|
msg_ids = { msg_ids }
|
||||||
end
|
end
|
||||||
for _, read_msg_id in ipairs(msg_ids) do
|
for _, property_msg_id in ipairs(msg_ids) do
|
||||||
for _, entry_msg in ipairs(entry.inbox) do
|
for _, entry_msg in ipairs(entry.inbox) do
|
||||||
if entry_msg.id == read_msg_id then
|
if entry_msg.id == property_msg_id then
|
||||||
entry_msg.read = true
|
entry_msg[property] = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
mail.set_storage_entry(playername, entry)
|
||||||
|
if hud_update then
|
||||||
|
mail.hud_update(playername, entry.inbox)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- marks a mail read by its id
|
||||||
|
function mail.mark_read(playername, msg_ids)
|
||||||
|
mark_property(playername, "read", msg_ids, true, true)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- marks a mail unread by its id
|
||||||
|
function mail.mark_unread(playername, msg_ids)
|
||||||
|
mark_property(playername, "read", msg_ids, false, true)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- marks a mail as a spam
|
||||||
|
function mail.mark_spam(playername, msg_ids)
|
||||||
|
mark_property(playername, "spam", msg_ids, true)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- marks a mail as a non-spam
|
||||||
|
function mail.unmark_spam(playername, msg_ids)
|
||||||
|
mark_property(playername, "spam", msg_ids, false)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- deletes a mail by its id
|
||||||
|
function mail.delete_mail(playername, msg_ids, delete_in_trash)
|
||||||
|
local entry = mail.get_storage_entry(playername)
|
||||||
|
if type(msg_ids) ~= "table" then -- if this is not a table
|
||||||
|
msg_ids = { msg_ids }
|
||||||
|
end
|
||||||
|
for i = #entry.inbox, 1, -1 do
|
||||||
|
for _, deleted_msg in ipairs(msg_ids) do
|
||||||
|
if entry.inbox[i].id == deleted_msg then
|
||||||
|
table.remove(entry.inbox, i)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for i = #entry.outbox, 1, -1 do
|
||||||
|
for _, deleted_msg in ipairs(msg_ids) do
|
||||||
|
if entry.outbox[i].id == deleted_msg then
|
||||||
|
table.remove(entry.outbox, i)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for i = #entry.drafts, 1, -1 do
|
||||||
|
for _, deleted_msg in ipairs(msg_ids) do
|
||||||
|
if entry.drafts[i].id == deleted_msg then
|
||||||
|
table.remove(entry.drafts, i)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if delete_in_trash then
|
||||||
|
for i = #entry.trash, 1, -1 do
|
||||||
|
for _, deleted_msg in ipairs(msg_ids) do
|
||||||
|
if entry.trash[i].id == deleted_msg then
|
||||||
|
table.remove(entry.trash, i)
|
||||||
|
break
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -90,50 +242,46 @@ function mail.mark_read(playername, msg_ids)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- marks a mail unread by its id
|
-- move to trash mails by id
|
||||||
function mail.mark_unread(playername, msg_ids)
|
function mail.trash_mail(playername, msg_ids)
|
||||||
local entry = mail.get_storage_entry(playername)
|
local entry = mail.get_storage_entry(playername)
|
||||||
if type(msg_ids) ~= "table" then -- if this is not a table
|
if type(msg_ids) ~= "table" then -- if this is not a table
|
||||||
msg_ids = { msg_ids }
|
msg_ids = { msg_ids }
|
||||||
end
|
end
|
||||||
for _, unread_msg_id in ipairs(msg_ids) do
|
for _, id in ipairs(msg_ids) do
|
||||||
for _, entry_msg in ipairs(entry.inbox) do
|
local msg = mail.get_message(playername, id)
|
||||||
if entry_msg.id == unread_msg_id then
|
msg.previous_boxes = mail.get_message_boxes(playername, id)
|
||||||
entry_msg.read = false
|
table.insert(entry.trash, 1, msg)
|
||||||
|
end
|
||||||
|
mail.set_storage_entry(playername, entry)
|
||||||
|
mail.delete_mail(playername, msg_ids)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- restore a mail from trash
|
||||||
|
function mail.restore_mail(playername, msg_id)
|
||||||
|
local entry = mail.get_storage_entry(playername)
|
||||||
|
for i, msg in ipairs(entry.trash) do
|
||||||
|
if msg.id == msg_id then
|
||||||
|
-- not anymore store previous boxes in json
|
||||||
|
local previous_boxes = msg.previous_boxes
|
||||||
|
msg.previous_boxes = nil
|
||||||
|
-- restore it in all previous boxes
|
||||||
|
for _, box in ipairs(previous_boxes) do
|
||||||
|
table.insert(entry[box], msg)
|
||||||
end
|
end
|
||||||
|
-- then delete it from trash
|
||||||
|
table.remove(entry.trash, i)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
mail.set_storage_entry(playername, entry)
|
mail.set_storage_entry(playername, entry)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- deletes a mail by its id
|
-- clear the trash
|
||||||
function mail.delete_mail(playername, msg_ids)
|
function mail.empty_trash(playername)
|
||||||
local entry = mail.get_storage_entry(playername)
|
local entry = mail.get_storage_entry(playername)
|
||||||
if type(msg_ids) ~= "table" then -- if this is not a table
|
entry.trash = {}
|
||||||
msg_ids = { msg_ids }
|
|
||||||
end
|
|
||||||
for i, msg in ipairs(entry.inbox) do
|
|
||||||
for _, deleted_msg in ipairs(msg_ids) do
|
|
||||||
if msg.id == deleted_msg then
|
|
||||||
table.remove(entry.inbox, i)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for i, msg in ipairs(entry.outbox) do
|
|
||||||
for _, deleted_msg in ipairs(msg_ids) do
|
|
||||||
if msg.id == deleted_msg then
|
|
||||||
table.remove(entry.outbox, i)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for i, msg in ipairs(entry.drafts) do
|
|
||||||
for _, deleted_msg in ipairs(msg_ids) do
|
|
||||||
if msg.id == deleted_msg then
|
|
||||||
table.remove(entry.drafts, i)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
mail.set_storage_entry(playername, entry)
|
mail.set_storage_entry(playername, entry)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -176,6 +324,17 @@ function mail.get_contacts(playername)
|
||||||
return entry.contacts
|
return entry.contacts
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- get a contact
|
||||||
|
function mail.get_contact(playername, contactname)
|
||||||
|
local entry = mail.get_storage_entry(playername)
|
||||||
|
for _, existing_contact in ipairs(entry.contacts) do
|
||||||
|
if existing_contact.name == contactname then
|
||||||
|
return existing_contact
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
-- returns the maillists of a player
|
-- returns the maillists of a player
|
||||||
function mail.get_maillists(playername)
|
function mail.get_maillists(playername)
|
||||||
local entry = mail.get_storage_entry(playername)
|
local entry = mail.get_storage_entry(playername)
|
||||||
|
@ -187,6 +346,9 @@ function mail.get_maillist_by_name(playername, listname)
|
||||||
local entry = mail.get_storage_entry(playername)
|
local entry = mail.get_storage_entry(playername)
|
||||||
for _, list in ipairs(entry.lists) do
|
for _, list in ipairs(entry.lists) do
|
||||||
if list.name == listname then
|
if list.name == listname then
|
||||||
|
if not list.players then
|
||||||
|
list.players = {}
|
||||||
|
end
|
||||||
return list
|
return list
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -203,6 +365,9 @@ function mail.update_maillist(playername, list, old_list_name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- insert
|
-- insert
|
||||||
|
if not list.players then
|
||||||
|
list.players = {}
|
||||||
|
end
|
||||||
table.insert(entry.lists, list)
|
table.insert(entry.lists, list)
|
||||||
mail.set_storage_entry(playername, entry)
|
mail.set_storage_entry(playername, entry)
|
||||||
end
|
end
|
||||||
|
@ -219,33 +384,81 @@ function mail.delete_maillist(playername, listname)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function mail.extractMaillists(receivers_string, maillists_owner)
|
local function extract_maillists_main(receivers, maillists_owner, expanded_receivers, seen)
|
||||||
local receivers = mail.parse_player_list(receivers_string) -- extracted receivers
|
if type(receivers) == "string" then
|
||||||
|
receivers = mail.parse_player_list(receivers)
|
||||||
-- extract players from mailing lists
|
|
||||||
while string.find(receivers_string, "@") do
|
|
||||||
local globalReceivers = mail.parse_player_list(receivers_string) -- receivers including maillists
|
|
||||||
receivers = {}
|
|
||||||
for _, receiver in ipairs(globalReceivers) do
|
|
||||||
local receiverInfo = receiver:split("@") -- @maillist
|
|
||||||
if receiverInfo[1] and receiver == "@" .. receiverInfo[1] then
|
|
||||||
local maillist = mail.get_maillist_by_name(maillists_owner, receiverInfo[1])
|
|
||||||
if maillist then
|
|
||||||
for _, playername in ipairs(maillist.players) do
|
|
||||||
table.insert(receivers, playername)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else -- in case of player
|
|
||||||
table.insert(receivers, receiver)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
receivers_string = mail.concat_player_list(receivers)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return receivers
|
for _, receiver in pairs(receivers) do
|
||||||
|
if seen[receiver] then
|
||||||
|
-- Do not add/expand this receiver as it is already seen
|
||||||
|
core.log("verbose", ("mail: ignoring duplicate receiver %q during maillist expansion"):format(receiver))
|
||||||
|
elseif string.find(receiver, "^@") then
|
||||||
|
seen[receiver] = true
|
||||||
|
local listname = string.sub(receiver, 2)
|
||||||
|
local maillist = mail.get_maillist_by_name(maillists_owner, listname)
|
||||||
|
if maillist then
|
||||||
|
core.log("verbose", ("mail: expanding maillist %q"):format(listname))
|
||||||
|
for _, entry in ipairs(maillist.players) do
|
||||||
|
extract_maillists_main(entry, maillists_owner, expanded_receivers, seen)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
seen[receiver] = true
|
||||||
|
core.log("verbose", ("mail: adding %q to receiver list during maillist expansion"):format(receiver))
|
||||||
|
table.insert(expanded_receivers, receiver)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function mail.pairsByKeys(t, f)
|
function mail.extract_maillists(receivers, maillists_owner)
|
||||||
|
local expanded_receivers = {}
|
||||||
|
extract_maillists_main(receivers, maillists_owner, expanded_receivers, {})
|
||||||
|
return expanded_receivers
|
||||||
|
end
|
||||||
|
|
||||||
|
function mail.get_setting_default_value(key)
|
||||||
|
return mail.settings[key].default
|
||||||
|
end
|
||||||
|
|
||||||
|
function mail.get_setting(playername, key)
|
||||||
|
local entry = mail.get_storage_entry(playername)
|
||||||
|
local value = (entry.settings[key] == nil
|
||||||
|
and {mail.get_setting_default_value(key)}
|
||||||
|
or {entry.settings[key]})[1]
|
||||||
|
|
||||||
|
if mail.settings[key].sync then -- in case this setting is shared with another mod
|
||||||
|
local sync_value = mail.settings[key].sync(playername) -- get new value
|
||||||
|
if sync_value then
|
||||||
|
value = sync_value
|
||||||
|
mail.set_setting(playername, key, value, true) -- update the setting in mail storage and don't transfer it again
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
|
||||||
|
-- add or update a setting
|
||||||
|
function mail.set_setting(playername, key, value, not_transfer)
|
||||||
|
local entry = mail.get_storage_entry(playername)
|
||||||
|
local valid_value = value
|
||||||
|
if mail.settings[key].check then
|
||||||
|
valid_value = mail.settings[key].check(playername, value)
|
||||||
|
end
|
||||||
|
entry.settings[key] = valid_value
|
||||||
|
mail.set_storage_entry(playername, entry)
|
||||||
|
if not not_transfer and mail.settings[key].transfer then -- in case this setting is shared with another mod
|
||||||
|
mail.settings[key].transfer(playername, valid_value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mail.reset_settings(playername)
|
||||||
|
local entry = mail.get_storage_entry(playername)
|
||||||
|
entry.settings = {}
|
||||||
|
mail.set_storage_entry(playername, entry)
|
||||||
|
end
|
||||||
|
|
||||||
|
function mail.pairs_by_keys(t, f)
|
||||||
-- http://www.lua.org/pil/19.3.html
|
-- http://www.lua.org/pil/19.3.html
|
||||||
local a = {}
|
local a = {}
|
||||||
for n in pairs(t) do table.insert(a, n) end
|
for n in pairs(t) do table.insert(a, n) end
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
ARG ENGINE_VERSION=5.5.0
|
ARG ENGINE_VERSION=5.7.0
|
||||||
FROM registry.gitlab.com/minetest/minetest/server:${ENGINE_VERSION}
|
FROM registry.gitlab.com/minetest/minetest/server:${ENGINE_VERSION}
|
||||||
|
|
||||||
# copy old v1 maildb for migration testing
|
# copy old v1 maildb for migration testing
|
||||||
|
@ -7,11 +7,9 @@ COPY ./mail.db /root/.minetest/worlds/world/mail.db
|
||||||
COPY ./old_v2_player.json /root/.minetest/worlds/world/mails/
|
COPY ./old_v2_player.json /root/.minetest/worlds/world/mails/
|
||||||
COPY ./auth.sqlite /root/.minetest/worlds/world/auth.sqlite
|
COPY ./auth.sqlite /root/.minetest/worlds/world/auth.sqlite
|
||||||
|
|
||||||
|
|
||||||
USER root
|
USER root
|
||||||
RUN apk add git &&\
|
RUN apk add git &&\
|
||||||
mkdir -p /root/.minetest/worlds/world/worldmods/ &&\
|
mkdir -p /root/.minetest/worlds/world/worldmods/ &&\
|
||||||
git clone https://github.com/BuckarooBanzay/mtt /root/.minetest/worlds/world/worldmods/mtt
|
git clone https://github.com/BuckarooBanzay/mtt /root/.minetest/worlds/world/worldmods/mtt
|
||||||
|
|
||||||
|
|
||||||
ENTRYPOINT minetestserver --config /minetest.conf
|
ENTRYPOINT minetestserver --config /minetest.conf
|
BIN
textures/search.png
Normal file
BIN
textures/search.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
159
ui/about.lua
159
ui/about.lua
|
@ -1,43 +1,152 @@
|
||||||
|
-- translation
|
||||||
|
local S = mail.S
|
||||||
|
|
||||||
local FORMNAME = "mail:about"
|
local FORMNAME = "mail:about"
|
||||||
|
|
||||||
|
local groups = {
|
||||||
|
{ "o", S("Original author")},
|
||||||
|
{ "c", S("Code")},
|
||||||
|
{ "i", S("Internationalization")},
|
||||||
|
{ "t", S("Textures")},
|
||||||
|
{ "a", S("Audio")},
|
||||||
|
}
|
||||||
|
|
||||||
|
local contributors = {
|
||||||
|
{ name = "Cheapie", groups = {"o", "c"} },
|
||||||
|
{ name = "aBlueShadow", groups = {"c"} },
|
||||||
|
{ name = "APercy", groups = {"i"} },
|
||||||
|
{ name = "Athozus", groups = {"c", "i"} },
|
||||||
|
{ name = "BuckarooBanzay", groups = {"c"} },
|
||||||
|
{ name = "Chache", groups = {"i"} },
|
||||||
|
{ name = "Dennis Jenkins", groups = {"c"} },
|
||||||
|
{ name = "Emojigit", groups = {"c", "i"} },
|
||||||
|
{ name = "Eredin", groups = {"i"} },
|
||||||
|
{ name = "fluxionary", groups = {"c"} },
|
||||||
|
{ name = "imre84", groups = {"c"} },
|
||||||
|
{ name = "Muhammad Rifqi Priyo Susanto", groups = {"i"} },
|
||||||
|
{ name = "NatureFreshMilk", groups = {"c", "t"} },
|
||||||
|
{ name = "Niklp", groups = {"c", "i"} },
|
||||||
|
{ name = "Nuno Filipe Povoa", groups = {"a"} },
|
||||||
|
{ name = "nyomi", groups = {"i"} },
|
||||||
|
{ name = "OgelGames", groups = {"c"} },
|
||||||
|
{ name = "Panquesito7", groups = {"c"} },
|
||||||
|
{ name = "Peter Nerlich", groups = {"c"} },
|
||||||
|
{ name = "Rubenwardy", groups = {"c"} },
|
||||||
|
{ name = "savilli", groups = {"c"} },
|
||||||
|
{ name = "Singularis", groups = {"c"} },
|
||||||
|
{ name = "SX", groups = {"c"} },
|
||||||
|
{ name = "TheTrueBeginner", groups = {"i"} },
|
||||||
|
{ name = "Thomas Rudin", groups = {"c"} },
|
||||||
|
{ name = "Toby1710", groups = {"c"} },
|
||||||
|
{ name = "whosit", groups = {"c"} },
|
||||||
|
{ name = "Wuzzy", groups = {"i"} },
|
||||||
|
{ name = "y5nw", groups = {"c", "i"} },
|
||||||
|
}
|
||||||
|
|
||||||
function mail.show_about(name)
|
function mail.show_about(name)
|
||||||
|
mail.selected_idxs.contributor_grouping[name] = tonumber(mail.selected_idxs.contributor_grouping[name]) or 1
|
||||||
|
|
||||||
local formspec = [[
|
local formspec = [[
|
||||||
size[10,6;]
|
size[10,6;]
|
||||||
|
tabheader[0,0;optionstab;]] .. S("Settings") .. "," .. S("About") .. [[;2;false;false]
|
||||||
button[9.35,0;0.75,0.5;back;X]
|
button[9.35,0;0.75,0.5;back;X]
|
||||||
label[0,0;Mail]
|
|
||||||
label[0,0.4;Provided my mt-mods]
|
|
||||||
label[0,0.8;Version: 1.1.1]
|
|
||||||
label[0,1.4;Licenses:]
|
|
||||||
label[0.2,1.8;Expat (code), WTFPL (textures)]
|
|
||||||
label[0,2.4;https://github.com/mt-mods/mail]
|
|
||||||
label[0,2.8;https://content.minetest.net/packages/mt-mods/mail]
|
|
||||||
textarea[0.5,4.0;4,5.5;;Note;]] ..
|
|
||||||
[[NOTE: Communication using this system is NOT guaranteed to be private!]] ..
|
|
||||||
[[ Admins are able to view the messages of any player.]
|
|
||||||
|
|
||||||
tablecolumns[color;text;text]
|
box[0,0;3,0.45;]] .. mail.get_color("highlighted") .. [[]
|
||||||
table[5,0.75;4.9,5.5;contributors;]] ..
|
label[0.2,0;Mail]
|
||||||
[[#999,Contributors,,]] ..
|
|
||||||
[[#FFD700,Cheapie,Initial idea/project,]] ..
|
|
||||||
[[#FFF,Rubenwardy,Lua/UI improvements,]] ..
|
|
||||||
[[#FFF,BuckarooBanzay,Clean-ups\, Refactoring,]] ..
|
|
||||||
[[#FFF,Athozus,Outbox\, Maillists\, UI\, Drafts,]] ..
|
|
||||||
[[#FFF,fluxionary,Minor fixups,]] ..
|
|
||||||
[[#FFF,SX,Various fixes\, UI,]] ..
|
|
||||||
[[#FFF,Toby1710,Ux fixes,]] ..
|
|
||||||
[[#FFF,Peter Nerlich,CC\, BCC]
|
|
||||||
]] .. mail.theme
|
|
||||||
|
|
||||||
minetest.show_formspec(name, FORMNAME, formspec)
|
label[0.2,0.5;]] .. S("Provided by mt-mods") .. [[]
|
||||||
|
label[0.2,0.9;]] .. S("Version: @1", "1.5.0-dev") .. [[]
|
||||||
|
|
||||||
|
box[0,1.5;3,0.45;]] .. mail.get_color("highlighted") .. [[]
|
||||||
|
label[0.2,1.5;]] .. S("Licenses") .. [[]
|
||||||
|
label[0.2,2.0;]] .. S("Expat (code), WTFPL (textures)") .. [[]
|
||||||
|
|
||||||
|
box[0,2.6;3,0.45;]] .. mail.get_color("highlighted") .. [[]
|
||||||
|
label[0.2,2.6;]] .. S("Note") .. [[]
|
||||||
|
textarea[0.5,3.15;4,5.5;;;]] ..
|
||||||
|
S("Communication using this system is NOT guaranteed to be private!") .. " " ..
|
||||||
|
S("Admins are able to view the messages of any player.") .. [[]
|
||||||
|
|
||||||
|
button[0,5.7;2,0.5;github;GitHub]
|
||||||
|
button[2,5.7;2,0.5;contentdb;ContentDB]
|
||||||
|
|
||||||
|
box[4,0;3,0.45;]] .. mail.get_color("highlighted") .. [[]
|
||||||
|
label[4.2,0;]] .. S("Contributors") .. [[]
|
||||||
|
|
||||||
|
dropdown[4,0.75;6.4;contributor_grouping;]]
|
||||||
|
.. S("Group by name") .. ","
|
||||||
|
.. S("Group by contribution") .. ";" .. mail.selected_idxs.contributor_grouping[name] .. [[;true]
|
||||||
|
]]
|
||||||
|
|
||||||
|
local contributor_list, contributor_columns = {}
|
||||||
|
|
||||||
|
if mail.selected_idxs.contributor_grouping[name] == 2 then
|
||||||
|
contributor_columns = "color;text"
|
||||||
|
local sorted = {}
|
||||||
|
for _, g in ipairs(groups) do
|
||||||
|
sorted[g[1]] = {}
|
||||||
|
end
|
||||||
|
for _, c in ipairs(contributors) do
|
||||||
|
for _, g in ipairs(c.groups) do
|
||||||
|
table.insert(sorted[g] or {}, c.name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for _, g in ipairs(groups) do
|
||||||
|
table.insert(contributor_list, mail.get_color("header") .. "," .. g[2])
|
||||||
|
for _, c in ipairs(sorted[g[1]]) do
|
||||||
|
table.insert(contributor_list, "," .. c)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
contributor_columns = "text;text"
|
||||||
|
for _, c in ipairs(contributors) do
|
||||||
|
for _, g in ipairs(groups) do
|
||||||
|
local index = table.indexof(c.groups, g[1])
|
||||||
|
if index >= 1 then
|
||||||
|
if index == 1 then
|
||||||
|
table.insert(contributor_list, c.name)
|
||||||
|
else
|
||||||
|
table.insert(contributor_list, "")
|
||||||
|
end
|
||||||
|
table.insert(contributor_list, g[2])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
formspec = formspec .. ("tablecolumns[%s]"):format(contributor_columns) ..
|
||||||
|
("table[4,1.6;5.9,4.65;contributors;%s]"):format(table.concat(contributor_list, ","))
|
||||||
|
|
||||||
|
formspec = formspec .. mail.theme
|
||||||
|
|
||||||
|
core.show_formspec(name, FORMNAME, formspec)
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
core.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
if formname ~= FORMNAME then
|
if formname ~= FORMNAME then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local playername = player:get_player_name()
|
||||||
|
|
||||||
if fields.back then
|
if fields.back then
|
||||||
local playername = player:get_player_name()
|
|
||||||
mail.show_mail_menu(playername)
|
mail.show_mail_menu(playername)
|
||||||
|
|
||||||
|
elseif fields.optionstab == "1" then
|
||||||
|
mail.selected_idxs.optionstab[playername] = 1
|
||||||
|
mail.show_settings(playername)
|
||||||
|
|
||||||
|
elseif fields.optionstab == "2" then
|
||||||
|
mail.selected_idxs.optionstab[playername] = 2
|
||||||
|
mail.show_about(playername)
|
||||||
|
|
||||||
|
elseif fields.github then
|
||||||
|
core.chat_send_player(playername, "https://github.com/mt-mods/mail")
|
||||||
|
|
||||||
|
elseif fields.contentdb then
|
||||||
|
core.chat_send_player(playername, "https://content.minetest.net/packages/mt-mods/mail")
|
||||||
|
elseif fields.contributor_grouping then
|
||||||
|
mail.selected_idxs.contributor_grouping[playername] = fields.contributor_grouping
|
||||||
|
mail.show_about(playername)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
-- translation
|
-- translation
|
||||||
local S = minetest.get_translator("mail")
|
local S = mail.S
|
||||||
|
|
||||||
local FORMNAME = "mail:compose"
|
local FORMNAME = "mail:compose"
|
||||||
local msg_id = {}
|
|
||||||
|
|
||||||
function mail.show_compose(name, to, subject, body, cc, bcc, id)
|
function mail.show_compose(name, to, subject, body, cc, bcc, id)
|
||||||
local formspec = [[
|
local formspec = [[
|
||||||
|
@ -21,30 +20,25 @@ function mail.show_compose(name, to, subject, body, cc, bcc, id)
|
||||||
]] .. mail.theme
|
]] .. mail.theme
|
||||||
|
|
||||||
formspec = string.format(formspec,
|
formspec = string.format(formspec,
|
||||||
minetest.formspec_escape(to) or "",
|
core.formspec_escape(to) or "",
|
||||||
minetest.formspec_escape(cc) or "",
|
core.formspec_escape(cc) or "",
|
||||||
minetest.formspec_escape(bcc) or "",
|
core.formspec_escape(bcc) or "",
|
||||||
minetest.formspec_escape(subject) or "",
|
core.formspec_escape(subject) or "",
|
||||||
minetest.formspec_escape(body) or "")
|
core.formspec_escape(body) or "")
|
||||||
|
|
||||||
if id then
|
mail.selected_idxs.message[name] = id or mail.new_uuid()
|
||||||
msg_id[name] = id
|
|
||||||
end
|
|
||||||
|
|
||||||
minetest.show_formspec(name, FORMNAME, formspec)
|
core.show_formspec(name, FORMNAME, formspec)
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
core.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
if formname ~= FORMNAME then
|
if formname ~= FORMNAME then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
if fields.send then
|
if fields.send then
|
||||||
local id = mail.new_uuid()
|
local id = mail.selected_idxs.message[name] or mail.new_uuid()
|
||||||
if msg_id[name] then
|
|
||||||
id = msg_id[name]
|
|
||||||
end
|
|
||||||
if (fields.to == "" and fields.cc == "" and fields.bcc == "") or fields.body == "" then
|
if (fields.to == "" and fields.cc == "" and fields.bcc == "") or fields.body == "" then
|
||||||
-- if mail is invalid then store it as a draft
|
-- if mail is invalid then store it as a draft
|
||||||
mail.save_draft({
|
mail.save_draft({
|
||||||
|
@ -69,7 +63,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
body = fields.body,
|
body = fields.body,
|
||||||
})
|
})
|
||||||
if not success then
|
if not success then
|
||||||
minetest.chat_send_player(name, err)
|
core.chat_send_player(name, err)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -93,7 +87,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.after(0.5, function()
|
core.after(0.5, function()
|
||||||
mail.selected_idxs.drafts[name] = nil
|
mail.selected_idxs.drafts[name] = nil
|
||||||
mail.show_mail_menu(name)
|
mail.show_mail_menu(name)
|
||||||
end)
|
end)
|
||||||
|
@ -115,8 +109,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
|
|
||||||
elseif fields.draft then
|
elseif fields.draft then
|
||||||
local id = mail.new_uuid()
|
local id = mail.new_uuid()
|
||||||
if msg_id[name] then
|
if mail.selected_idxs.message[name] then
|
||||||
id = msg_id[name]
|
id = mail.selected_idxs.message[name]
|
||||||
end
|
end
|
||||||
mail.save_draft({
|
mail.save_draft({
|
||||||
id = id,
|
id = id,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
-- translation
|
-- translation
|
||||||
local S = minetest.get_translator("mail")
|
local S = mail.S
|
||||||
|
|
||||||
local FORMNAME = "mail:contacts"
|
local FORMNAME = "mail:contacts"
|
||||||
|
|
||||||
|
@ -9,15 +9,15 @@ local contacts_formspec = "size[8,9;]" .. mail.theme .. [[
|
||||||
button[6,1.60;2,0.5;delete;]] .. S("Delete") .. [[]
|
button[6,1.60;2,0.5;delete;]] .. S("Delete") .. [[]
|
||||||
button[6,8.25;2,0.5;back;]] .. S("Back") .. [[]
|
button[6,8.25;2,0.5;back;]] .. S("Back") .. [[]
|
||||||
tablecolumns[color;text;text]
|
tablecolumns[color;text;text]
|
||||||
table[0,0;5.75,9;contacts;#999,]] .. S("Name") .. "," .. S("Note")
|
table[0,0;5.75,9;contacts;]] .. mail.get_color("header") .. "," .. S("Name") .. "," .. S("Note")
|
||||||
|
|
||||||
|
|
||||||
function mail.show_contacts(name)
|
function mail.show_contacts(name)
|
||||||
local formspec = contacts_formspec .. mail.compile_contact_list(name, mail.selected_idxs.contacts[name])
|
local formspec = contacts_formspec .. mail.compile_contact_list(name, mail.selected_idxs.contacts[name])
|
||||||
minetest.show_formspec(name, FORMNAME, formspec)
|
core.show_formspec(name, FORMNAME, formspec)
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
core.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
if formname ~= FORMNAME then
|
if formname ~= FORMNAME then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -26,10 +26,10 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
local contacts = mail.get_contacts(name)
|
local contacts = mail.get_contacts(name)
|
||||||
|
|
||||||
if fields.contacts then
|
if fields.contacts then
|
||||||
local evt = minetest.explode_table_event(fields.contacts)
|
local evt = core.explode_table_event(fields.contacts)
|
||||||
for k, _, i in mail.pairsByKeys(contacts) do
|
for k, _, i in mail.pairs_by_keys(contacts) do
|
||||||
if i == evt.row - 1 then
|
if i == evt.row - 1 then
|
||||||
mail.selected_idxs.contacts[name] = k
|
mail.selected_idxs.contacts[name] = tonumber(k)
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -58,16 +58,16 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
-- except if it was the last. Then determine the new last
|
-- except if it was the last. Then determine the new last
|
||||||
local found = false
|
local found = false
|
||||||
local last = nil
|
local last = nil
|
||||||
for k in mail.pairsByKeys(contacts) do
|
for k in mail.pairs_by_keys(contacts) do
|
||||||
if found then
|
if found then
|
||||||
mail.selected_idxs.contacts[name] = k
|
mail.selected_idxs.contacts[name] = tonumber(k)
|
||||||
break
|
break
|
||||||
elseif k == mail.selected_idxs.contacts[name] then
|
elseif k == mail.selected_idxs.contacts[name] then
|
||||||
mail.delete_contact(name, contacts[mail.selected_idxs.contacts[name]].name)
|
mail.delete_contact(name, contacts[mail.selected_idxs.contacts[name]].name)
|
||||||
mail.selected_idxs.contacts[name] = nil
|
mail.selected_idxs.contacts[name] = nil
|
||||||
found = true
|
found = true
|
||||||
else
|
else
|
||||||
last = k
|
last = tonumber(k)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if found and not mail.selected_idxs.contacts[name] then
|
if found and not mail.selected_idxs.contacts[name] then
|
||||||
|
|
|
@ -1,22 +1,27 @@
|
||||||
-- translation
|
-- translation
|
||||||
local S = minetest.get_translator("mail")
|
local S = mail.S
|
||||||
|
|
||||||
local drafts_formspec = "size[8.5,10;]" .. mail.theme .. [[
|
|
||||||
tabheader[0.3,1;boxtab;]] .. S("Inbox") .. "," .. S("Sent messages").. "," .. S("Drafts") .. [[;3;false;false]
|
|
||||||
|
|
||||||
button[6,0.10;2.5,0.5;new;]] .. S("New") .. [[]
|
|
||||||
button[6,0.95;2.5,0.5;edit;]] .. S("Edit") .. [[]
|
|
||||||
button[6,1.70;2.5,0.5;delete;]] .. S("Delete") .. [[]
|
|
||||||
button[6,6.8;2.5,0.5;contacts;]] .. S("Contacts") .. [[]
|
|
||||||
button[6,7.6;2.5,0.5;maillists;]] .. S("Mail lists") .. [[]
|
|
||||||
button[6,8.7;2.5,0.5;about;]] .. S("About") .. [[]
|
|
||||||
button_exit[6,9.5;2.5,0.5;quit;]] .. S("Close") .. [[]
|
|
||||||
|
|
||||||
tablecolumns[color;text;text]
|
|
||||||
table[0,0.7;5.75,9.35;drafts;#999,]] .. S("To") .. "," .. S("Subject")
|
|
||||||
|
|
||||||
|
|
||||||
function mail.show_drafts(name)
|
function mail.show_drafts(name)
|
||||||
|
local trash_tab = ""
|
||||||
|
if mail.get_setting(name, "trash_move_enable") then
|
||||||
|
trash_tab = "," .. S("Trash")
|
||||||
|
end
|
||||||
|
|
||||||
|
local drafts_formspec = "size[8.5,11;]" .. mail.theme .. [[
|
||||||
|
tabheader[0.3,1;boxtab;]] ..
|
||||||
|
S("Inbox") .. "," .. S("Outbox").. "," .. S("Drafts") .. trash_tab .. [[;3;false;false]
|
||||||
|
|
||||||
|
button[6,0.10;2.5,0.5;new;]] .. S("New") .. [[]
|
||||||
|
button[6,0.95;2.5,0.5;edit;]] .. S("Edit") .. [[]
|
||||||
|
button[6,1.70;2.5,0.5;delete;]] .. S("Delete") .. [[]
|
||||||
|
button[6,8.0;2.5,0.5;contacts;]] .. S("Contacts") .. [[]
|
||||||
|
button[6,8.8;2.5,0.5;maillists;]] .. S("Mail lists") .. [[]
|
||||||
|
button[6,9.7;2.5,0.5;options;]] .. S("Options") .. [[]
|
||||||
|
button_exit[6,10.5;2.5,0.5;quit;]] .. S("Close") .. [[]
|
||||||
|
|
||||||
|
tablecolumns[color;text;text]
|
||||||
|
table[0,0.7;5.75,10.35;drafts;]] .. mail.get_color("header") .. "," .. S("To") .. "," .. S("Subject")
|
||||||
|
|
||||||
local formspec = { drafts_formspec }
|
local formspec = { drafts_formspec }
|
||||||
local entry = mail.get_storage_entry(name)
|
local entry = mail.get_storage_entry(name)
|
||||||
local messages = entry.drafts
|
local messages = entry.drafts
|
||||||
|
@ -27,14 +32,14 @@ function mail.show_drafts(name)
|
||||||
for _, message in ipairs(messages) do
|
for _, message in ipairs(messages) do
|
||||||
formspec[#formspec + 1] = ","
|
formspec[#formspec + 1] = ","
|
||||||
formspec[#formspec + 1] = ","
|
formspec[#formspec + 1] = ","
|
||||||
formspec[#formspec + 1] = minetest.formspec_escape(message.to)
|
formspec[#formspec + 1] = core.formspec_escape(message.to)
|
||||||
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
|
||||||
formspec[#formspec + 1] = minetest.formspec_escape(string.sub(message.subject, 1, 27))
|
formspec[#formspec + 1] = core.formspec_escape(string.sub(message.subject, 1, 27))
|
||||||
formspec[#formspec + 1] = "..."
|
formspec[#formspec + 1] = "..."
|
||||||
else
|
else
|
||||||
formspec[#formspec + 1] = minetest.formspec_escape(message.subject)
|
formspec[#formspec + 1] = core.formspec_escape(message.subject)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
formspec[#formspec + 1] = S("(No subject)")
|
formspec[#formspec + 1] = S("(No subject)")
|
||||||
|
@ -48,5 +53,5 @@ function mail.show_drafts(name)
|
||||||
else
|
else
|
||||||
formspec[#formspec + 1] = "]label[2.25,4.5;" .. S("No drafts") .. "]"
|
formspec[#formspec + 1] = "]label[2.25,4.5;" .. S("No drafts") .. "]"
|
||||||
end
|
end
|
||||||
minetest.show_formspec(name, "mail:drafts", table.concat(formspec, ""))
|
core.show_formspec(name, "mail:drafts", table.concat(formspec, ""))
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
-- translation
|
-- translation
|
||||||
local S = minetest.get_translator("mail")
|
local S = mail.S
|
||||||
|
|
||||||
local FORMNAME = "mail:editcontact"
|
local FORMNAME = "mail:editcontact"
|
||||||
|
|
||||||
|
@ -13,25 +13,23 @@ function mail.show_edit_contact(name, contact_name, note, illegal_name_hint)
|
||||||
]]
|
]]
|
||||||
if illegal_name_hint == "collision" then
|
if illegal_name_hint == "collision" then
|
||||||
formspec = formspec .. [[
|
formspec = formspec .. [[
|
||||||
label[4,1;]] .. S("That name") .. [[]
|
textarea[4.25,1;2.5,6;;;]] ..
|
||||||
label[4,1.5;]] .. S("is already in") .. [[]
|
S("That name is already in your contacts") .. [[]
|
||||||
label[4,2;]] .. S("your contacts.") .. [[]
|
|
||||||
]]
|
]]
|
||||||
elseif illegal_name_hint == "empty" then
|
elseif illegal_name_hint == "empty" then
|
||||||
formspec = formspec .. [[
|
formspec = formspec .. [[
|
||||||
label[4,1;]] .. S("The contact") .. [[]
|
textarea[4.25,1;2.5,6;;;]] ..
|
||||||
label[4,1.5;]] .. S("name cannot") .. [[]
|
S("The contact name cannot be empty.") .. [[]
|
||||||
label[4,2;]] .. S("be empty.") .. [[]
|
|
||||||
]]
|
]]
|
||||||
end
|
end
|
||||||
formspec = formspec .. mail.theme
|
formspec = formspec .. mail.theme
|
||||||
formspec = string.format(formspec,
|
formspec = string.format(formspec,
|
||||||
minetest.formspec_escape(contact_name or ""),
|
core.formspec_escape(contact_name or ""),
|
||||||
minetest.formspec_escape(note or ""))
|
core.formspec_escape(note or ""))
|
||||||
minetest.show_formspec(name, FORMNAME, formspec)
|
core.show_formspec(name, FORMNAME, formspec)
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
core.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
if formname ~= FORMNAME then
|
if formname ~= FORMNAME then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -40,19 +38,21 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
local contacts = mail.get_contacts(name)
|
local contacts = mail.get_contacts(name)
|
||||||
|
|
||||||
if fields.save then
|
if fields.save then
|
||||||
if mail.selected_idxs.contacts[name] and mail.selected_idxs.contacts[name] ~= "#NEW#" then
|
if mail.selected_idxs.contacts[name] then
|
||||||
local contact = contacts[mail.selected_idxs.contacts[name]]
|
local contact = contacts[mail.selected_idxs.contacts[name]] or {name = ""}
|
||||||
if mail.selected_idxs.contacts[name] ~= string.lower(fields.name) then
|
if contact.name ~= fields.name or fields.name == "" then
|
||||||
-- name changed!
|
-- name changed!
|
||||||
if #fields.name == 0 then
|
if #fields.name == 0 then
|
||||||
mail.show_edit_contact(name, contact.name, fields.note, "empty")
|
mail.show_edit_contact(name, contact.name, fields.note, "empty")
|
||||||
return true
|
return true
|
||||||
|
|
||||||
elseif contacts[string.lower(fields.name)] ~= nil then
|
elseif mail.get_contact(name, fields.name) then
|
||||||
mail.show_edit_contact(name, contact.name, fields.note, "collision")
|
mail.show_edit_contact(name, contact.name, fields.note, "collision")
|
||||||
return true
|
return true
|
||||||
|
|
||||||
else
|
else
|
||||||
|
contact.name = fields.name
|
||||||
|
contact.note = fields.note
|
||||||
mail.update_contact(name, contact)
|
mail.update_contact(name, contact)
|
||||||
contacts[mail.selected_idxs.contacts[name]] = nil
|
contacts[mail.selected_idxs.contacts[name]] = nil
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
-- translation
|
-- translation
|
||||||
local S = minetest.get_translator("mail")
|
local S = mail.S
|
||||||
local old_lists_names = {}
|
|
||||||
|
|
||||||
local FORMNAME = "mail:editmaillist"
|
local FORMNAME = "mail:editmaillist"
|
||||||
|
|
||||||
function mail.show_edit_maillist(playername, maillist_name, desc, players, illegal_name_hint)
|
function mail.show_edit_maillist(playername, maillist_name, desc, players, illegal_name_hint)
|
||||||
old_lists_names[playername] = maillist_name
|
|
||||||
local formspec = [[
|
local formspec = [[
|
||||||
size[6,7]
|
size[6,7]
|
||||||
button[4,6.25;2,0.5;back;]] .. S("Back") .. [[]
|
button[4,6.25;2,0.5;back;]] .. S("Back") .. [[]
|
||||||
|
@ -16,38 +14,68 @@ function mail.show_edit_maillist(playername, maillist_name, desc, players, illeg
|
||||||
]]
|
]]
|
||||||
if illegal_name_hint == "collision" then
|
if illegal_name_hint == "collision" then
|
||||||
formspec = formspec .. [[
|
formspec = formspec .. [[
|
||||||
label[4,1;]] .. S("That name") .. [[]
|
textarea[4.25,1;2.5,6;;;]] ..
|
||||||
label[4,1.5;]] .. S("is already in") .. [[]
|
S("That name is already in your mailing lists.") .. [[]
|
||||||
label[4,2;]] .. S("your maillists.") .. [[]
|
|
||||||
]]
|
]]
|
||||||
elseif illegal_name_hint == "empty" then
|
elseif illegal_name_hint == "empty" then
|
||||||
formspec = formspec .. [[
|
formspec = formspec .. [[
|
||||||
label[4,1;]] .. S("The maillist") .. [[]
|
textarea[4.25,1;2.5,6;;;]] ..
|
||||||
label[4,1.5;]] .. S("name cannot") .. [[]
|
S("The mailing list name cannot be empty.") .. [[]
|
||||||
label[4,2;]] .. S("be empty.") .. [[]
|
|
||||||
]]
|
]]
|
||||||
end
|
end
|
||||||
formspec = formspec .. mail.theme
|
formspec = formspec .. mail.theme
|
||||||
formspec = string.format(formspec,
|
formspec = string.format(formspec,
|
||||||
minetest.formspec_escape(maillist_name or ""),
|
core.formspec_escape(maillist_name or ""),
|
||||||
minetest.formspec_escape(desc or ""),
|
core.formspec_escape(desc or ""),
|
||||||
minetest.formspec_escape(players or ""))
|
core.formspec_escape(players or ""))
|
||||||
minetest.show_formspec(playername, FORMNAME, formspec)
|
core.show_formspec(playername, FORMNAME, formspec)
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
core.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
if formname ~= FORMNAME then
|
if formname ~= FORMNAME then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
|
local maillists = mail.get_maillists(name)
|
||||||
|
|
||||||
if fields.save then
|
if fields.save then
|
||||||
mail.update_maillist(name, {
|
local old_maillist = maillists[mail.selected_idxs.maillists[name]] or {name = ""}
|
||||||
owner = name,
|
if mail.selected_idxs.maillists[name] then
|
||||||
name = fields.name,
|
if old_maillist.name ~= fields.name or fields.name == "" then
|
||||||
desc = fields.desc,
|
-- name changed!
|
||||||
players = mail.parse_player_list(fields.players)
|
if #fields.name == 0 then
|
||||||
}, old_lists_names[name])
|
mail.show_edit_maillist(name, old_maillist.name, fields.desc, fields.players, "empty")
|
||||||
|
return true
|
||||||
|
|
||||||
|
elseif mail.get_maillist_by_name(name, fields.name) then
|
||||||
|
mail.show_edit_maillist(name, old_maillist.name, fields.desc, fields.players, "collision")
|
||||||
|
return true
|
||||||
|
|
||||||
|
else
|
||||||
|
mail.update_maillist(name, {
|
||||||
|
owner = name,
|
||||||
|
name = fields.name,
|
||||||
|
desc = fields.desc,
|
||||||
|
players = mail.parse_player_list(fields.players)
|
||||||
|
}, old_maillist.name)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
mail.update_maillist(name, {
|
||||||
|
owner = name,
|
||||||
|
name = fields.name,
|
||||||
|
desc = fields.desc,
|
||||||
|
players = mail.parse_player_list(fields.players)
|
||||||
|
}, old_maillist.name)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
mail.update_maillist(name, {
|
||||||
|
owner = name,
|
||||||
|
name = fields.name,
|
||||||
|
desc = fields.desc,
|
||||||
|
players = mail.parse_player_list(fields.players)
|
||||||
|
}, old_maillist.name)
|
||||||
|
end
|
||||||
mail.show_maillists(name)
|
mail.show_maillists(name)
|
||||||
|
|
||||||
elseif fields.back then
|
elseif fields.back then
|
||||||
|
|
230
ui/events.lua
230
ui/events.lua
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
-- Getter to filter and sort messages on demand
|
-- Getter to filter and sort messages on demand
|
||||||
local function messageGetter(messages, sortfield, ascending, filter)
|
local function message_getter(messages, sortfield, ascending, filter)
|
||||||
local results
|
local results
|
||||||
return function()
|
return function()
|
||||||
if not results then
|
if not results then
|
||||||
|
@ -10,16 +10,23 @@ local function messageGetter(messages, sortfield, ascending, filter)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
local function nonempty(x)
|
||||||
if formname ~= "mail:inbox" and formname ~= "mail:sent" and formname ~= "mail:drafts" then
|
return ((type(x)=="table")and(#x>0))
|
||||||
return
|
end
|
||||||
elseif fields.quit then
|
|
||||||
|
core.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
|
if formname ~= "mail:inbox" and formname ~= "mail:outbox"
|
||||||
|
and formname ~= "mail:drafts" and formname ~= "mail:trash" then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if fields.quit then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
-- Get player name and handle / convert common input fields
|
-- Get player name and handle / convert common input fields
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
local filter = fields.filter or mail.selected_idxs.filter[name] or ""
|
local filter = (fields.search and fields.filter) or mail.selected_idxs.filter[name] or ""
|
||||||
local sortfieldindex = tonumber(fields.sortfield or mail.selected_idxs.sortfield[name]) or 3
|
local sortfieldindex = tonumber(fields.sortfield or mail.selected_idxs.sortfield[name]) or 3
|
||||||
local sortdirection = fields.sortdirection or mail.selected_idxs.sortdirection[name] or "1"
|
local sortdirection = fields.sortdirection or mail.selected_idxs.sortdirection[name] or "1"
|
||||||
local inboxsortfield = ({"from","subject","time"})[sortfieldindex]
|
local inboxsortfield = ({"from","subject","time"})[sortfieldindex]
|
||||||
|
@ -27,7 +34,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
|
|
||||||
-- Be sure that inbox/outbox selected idxs aren't nil
|
-- Be sure that inbox/outbox selected idxs aren't nil
|
||||||
mail.selected_idxs.inbox[name] = mail.selected_idxs.inbox[name] or {}
|
mail.selected_idxs.inbox[name] = mail.selected_idxs.inbox[name] or {}
|
||||||
mail.selected_idxs.sent[name] = mail.selected_idxs.sent[name] or {}
|
mail.selected_idxs.outbox[name] = mail.selected_idxs.outbox[name] or {}
|
||||||
|
|
||||||
-- Store common player configuration for reuse
|
-- Store common player configuration for reuse
|
||||||
mail.selected_idxs.sortfield[name] = sortfieldindex
|
mail.selected_idxs.sortfield[name] = sortfieldindex
|
||||||
|
@ -40,25 +47,31 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
-- Avoid several selected after disabling the multiple selection
|
-- Avoid several selected after disabling the multiple selection
|
||||||
if not mail.selected_idxs.multipleselection[name] then
|
if not mail.selected_idxs.multipleselection[name] then
|
||||||
mail.selected_idxs.inbox[name] = { mail.selected_idxs.inbox[name][#mail.selected_idxs.inbox[name]] }
|
mail.selected_idxs.inbox[name] = { mail.selected_idxs.inbox[name][#mail.selected_idxs.inbox[name]] }
|
||||||
mail.selected_idxs.sent[name] = { mail.selected_idxs.sent[name][#mail.selected_idxs.sent[name]] }
|
mail.selected_idxs.outbox[name] = { mail.selected_idxs.outbox[name][#mail.selected_idxs.outbox[name]] }
|
||||||
end
|
end
|
||||||
|
|
||||||
-- split inbox and sent msgs for different tests
|
-- split inbox and outbox msgs for different tests
|
||||||
local entry = mail.get_storage_entry(name)
|
local entry = mail.get_storage_entry(name)
|
||||||
local messagesDrafts = entry.drafts
|
local messagesDrafts = entry.drafts
|
||||||
local getInbox = messageGetter(entry.inbox, inboxsortfield, sortdirection == "2", filter)
|
local messagesTrash = entry.trash
|
||||||
local getOutbox = messageGetter(entry.outbox, outboxsortfield, sortdirection == "2", filter)
|
local getInbox = message_getter(entry.inbox, inboxsortfield, sortdirection == "2", filter)
|
||||||
|
local getOutbox = message_getter(entry.outbox, outboxsortfield, sortdirection == "2", filter)
|
||||||
|
|
||||||
-- Hanmdle formspec event
|
-- Hanmdle formspec event
|
||||||
if fields.inbox then -- inbox table
|
if fields.inbox then -- inbox table
|
||||||
local evt = minetest.explode_table_event(fields.inbox)
|
local evt = core.explode_table_event(fields.inbox)
|
||||||
if evt.row == 1 then -- header
|
if evt.row == 1 then -- header
|
||||||
if mail.selected_idxs.sortfield[name] == evt.column-1 then -- if already this field, then change direction
|
if mail.selected_idxs.sortfield[name] == evt.column-1 then -- if already this field, then change direction
|
||||||
mail.selected_idxs.sortdirection[name] = mail.selected_idxs.sortdirection[name] == "2" and "1" or "2"
|
mail.selected_idxs.sortdirection[name] = mail.selected_idxs.sortdirection[name] == "2" and "1" or "2"
|
||||||
end
|
end
|
||||||
mail.selected_idxs.sortfield[name] = evt.column-1 -- update column
|
mail.selected_idxs.sortfield[name] = evt.column-1 -- update column
|
||||||
mail.show_mail_menu(name)
|
mail.show_mail_menu(name)
|
||||||
return
|
return true
|
||||||
|
end
|
||||||
|
local inbox = getInbox()[evt.row-1]
|
||||||
|
if not inbox then
|
||||||
|
mail.show_mail_menu(name)
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
if mail.selected_idxs.multipleselection[name] then
|
if mail.selected_idxs.multipleselection[name] then
|
||||||
if not mail.selected_idxs.inbox[name] then
|
if not mail.selected_idxs.inbox[name] then
|
||||||
|
@ -67,7 +80,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
local selected_id = 0
|
local selected_id = 0
|
||||||
if mail.selected_idxs.inbox[name] and #mail.selected_idxs.inbox[name] > 0 then
|
if mail.selected_idxs.inbox[name] and #mail.selected_idxs.inbox[name] > 0 then
|
||||||
for i, selected_msg in ipairs(mail.selected_idxs.inbox[name]) do
|
for i, selected_msg in ipairs(mail.selected_idxs.inbox[name]) do
|
||||||
if getInbox()[evt.row-1].id == selected_msg then
|
if inbox.id == selected_msg then
|
||||||
selected_id = i
|
selected_id = i
|
||||||
table.remove(mail.selected_idxs.inbox[name], i)
|
table.remove(mail.selected_idxs.inbox[name], i)
|
||||||
break
|
break
|
||||||
|
@ -75,51 +88,62 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if selected_id == 0 then
|
if selected_id == 0 then
|
||||||
table.insert(mail.selected_idxs.inbox[name], getInbox()[evt.row-1].id)
|
table.insert(mail.selected_idxs.inbox[name], inbox.id)
|
||||||
|
mail.selected_idxs.message[name] = inbox.id
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
mail.selected_idxs.inbox[name] = { getInbox()[evt.row-1].id }
|
mail.selected_idxs.inbox[name] = { inbox.id }
|
||||||
|
mail.selected_idxs.message[name] = inbox.id
|
||||||
end
|
end
|
||||||
if evt.type == "DCL" and getInbox()[evt.row-1] then
|
if evt.type == "DCL" then
|
||||||
mail.show_message(name, getInbox()[evt.row-1].id)
|
mail.selected_idxs.message[name] = inbox.id
|
||||||
|
mail.show_message(name, inbox.id)
|
||||||
else
|
else
|
||||||
mail.show_mail_menu(name)
|
mail.show_mail_menu(name)
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
if fields.sent then -- sent table
|
if fields.outbox then -- outbox table
|
||||||
local evt = minetest.explode_table_event(fields.sent)
|
local evt = core.explode_table_event(fields.outbox)
|
||||||
if evt.row == 1 then -- header
|
if evt.row == 1 then -- header
|
||||||
if mail.selected_idxs.sortfield[name] == evt.column-1 then -- if already this field, then change direction
|
if mail.selected_idxs.sortfield[name] == evt.column-1 then -- if already this field, then change direction
|
||||||
mail.selected_idxs.sortdirection[name] = mail.selected_idxs.sortdirection[name] == "2" and "1" or "2"
|
mail.selected_idxs.sortdirection[name] = mail.selected_idxs.sortdirection[name] == "2" and "1" or "2"
|
||||||
end
|
end
|
||||||
mail.selected_idxs.sortfield[name] = evt.column-1 -- update column
|
mail.selected_idxs.sortfield[name] = evt.column-1 -- update column
|
||||||
mail.show_mail_menu(name)
|
mail.show_mail_menu(name)
|
||||||
return
|
return true
|
||||||
|
end
|
||||||
|
local outbox = getOutbox()[evt.row-1]
|
||||||
|
if not outbox then
|
||||||
|
mail.show_mail_menu(name)
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
if mail.selected_idxs.multipleselection[name] then
|
if mail.selected_idxs.multipleselection[name] then
|
||||||
if not mail.selected_idxs.sent[name] then
|
if not mail.selected_idxs.outbox[name] then
|
||||||
mail.selected_idxs.sent[name] = {}
|
mail.selected_idxs.outbox[name] = {}
|
||||||
end
|
end
|
||||||
local selected_id = 0
|
local selected_id = 0
|
||||||
if mail.selected_idxs.sent[name] and #mail.selected_idxs.sent[name] > 0 then
|
if mail.selected_idxs.outbox[name] and #mail.selected_idxs.outbox[name] > 0 then
|
||||||
for i, selected_msg in ipairs(mail.selected_idxs.sent[name]) do
|
for i, selected_msg in ipairs(mail.selected_idxs.outbox[name]) do
|
||||||
if getOutbox()[evt.row-1].id == selected_msg then
|
if outbox.id == selected_msg then
|
||||||
selected_id = i
|
selected_id = i
|
||||||
table.remove(mail.selected_idxs.sent[name], i)
|
table.remove(mail.selected_idxs.outbox[name], i)
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if selected_id == 0 then
|
if selected_id == 0 then
|
||||||
table.insert(mail.selected_idxs.sent[name], getOutbox()[evt.row-1].id)
|
table.insert(mail.selected_idxs.outbox[name], outbox.id)
|
||||||
|
mail.selected_idxs.message[name] = outbox.id
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
mail.selected_idxs.sent[name] = { getOutbox()[evt.row-1].id }
|
mail.selected_idxs.outbox[name] = { outbox.id }
|
||||||
|
mail.selected_idxs.message[name] = outbox.id
|
||||||
end
|
end
|
||||||
if evt.type == "DCL" and getOutbox()[evt.row-1] then
|
if evt.type == "DCL" then
|
||||||
mail.show_message(name, getOutbox()[evt.row-1].id)
|
mail.selected_idxs.message[name] = outbox.id
|
||||||
|
mail.show_message(name, outbox.id)
|
||||||
else
|
else
|
||||||
mail.show_mail_menu(name)
|
mail.show_mail_menu(name)
|
||||||
end
|
end
|
||||||
|
@ -127,7 +151,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
end
|
end
|
||||||
|
|
||||||
if fields.drafts then -- drafts table
|
if fields.drafts then -- drafts table
|
||||||
local evt = minetest.explode_table_event(fields.drafts)
|
local evt = core.explode_table_event(fields.drafts)
|
||||||
if evt.row == 1 then -- header
|
if evt.row == 1 then -- header
|
||||||
if mail.selected_idxs.sortfield[name] == evt.column-1 then -- if already this field, then change direction
|
if mail.selected_idxs.sortfield[name] == evt.column-1 then -- if already this field, then change direction
|
||||||
mail.selected_idxs.sortdirection[name] = mail.selected_idxs.sortdirection[name] == "2" and "1" or "2"
|
mail.selected_idxs.sortdirection[name] = mail.selected_idxs.sortdirection[name] == "2" and "1" or "2"
|
||||||
|
@ -138,6 +162,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
end
|
end
|
||||||
mail.selected_idxs.drafts[name] = evt.row - 1
|
mail.selected_idxs.drafts[name] = evt.row - 1
|
||||||
if evt.type == "DCL" and messagesDrafts[mail.selected_idxs.drafts[name]] then
|
if evt.type == "DCL" and messagesDrafts[mail.selected_idxs.drafts[name]] then
|
||||||
|
mail.selected_idxs.message[name] = messagesDrafts[mail.selected_idxs.drafts[name]].id
|
||||||
mail.show_compose(name,
|
mail.show_compose(name,
|
||||||
messagesDrafts[mail.selected_idxs.drafts[name]].to,
|
messagesDrafts[mail.selected_idxs.drafts[name]].to,
|
||||||
messagesDrafts[mail.selected_idxs.drafts[name]].subject,
|
messagesDrafts[mail.selected_idxs.drafts[name]].subject,
|
||||||
|
@ -150,23 +175,50 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if fields.trash then -- trash table
|
||||||
|
local evt = core.explode_table_event(fields.trash)
|
||||||
|
if evt.row == 1 then -- header
|
||||||
|
if mail.selected_idxs.sortfield[name] == evt.column-1 then -- if already this field, then change direction
|
||||||
|
mail.selected_idxs.sortdirection[name] = mail.selected_idxs.sortdirection[name] == "2" and "1" or "2"
|
||||||
|
end
|
||||||
|
mail.selected_idxs.sortfield[name] = evt.column-1 -- update column
|
||||||
|
mail.show_mail_menu(name)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
mail.selected_idxs.trash[name] = evt.row - 1
|
||||||
|
if evt.type == "DCL" and messagesTrash[mail.selected_idxs.trash[name]] then
|
||||||
|
mail.selected_idxs.message[name] = messagesTrash[mail.selected_idxs.trash[name]].id
|
||||||
|
mail.show_message(name, messagesTrash[mail.selected_idxs.trash[name]].id)
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
if fields.boxtab == "1" then
|
if fields.boxtab == "1" then
|
||||||
mail.selected_idxs.boxtab[name] = 1
|
mail.selected_idxs.boxtab[name] = 1
|
||||||
mail.show_inbox(name, sortfieldindex, sortdirection, filter)
|
mail.show_inbox(name, sortfieldindex, sortdirection, filter)
|
||||||
|
|
||||||
elseif fields.boxtab == "2" then
|
elseif fields.boxtab == "2" then
|
||||||
mail.selected_idxs.boxtab[name] = 2
|
mail.selected_idxs.boxtab[name] = 2
|
||||||
mail.show_sent(name, sortfieldindex, sortdirection, filter)
|
mail.show_outbox(name, sortfieldindex, sortdirection, filter)
|
||||||
|
|
||||||
elseif fields.boxtab == "3" then
|
elseif fields.boxtab == "3" then
|
||||||
mail.selected_idxs.boxtab[name] = 3
|
mail.selected_idxs.boxtab[name] = 3
|
||||||
mail.show_drafts(name)
|
mail.show_drafts(name)
|
||||||
|
|
||||||
|
elseif fields.boxtab == "4" then
|
||||||
|
mail.selected_idxs.boxtab[name] = 4
|
||||||
|
mail.show_trash(name)
|
||||||
|
|
||||||
elseif fields.read then
|
elseif fields.read then
|
||||||
if formname == "mail:inbox" and mail.selected_idxs.inbox[name] then -- inbox table
|
if formname == "mail:inbox" and nonempty(mail.selected_idxs.inbox[name]) then -- inbox table
|
||||||
mail.show_message(name, mail.selected_idxs.inbox[name][#mail.selected_idxs.inbox[name]])
|
mail.selected_idxs.message[name] = mail.selected_idxs.inbox[name][#mail.selected_idxs.inbox[name]]
|
||||||
elseif formname == "mail:sent" and mail.selected_idxs.sent[name] then -- sent table
|
elseif formname == "mail:outbox" and nonempty(mail.selected_idxs.outbox[name]) then -- outbox table
|
||||||
mail.show_message(name, mail.selected_idxs.inbox[name][#mail.selected_idxs.inbox[name]])
|
mail.selected_idxs.message[name] = mail.selected_idxs.outbox[name][#mail.selected_idxs.outbox[name]]
|
||||||
|
elseif formname == "mail:trash" and messagesTrash[mail.selected_idxs.trash[name]] then
|
||||||
|
mail.selected_idxs.message[name] = messagesTrash[mail.selected_idxs.trash[name]].id
|
||||||
|
end
|
||||||
|
if mail.selected_idxs.message[name] then
|
||||||
|
mail.show_message(name, mail.selected_idxs.message[name])
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif fields.edit then
|
elseif fields.edit then
|
||||||
|
@ -182,40 +234,68 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif fields.delete then
|
elseif fields.delete then
|
||||||
|
local trash_enabled = mail.get_setting(name, "trash_move_enable")
|
||||||
if formname == "mail:inbox" and mail.selected_idxs.inbox[name] then -- inbox table
|
if formname == "mail:inbox" and mail.selected_idxs.inbox[name] then -- inbox table
|
||||||
mail.delete_mail(name, mail.selected_idxs.inbox[name])
|
if trash_enabled then
|
||||||
elseif formname == "mail:sent" and mail.selected_idxs.sent[name] then -- sent table
|
mail.trash_mail(name, mail.selected_idxs.inbox[name])
|
||||||
mail.delete_mail(name, mail.selected_idxs.sent[name])
|
else
|
||||||
|
mail.delete_mail(name, mail.selected_idxs.inbox[name])
|
||||||
|
end
|
||||||
|
mail.selected_idxs.inbox[name] = {}
|
||||||
|
elseif formname == "mail:outbox" and mail.selected_idxs.outbox[name] then -- outbox table
|
||||||
|
if trash_enabled then
|
||||||
|
mail.trash_mail(name, mail.selected_idxs.outbox[name])
|
||||||
|
else
|
||||||
|
mail.delete_mail(name, mail.selected_idxs.outbox[name])
|
||||||
|
end
|
||||||
|
mail.selected_idxs.outbox[name] = {}
|
||||||
elseif formname == "mail:drafts" and messagesDrafts[mail.selected_idxs.drafts[name]] then -- drafts table
|
elseif formname == "mail:drafts" and messagesDrafts[mail.selected_idxs.drafts[name]] then -- drafts table
|
||||||
mail.delete_mail(name, messagesDrafts[mail.selected_idxs.drafts[name]].id)
|
if trash_enabled then
|
||||||
|
mail.trash_mail(name, messagesDrafts[mail.selected_idxs.drafts[name]].id)
|
||||||
|
else
|
||||||
|
mail.delete_mail(name, messagesDrafts[mail.selected_idxs.drafts[name]].id)
|
||||||
|
end
|
||||||
|
mail.selected_idxs.drafts[name] = nil
|
||||||
|
|
||||||
|
elseif formname == "mail:trash" and messagesTrash[mail.selected_idxs.trash[name]] then -- trash table
|
||||||
|
mail.delete_mail(name, messagesTrash[mail.selected_idxs.trash[name]].id, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
mail.show_mail_menu(name, sortfieldindex, sortdirection, filter)
|
mail.show_mail_menu(name, sortfieldindex, sortdirection, filter)
|
||||||
|
|
||||||
|
elseif fields.restore then
|
||||||
|
if messagesTrash[mail.selected_idxs.trash[name]] then
|
||||||
|
mail.restore_mail(name, messagesTrash[mail.selected_idxs.trash[name]].id)
|
||||||
|
end
|
||||||
|
mail.show_mail_menu(name, sortfieldindex, sortdirection, filter)
|
||||||
|
|
||||||
elseif fields.reply then
|
elseif fields.reply then
|
||||||
if formname == "mail:inbox" and mail.selected_idxs.inbox[name] then
|
if formname == "mail:inbox" and mail.selected_idxs.inbox[name] and #mail.selected_idxs.inbox[name] > 0 then
|
||||||
local message = mail.get_message(name, mail.selected_idxs.inbox[name][#mail.selected_idxs.inbox[name]])
|
local message = mail.get_message(name, mail.selected_idxs.inbox[name][#mail.selected_idxs.inbox[name]])
|
||||||
mail.reply(name, message)
|
mail.reply(name, message)
|
||||||
elseif formname == "mail:sent" and mail.selected_idxs.sent[name] then
|
elseif
|
||||||
local message = mail.get_message(name, mail.selected_idxs.sent[name][#mail.selected_idxs.sent[name]])
|
formname == "mail:outbox" and mail.selected_idxs.outbox[name] and #mail.selected_idxs.outbox[name] > 0 then
|
||||||
|
local message = mail.get_message(name, mail.selected_idxs.outbox[name][#mail.selected_idxs.outbox[name]])
|
||||||
mail.reply(name, message)
|
mail.reply(name, message)
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif fields.replyall then
|
elseif fields.replyall then
|
||||||
if formname == "mail:inbox" and mail.selected_idxs.inbox[name] then
|
if formname == "mail:inbox" and mail.selected_idxs.inbox[name] and #mail.selected_idxs.inbox[name] > 0 then
|
||||||
local message = mail.get_message(name, mail.selected_idxs.inbox[name][#mail.selected_idxs.inbox[name]])
|
local message = mail.get_message(name, mail.selected_idxs.inbox[name][#mail.selected_idxs.inbox[name]])
|
||||||
mail.replyall(name, message)
|
mail.replyall(name, message)
|
||||||
elseif formname == "mail:sent" and mail.selected_idxs.sent[name] then
|
elseif
|
||||||
local message = mail.get_message(name, mail.selected_idxs.sent[name][#mail.selected_idxs.sent[name]])
|
formname == "mail:outbox" and mail.selected_idxs.outbox[name] and #mail.selected_idxs.outbox[name] > 0 then
|
||||||
|
local message = mail.get_message(name, mail.selected_idxs.outbox[name][#mail.selected_idxs.outbox[name]])
|
||||||
mail.replyall(name, message)
|
mail.replyall(name, message)
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif fields.forward then
|
elseif fields.forward then
|
||||||
if formname == "mail:inbox" and mail.selected_idxs.inbox[name] then
|
if formname == "mail:inbox" and mail.selected_idxs.inbox[name] and #mail.selected_idxs.inbox[name] > 0 then
|
||||||
local message = mail.get_message(name, mail.selected_idxs.inbox[name][#mail.selected_idxs.inbox[name]])
|
local message = mail.get_message(name, mail.selected_idxs.inbox[name][#mail.selected_idxs.inbox[name]])
|
||||||
mail.forward(name, message)
|
mail.forward(name, message)
|
||||||
elseif formname == "mail:sent" and mail.selected_idxs.sent[name] then
|
elseif
|
||||||
local message = mail.get_message(name, mail.selected_idxs.sent[name][#mail.selected_idxs.sent[name]])
|
formname == "mail:outbox" and mail.selected_idxs.outbox[name] and #mail.selected_idxs.outbox[name] > 0 then
|
||||||
|
local message = mail.get_message(name, mail.selected_idxs.outbox[name][#mail.selected_idxs.outbox[name]])
|
||||||
mail.forward(name, message)
|
mail.forward(name, message)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -233,43 +313,53 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
|
|
||||||
mail.show_mail_menu(name, sortfieldindex, sortdirection, filter)
|
mail.show_mail_menu(name, sortfieldindex, sortdirection, filter)
|
||||||
|
|
||||||
|
elseif fields.markspam then
|
||||||
|
if formname == "mail:inbox" and mail.selected_idxs.inbox[name] then
|
||||||
|
mail.mark_spam(name, mail.selected_idxs.inbox[name])
|
||||||
|
end
|
||||||
|
|
||||||
|
mail.show_mail_menu(name, sortfieldindex, sortdirection, filter)
|
||||||
|
|
||||||
|
elseif fields.unmarkspam then
|
||||||
|
if formname == "mail:inbox" and mail.selected_idxs.inbox[name] then
|
||||||
|
mail.unmark_spam(name, mail.selected_idxs.inbox[name])
|
||||||
|
end
|
||||||
|
|
||||||
|
mail.show_mail_menu(name, sortfieldindex, sortdirection, filter)
|
||||||
|
|
||||||
elseif fields.new then
|
elseif fields.new then
|
||||||
mail.show_compose(name)
|
mail.show_compose(name)
|
||||||
|
|
||||||
|
elseif fields.empty then
|
||||||
|
mail.empty_trash(name)
|
||||||
|
mail.show_mail_menu(name)
|
||||||
|
|
||||||
elseif fields.contacts then
|
elseif fields.contacts then
|
||||||
mail.show_contacts(name)
|
mail.show_contacts(name)
|
||||||
|
|
||||||
elseif fields.maillists then
|
elseif fields.maillists then
|
||||||
mail.show_maillists(name)
|
mail.show_maillists(name)
|
||||||
|
|
||||||
elseif fields.about then
|
elseif fields.options then
|
||||||
mail.show_about(name)
|
mail.show_options(name)
|
||||||
|
|
||||||
elseif fields.selectall then
|
elseif fields.selectall then
|
||||||
if formname == "mail:inbox" then
|
if formname == "mail:inbox" then
|
||||||
if not mail.selected_idxs.inbox[name] then
|
local selected_number = #mail.selected_idxs.inbox[name]
|
||||||
mail.selected_idxs.inbox[name] = {}
|
mail.selected_idxs.inbox[name] = {} -- reset for select, unselect and not existing
|
||||||
end
|
mail.selected_idxs.multipleselection[name] = true -- enable as the button were pressed
|
||||||
if #mail.selected_idxs.inbox[name] >= #getInbox() then -- if selection is full
|
if selected_number < #getInbox() then -- then populate it if selection isn't full
|
||||||
mail.selected_idxs.inbox[name] = {}
|
|
||||||
else
|
|
||||||
mail.selected_idxs.inbox[name] = {} -- reset to avoid duplicates
|
|
||||||
mail.selected_idxs.multipleselection[name] = true
|
|
||||||
for _, msg in ipairs(getInbox()) do
|
for _, msg in ipairs(getInbox()) do
|
||||||
table.insert(mail.selected_idxs.inbox[name], msg.id)
|
table.insert(mail.selected_idxs.inbox[name], msg.id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif formname == "mail:sent" then
|
elseif formname == "mail:outbox" then
|
||||||
if not mail.selected_idxs.sent[name] then
|
local selected_number = #mail.selected_idxs.outbox[name]
|
||||||
mail.selected_idxs.sent[name] = {}
|
mail.selected_idxs.outbox[name] = {} -- reset for select, unselect and not existing
|
||||||
end
|
mail.selected_idxs.multipleselection[name] = true -- enable as the button were pressed
|
||||||
if #mail.selected_idxs.sent[name] >= #getOutbox() then -- if selection is full
|
if selected_number < #getOutbox() then -- then populate it if selection isn't full
|
||||||
mail.selected_idxs.sent[name] = {}
|
|
||||||
else
|
|
||||||
mail.selected_idxs.sent[name] = {} -- reset to avoid duplicates
|
|
||||||
mail.selected_idxs.multipleselection[name] = true
|
|
||||||
for _, msg in ipairs(getOutbox()) do
|
for _, msg in ipairs(getOutbox()) do
|
||||||
table.insert(mail.selected_idxs.sent[name], msg.id)
|
table.insert(mail.selected_idxs.outbox[name], msg.id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
129
ui/inbox.lua
129
ui/inbox.lua
|
@ -1,15 +1,41 @@
|
||||||
-- translation
|
-- translation
|
||||||
local S = minetest.get_translator("mail")
|
local S = mail.S
|
||||||
|
|
||||||
|
|
||||||
function mail.show_inbox(name, sortfieldindex, sortdirection, filter)
|
function mail.show_inbox(name, sortfieldindex, sortdirection, filter)
|
||||||
sortfieldindex = tonumber(sortfieldindex or mail.selected_idxs.sortfield[name]) or 3
|
sortfieldindex = tonumber(sortfieldindex or mail.selected_idxs.sortfield[name])
|
||||||
sortdirection = sortdirection or mail.selected_idxs.sortdirection[name] or "1"
|
or mail.get_setting(name, "defaultsortfield") or 3
|
||||||
|
sortdirection = tostring(sortdirection or mail.selected_idxs.sortdirection[name]
|
||||||
|
or mail.get_setting(name, "defaultsortdirection") or "1")
|
||||||
filter = filter or mail.selected_idxs.filter[name] or ""
|
filter = filter or mail.selected_idxs.filter[name] or ""
|
||||||
mail.selected_idxs.inbox[name] = mail.selected_idxs.inbox[name] or {}
|
mail.selected_idxs.inbox[name] = mail.selected_idxs.inbox[name] or {}
|
||||||
|
|
||||||
local inbox_formspec = "size[8.5,10;]" .. mail.theme .. [[
|
local entry = mail.get_storage_entry(name)
|
||||||
tabheader[0.3,1;boxtab;]] .. S("Inbox") .. "," .. S("Sent messages").. "," .. S("Drafts") .. [[;1;false;false]
|
local sortfield = ({"from","subject","time"})[sortfieldindex]
|
||||||
|
local messages = mail.sort_messages(entry.inbox, sortfield, sortdirection == "2", filter)
|
||||||
|
|
||||||
|
if mail.selected_idxs.inbox[name] and #mail.selected_idxs.inbox[name] > 0 then
|
||||||
|
for i, selected_msg in ipairs(mail.selected_idxs.inbox[name]) do
|
||||||
|
local is_present = false
|
||||||
|
for _, msg in ipairs(messages) do
|
||||||
|
if msg.id == selected_msg then
|
||||||
|
is_present = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not is_present then
|
||||||
|
table.remove(mail.selected_idxs.inbox[name], i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local trash_tab = ""
|
||||||
|
if mail.get_setting(name, "trash_move_enable") then
|
||||||
|
trash_tab = "," .. S("Trash")
|
||||||
|
end
|
||||||
|
|
||||||
|
local inbox_formspec = "size[8.5,11;]" .. mail.theme .. [[
|
||||||
|
tabheader[0.3,1;boxtab;]] ..
|
||||||
|
S("Inbox") .. "," .. S("Outbox").. "," .. S("Drafts") .. trash_tab .. [[;1;false;false]
|
||||||
|
|
||||||
button[6,0.10;2.5,0.5;new;]] .. S("New") .. [[]
|
button[6,0.10;2.5,0.5;new;]] .. S("New") .. [[]
|
||||||
button[6,0.95;2.5,0.5;read;]] .. S("Read") .. [[]
|
button[6,0.95;2.5,0.5;read;]] .. S("Read") .. [[]
|
||||||
|
@ -17,37 +43,46 @@ function mail.show_inbox(name, sortfieldindex, sortdirection, filter)
|
||||||
button[6,2.45;2.5,0.5;replyall;]] .. S("Reply all") .. [[]
|
button[6,2.45;2.5,0.5;replyall;]] .. S("Reply all") .. [[]
|
||||||
button[6,3.20;2.5,0.5;forward;]] .. S("Forward") .. [[]
|
button[6,3.20;2.5,0.5;forward;]] .. S("Forward") .. [[]
|
||||||
button[6,3.95;2.5,0.5;delete;]] .. S("Delete") .. [[]
|
button[6,3.95;2.5,0.5;delete;]] .. S("Delete") .. [[]
|
||||||
button[6,4.82;2.5,0.5;markread;]] .. S("Mark Read") .. [[]
|
button[6,4.85;2.5,0.5;markread;]] .. S("Mark Read") .. [[]
|
||||||
button[6,5.55;2.5,0.5;markunread;]] .. S("Mark Unread") .. [[]
|
button[6,5.55;2.5,0.5;markunread;]] .. S("Mark Unread") .. [[]
|
||||||
button[6,6.8;2.5,0.5;contacts;]] .. S("Contacts") .. [[]
|
button[6,6.4;2.5,0.5;markspam;]] .. S("Mark Spam") .. [[]
|
||||||
button[6,7.6;2.5,0.5;maillists;]] .. S("Mail lists") .. [[]
|
button[6,7.1;2.5,0.5;unmarkspam;]] .. S("Unmark Spam") .. [[]
|
||||||
button[6,8.7;2.5,0.5;about;]] .. S("About") .. [[]
|
button[6,8.0;2.5,0.5;contacts;]] .. S("Contacts") .. [[]
|
||||||
button_exit[6,9.5;2.5,0.5;quit;]] .. S("Close") .. [[]
|
button[6,8.8;2.5,0.5;maillists;]] .. S("Mail lists") .. [[]
|
||||||
|
button[6,9.7;2.5,0.5;options;]] .. S("Options") .. [[]
|
||||||
|
button_exit[6,10.5;2.5,0.5;quit;]] .. S("Close") .. [[]
|
||||||
|
|
||||||
dropdown[0,8.4;2,0.5;sortfield;]] ..
|
tooltip[reply;]] .. S("Reply only to the sender") .. [[]
|
||||||
|
tooltip[replyall;]] .. S("Reply to all involved people") .. [[]
|
||||||
|
tooltip[forward;]] .. S("Transfer message to other people") .. [[]
|
||||||
|
|
||||||
|
dropdown[0,9.5;2,0.5;sortfield;]] ..
|
||||||
S("From") .. "," .. S("Subject") .. "," .. S("Date") .. [[;]] .. sortfieldindex .. [[;true]
|
S("From") .. "," .. S("Subject") .. "," .. S("Date") .. [[;]] .. sortfieldindex .. [[;true]
|
||||||
dropdown[2.0,8.4;2,0.5;sortdirection;]] ..
|
dropdown[2.0,9.5;2,0.5;sortdirection;]] ..
|
||||||
S("Ascending") .. "," .. S("Descending") .. [[;]] .. sortdirection .. [[;true]
|
S("Ascending") .. "," .. S("Descending") .. [[;]] .. sortdirection .. [[;true]
|
||||||
field[4.25,8.85;1.4,0.5;filter;]] .. S("Filter") .. [[:;]] .. filter .. [[]
|
field[4.25,9.95;1.4,0.5;filter;]] .. S("Filter") .. [[:;]] .. filter .. [[]
|
||||||
button[5.14,8.52;0.85,0.5;search;Q]
|
image_button[5.14,9.5;0.85,0.85;search.png;search;]
|
||||||
|
|
||||||
checkbox[0,9.1;multipleselection;]] .. S("Allow multiple selection") .. [[;]] ..
|
checkbox[0,10.1;multipleselection;]] .. S("Allow multiple selection") .. [[;]] ..
|
||||||
tostring(mail.selected_idxs.multipleselection[name]) .. [[]
|
tostring(mail.selected_idxs.multipleselection[name]) .. [[]
|
||||||
label[0,9.65;]] .. tostring(#mail.selected_idxs.inbox[name]) .. " " .. S("selected") .. [[]
|
label[0,10.65;]] ..
|
||||||
button[3.5,9.5;2.5,0.5;selectall;]] .. S("(Un)select all") .. [[]
|
S("@1 of @2 selected", tostring(#mail.selected_idxs.inbox[name]), tostring(#messages)) .. [[]
|
||||||
|
button[3.5,10.5;2.5,0.5;selectall;]] .. S("(Un)select all") .. [[]
|
||||||
|
|
||||||
tablecolumns[color;text;text]
|
tablecolumns[color;text;text]
|
||||||
table[0,0.7;5.75,7.35;inbox;#999,]] .. S("From") .. "," .. S("Subject")
|
table[0,0.7;5.75,8.45;inbox;]] .. mail.get_color("header") .. "," .. S("From") .. "," .. S("Subject")
|
||||||
local formspec = { inbox_formspec }
|
local formspec = { inbox_formspec }
|
||||||
local entry = mail.get_storage_entry(name)
|
|
||||||
local sortfield = ({"from","subject","time"})[sortfieldindex]
|
|
||||||
local messages = mail.sort_messages(entry.inbox, sortfield, sortdirection == "2", filter)
|
|
||||||
|
|
||||||
mail.message_drafts[name] = nil
|
mail.message_drafts[name] = nil
|
||||||
|
|
||||||
|
local unread_color_enable = mail.get_setting(name, "unreadcolorenable")
|
||||||
|
local cc_color_enable = mail.get_setting(name, "cccolorenable")
|
||||||
|
local mute_list = mail.get_setting(name, "mute_list")
|
||||||
|
|
||||||
if #messages > 0 then
|
if #messages > 0 then
|
||||||
for _, message in ipairs(messages) do
|
for _, message in ipairs(messages) do
|
||||||
local selected_id = 0
|
local selected_id = 0
|
||||||
|
local displayed_color = {}
|
||||||
-- check if message is in selection list and return its id
|
-- check if message is in selection list and return its id
|
||||||
if mail.selected_idxs.inbox[name] and #mail.selected_idxs.inbox[name] > 0 then
|
if mail.selected_idxs.inbox[name] and #mail.selected_idxs.inbox[name] > 0 then
|
||||||
for i, selected_msg in ipairs(mail.selected_idxs.inbox[name]) do
|
for i, selected_msg in ipairs(mail.selected_idxs.inbox[name]) do
|
||||||
|
@ -58,43 +93,30 @@ function mail.show_inbox(name, sortfieldindex, sortdirection, filter)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if selected_id > 0 then
|
if selected_id > 0 then
|
||||||
if not message.read then
|
table.insert(displayed_color, "selected")
|
||||||
if not mail.player_in_list(name, message.to) then
|
|
||||||
formspec[#formspec + 1] = ",#A39E5D"
|
|
||||||
else
|
|
||||||
formspec[#formspec + 1] = ",#A39E19"
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if not mail.player_in_list(name, message.to) then
|
|
||||||
formspec[#formspec + 1] = ",#899888"
|
|
||||||
else
|
|
||||||
formspec[#formspec + 1] = ",#466432"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if not message.read then
|
|
||||||
if not mail.player_in_list(name, message.to) then
|
|
||||||
formspec[#formspec + 1] = ",#FFD788"
|
|
||||||
else
|
|
||||||
formspec[#formspec + 1] = ",#FFD700"
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if not mail.player_in_list(name, message.to) then
|
|
||||||
formspec[#formspec + 1] = ",#CCCCDD"
|
|
||||||
else
|
|
||||||
formspec[#formspec + 1] = ","
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
if not message.read and unread_color_enable then
|
||||||
|
table.insert(displayed_color, "important")
|
||||||
|
end
|
||||||
|
if not mail.player_in_list(name, message.to) and cc_color_enable then
|
||||||
|
table.insert(displayed_color, "additional")
|
||||||
|
end
|
||||||
|
if message.spam then
|
||||||
|
table.insert(displayed_color, "warning")
|
||||||
|
end
|
||||||
|
if table.indexof(mute_list, message.from) >= 1 then
|
||||||
|
table.insert(displayed_color, "muted")
|
||||||
|
end
|
||||||
|
formspec[#formspec + 1] = "," .. mail.get_color(displayed_color)
|
||||||
formspec[#formspec + 1] = ","
|
formspec[#formspec + 1] = ","
|
||||||
formspec[#formspec + 1] = minetest.formspec_escape(message.from)
|
formspec[#formspec + 1] = core.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
|
||||||
formspec[#formspec + 1] = minetest.formspec_escape(string.sub(message.subject, 1, 27))
|
formspec[#formspec + 1] = core.formspec_escape(string.sub(message.subject, 1, 27))
|
||||||
formspec[#formspec + 1] = "..."
|
formspec[#formspec + 1] = "..."
|
||||||
else
|
else
|
||||||
formspec[#formspec + 1] = minetest.formspec_escape(message.subject)
|
formspec[#formspec + 1] = core.formspec_escape(message.subject)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
formspec[#formspec + 1] = S("(No subject)")
|
formspec[#formspec + 1] = S("(No subject)")
|
||||||
|
@ -104,5 +126,6 @@ function mail.show_inbox(name, sortfieldindex, sortdirection, filter)
|
||||||
else
|
else
|
||||||
formspec[#formspec + 1] = "]label[2.25,4.5;" .. S("No mail") .. "]"
|
formspec[#formspec + 1] = "]label[2.25,4.5;" .. S("No mail") .. "]"
|
||||||
end
|
end
|
||||||
minetest.show_formspec(name, "mail:inbox", table.concat(formspec, ""))
|
|
||||||
|
core.show_formspec(name, "mail:inbox", table.concat(formspec, ""))
|
||||||
end
|
end
|
||||||
|
|
37
ui/init.lua
Normal file
37
ui/init.lua
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
-- sub files
|
||||||
|
local MP = core.get_modpath(core.get_current_modname())
|
||||||
|
|
||||||
|
dofile(MP .. "/ui/inbox.lua")
|
||||||
|
dofile(MP .. "/ui/outbox.lua")
|
||||||
|
dofile(MP .. "/ui/drafts.lua")
|
||||||
|
dofile(MP .. "/ui/trash.lua")
|
||||||
|
dofile(MP .. "/ui/message.lua")
|
||||||
|
dofile(MP .. "/ui/receivers.lua")
|
||||||
|
dofile(MP .. "/ui/events.lua")
|
||||||
|
dofile(MP .. "/ui/contacts.lua")
|
||||||
|
dofile(MP .. "/ui/edit_contact.lua")
|
||||||
|
dofile(MP .. "/ui/select_contact.lua")
|
||||||
|
dofile(MP .. "/ui/maillists.lua")
|
||||||
|
dofile(MP .. "/ui/edit_maillists.lua")
|
||||||
|
dofile(MP .. "/ui/compose.lua")
|
||||||
|
dofile(MP .. "/ui/options.lua")
|
||||||
|
dofile(MP .. "/ui/settings.lua")
|
||||||
|
dofile(MP .. "/ui/about.lua")
|
||||||
|
|
||||||
|
-- helper function for tabbed overview
|
||||||
|
|
||||||
|
function mail.show_mail_menu(playername, sortfield, sortdirection, filter)
|
||||||
|
local index = mail.selected_idxs.boxtab[playername] or 1
|
||||||
|
if not mail.selected_idxs.boxtab[playername] then
|
||||||
|
mail.selected_idxs.boxtab[playername] = 1
|
||||||
|
end
|
||||||
|
if index == 1 then
|
||||||
|
mail.show_inbox(playername, sortfield, sortdirection, filter)
|
||||||
|
elseif index == 2 then
|
||||||
|
mail.show_outbox(playername, sortfield, sortdirection, filter)
|
||||||
|
elseif index == 3 then
|
||||||
|
mail.show_drafts(playername)
|
||||||
|
elseif index == 4 then
|
||||||
|
mail.show_trash(playername)
|
||||||
|
end
|
||||||
|
end
|
12
ui/mail.lua
12
ui/mail.lua
|
@ -1,12 +0,0 @@
|
||||||
-- helper function for tabbed overview
|
|
||||||
|
|
||||||
function mail.show_mail_menu(playername, sortfield, sortdirection, filter)
|
|
||||||
local index = mail.selected_idxs.boxtab[playername] or 1
|
|
||||||
if index == 1 then
|
|
||||||
mail.show_inbox(playername, sortfield, sortdirection, filter)
|
|
||||||
elseif index == 2 then
|
|
||||||
mail.show_sent(playername, sortfield, sortdirection, filter)
|
|
||||||
elseif index == 3 then
|
|
||||||
mail.show_drafts(playername)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,5 +1,5 @@
|
||||||
-- translation
|
-- translation
|
||||||
local S = minetest.get_translator("mail")
|
local S = mail.S
|
||||||
|
|
||||||
local FORMNAME = "mail:maillists"
|
local FORMNAME = "mail:maillists"
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ local maillists_formspec = "size[8,9;]" .. mail.theme .. [[
|
||||||
button[6,1.60;2,0.5;delete;]] .. S("Delete") .. [[]
|
button[6,1.60;2,0.5;delete;]] .. S("Delete") .. [[]
|
||||||
button[6,8.25;2,0.5;back;]] .. S("Back") .. [[]
|
button[6,8.25;2,0.5;back;]] .. S("Back") .. [[]
|
||||||
tablecolumns[color;text;text]
|
tablecolumns[color;text;text]
|
||||||
table[0,0;5.75,9;maillists;#999,]] .. S("Name") .. "," .. S("Note")
|
table[0,0;5.75,9;maillists;]] .. mail.get_color("header") .. "," .. S("Name") .. "," .. S("Note")
|
||||||
|
|
||||||
function mail.show_maillists(name)
|
function mail.show_maillists(name)
|
||||||
local formspec = { maillists_formspec }
|
local formspec = { maillists_formspec }
|
||||||
|
@ -19,14 +19,14 @@ function mail.show_maillists(name)
|
||||||
for _, maillist in ipairs(maillists) do
|
for _, maillist in ipairs(maillists) do
|
||||||
formspec[#formspec + 1] = ","
|
formspec[#formspec + 1] = ","
|
||||||
formspec[#formspec + 1] = ","
|
formspec[#formspec + 1] = ","
|
||||||
formspec[#formspec + 1] = "@" .. minetest.formspec_escape(maillist.name)
|
formspec[#formspec + 1] = "@" .. core.formspec_escape(maillist.name)
|
||||||
formspec[#formspec + 1] = ","
|
formspec[#formspec + 1] = ","
|
||||||
if maillist.desc ~= "" then
|
if maillist.desc ~= "" then
|
||||||
if string.len(maillist.desc) > 30 then
|
if string.len(maillist.desc or "") > 30 then
|
||||||
formspec[#formspec + 1] = minetest.formspec_escape(string.sub(maillist.desc, 1, 27))
|
formspec[#formspec + 1] = core.formspec_escape(string.sub(maillist.desc, 1, 27))
|
||||||
formspec[#formspec + 1] = "..."
|
formspec[#formspec + 1] = "..."
|
||||||
else
|
else
|
||||||
formspec[#formspec + 1] = minetest.formspec_escape(maillist.desc)
|
formspec[#formspec + 1] = core.formspec_escape(maillist.desc)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
formspec[#formspec + 1] = S("(No description)")
|
formspec[#formspec + 1] = S("(No description)")
|
||||||
|
@ -40,10 +40,10 @@ function mail.show_maillists(name)
|
||||||
else
|
else
|
||||||
formspec[#formspec + 1] = "]label[2.25,4.5;" .. S("No maillist") .. "]"
|
formspec[#formspec + 1] = "]label[2.25,4.5;" .. S("No maillist") .. "]"
|
||||||
end
|
end
|
||||||
minetest.show_formspec(name, FORMNAME, table.concat(formspec, ""))
|
core.show_formspec(name, FORMNAME, table.concat(formspec, ""))
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
core.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
if formname ~= FORMNAME then
|
if formname ~= FORMNAME then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -52,7 +52,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
local maillists = mail.get_maillists(name)
|
local maillists = mail.get_maillists(name)
|
||||||
|
|
||||||
if fields.maillists then
|
if fields.maillists then
|
||||||
local evt = minetest.explode_table_event(fields.maillists)
|
local evt = core.explode_table_event(fields.maillists)
|
||||||
mail.selected_idxs.maillists[name] = evt.row - 1
|
mail.selected_idxs.maillists[name] = evt.row - 1
|
||||||
if evt.type == "DCL" and maillists[mail.selected_idxs.maillists[name]] then
|
if evt.type == "DCL" and maillists[mail.selected_idxs.maillists[name]] then
|
||||||
local maillist = mail.get_maillist_by_name(name, maillists[mail.selected_idxs.maillists[name]].name)
|
local maillist = mail.get_maillist_by_name(name, maillists[mail.selected_idxs.maillists[name]].name)
|
||||||
|
@ -85,7 +85,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
-- except if it was the last. Then determine the new last
|
-- except if it was the last. Then determine the new last
|
||||||
local found = false
|
local found = false
|
||||||
local last = nil
|
local last = nil
|
||||||
for k in mail.pairsByKeys(maillists) do
|
for k in mail.pairs_by_keys(maillists) do
|
||||||
if found then
|
if found then
|
||||||
mail.selected_idxs.maillists[name] = k
|
mail.selected_idxs.maillists[name] = k
|
||||||
break
|
break
|
||||||
|
|
132
ui/message.lua
132
ui/message.lua
|
@ -1,56 +1,94 @@
|
||||||
-- translation
|
-- translation
|
||||||
local S = minetest.get_translator("mail")
|
local S = mail.S
|
||||||
|
|
||||||
local FORMNAME = "mail:message"
|
local FORMNAME = "mail:message"
|
||||||
|
|
||||||
|
local function interleave_msg(body)
|
||||||
|
return "> " .. (body or ""):gsub("\n", "\n> ")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function mail.show_message(name, id)
|
function mail.show_message(name, id)
|
||||||
local message = mail.get_message(name, id)
|
local message = mail.get_message(name, id)
|
||||||
|
if not message then
|
||||||
|
-- message not found or vanished
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
mail.selected_idxs.message[name] = id
|
||||||
|
|
||||||
local formspec = [[
|
local formspec = [[
|
||||||
size[8,9]
|
size[10,10]
|
||||||
|
|
||||||
box[0,0;7,1.9;#466432]
|
box[0,0;7,1.9;]] .. mail.get_color("highlighted") .. [[]
|
||||||
|
|
||||||
button[7.25,0.15;0.75,0.5;back;X]
|
button[9.25,0.15;0.75,0.5;back;X]
|
||||||
|
button[7.25,-0.07;2,1;receivers;]] .. S("Receivers") .. [[]
|
||||||
|
|
||||||
label[0.2,0.1;]] .. S("From") .. [[: %s]
|
label[0.2,0.1;]] .. S("From") .. [[: %s]
|
||||||
label[0.2,0.5;]] .. S("To") .. [[: %s]
|
label[0.2,0.5;]] .. S("To") .. [[: %s]
|
||||||
label[0.2,0.9;]] .. S("CC") .. [[: %s]
|
label[0.2,0.9;]] .. S("CC") .. [[: %s]
|
||||||
label[0.2,1.3;]] .. S("Date") .. [[: %s]
|
label[0.2,1.3;]] .. S("Date") .. [[: %s]
|
||||||
|
tooltip[0.2,1.3;4.8,0.4;]] .. mail.time_ago(message.time) .. [[]
|
||||||
|
|
||||||
label[0,2.1;]] .. S("Subject") .. [[: %s]
|
label[0,2.1;]] .. S("Subject") .. [[: %s]
|
||||||
textarea[0.25,2.6;8,7.0;;;%s]
|
textarea[0.25,2.6;7.25,8.75;;;%s]
|
||||||
|
|
||||||
button[0,8.5;2,1;reply;]] .. S("Reply") .. [[]
|
button[7.25,1.0;2.75,1;reply;]] .. S("Reply") .. [[]
|
||||||
button[2,8.5;2,1;replyall;]] .. S("Reply all") .. [[]
|
button[7.25,1.8;2.75,1;replyall;]] .. S("Reply all") .. [[]
|
||||||
button[4,8.5;2,1;forward;]] .. S("Forward") .. [[]
|
button[7.25,2.6;2.75,1;forward;]] .. S("Forward") .. [[]
|
||||||
button[6,8.5;2,1;delete;]] .. S("Delete") .. [[]
|
|
||||||
|
button[7.25,3.6;2.75,1;markspam;]] .. S("Mark Spam") .. [[]
|
||||||
|
button[7.25,4.4;2.75,1;unmarkspam;]] .. S("Unmark Spam") .. [[]
|
||||||
|
|
||||||
|
button[7.25,5.4;2.75,1;togglemute;]] .. S("(Un)mute sender") .. [[]
|
||||||
|
|
||||||
|
box[7.25,6.4;2.5,2.75;]] .. mail.get_color("disabled") .. [[]
|
||||||
|
|
||||||
|
button[7.25,9.25;2.75,1;delete;]] .. S("Delete") .. [[]
|
||||||
|
|
||||||
|
tooltip[reply;]] .. S("Reply only to the sender") .. [[]
|
||||||
|
tooltip[replyall;]] .. S("Reply to all involved people") .. [[]
|
||||||
|
tooltip[forward;]] .. S("Transfer message to other people") .. [[]
|
||||||
]] .. mail.theme
|
]] .. mail.theme
|
||||||
|
|
||||||
local from = minetest.formspec_escape(message.from) or ""
|
local from = core.formspec_escape(message.from) or ""
|
||||||
local to = minetest.formspec_escape(message.to) or ""
|
local to = core.formspec_escape(message.to) or ""
|
||||||
local cc = minetest.formspec_escape(message.cc) or ""
|
if string.len(to) > 70 then to = string.sub(to, 1, 67) .. "..." end
|
||||||
|
local cc = core.formspec_escape(message.cc) or ""
|
||||||
|
if string.len(cc) > 50 then cc = string.sub(cc, 1, 47) .. "..." end
|
||||||
local date = type(message.time) == "number"
|
local date = type(message.time) == "number"
|
||||||
and minetest.formspec_escape(os.date("%Y-%m-%d %X", message.time)) or ""
|
and core.formspec_escape(os.date(mail.get_setting(name, "date_format"),
|
||||||
local subject = minetest.formspec_escape(message.subject) or ""
|
message.time+3600*mail.get_setting(name, "timezone_offset"))) or ""
|
||||||
local body = minetest.formspec_escape(message.body) or ""
|
local subject = core.formspec_escape(message.subject) or ""
|
||||||
|
local body = core.formspec_escape(message.body) or ""
|
||||||
formspec = string.format(formspec, from, to, cc, date, subject, body)
|
formspec = string.format(formspec, from, to, cc, date, subject, body)
|
||||||
|
|
||||||
if not message.read then
|
if not message.read and mail.get_setting(name, "auto_marking_read") then
|
||||||
-- mark as read
|
-- mark as read
|
||||||
mail.mark_read(name, id)
|
mail.mark_read(name, id)
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.show_formspec(name, FORMNAME, formspec)
|
core.show_formspec(name, FORMNAME, formspec)
|
||||||
end
|
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
|
if not message then
|
||||||
mail.show_compose(name, message.from, "Re: "..message.subject, replyfooter)
|
-- TODO: workaround for https://github.com/mt-mods/mail/issues/84
|
||||||
|
core.log("error", "[mail] reply called with nil message for player: " .. name)
|
||||||
|
core.log("error", "[mail] current mail-context: " .. dump(mail.selected_idxs))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
mail.show_compose(name, message.from, "Re: "..message.subject, interleave_msg(message.body))
|
||||||
end
|
end
|
||||||
|
|
||||||
function mail.replyall(name, message)
|
function mail.replyall(name, message)
|
||||||
local replyfooter = "Type your reply here.\n\n--Original message follows--\n" ..message.body
|
if not message then
|
||||||
|
-- TODO: workaround for https://github.com/mt-mods/mail/issues/84
|
||||||
|
core.log("error", "[mail] replyall called with nil message for player: " .. name)
|
||||||
|
core.log("error", "[mail] current mail-context: " .. dump(mail.selected_idxs))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- 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 ""
|
||||||
|
@ -76,59 +114,61 @@ function mail.replyall(name, message)
|
||||||
end
|
end
|
||||||
cc = mail.concat_player_list(cc)
|
cc = mail.concat_player_list(cc)
|
||||||
|
|
||||||
mail.show_compose(name, recipients, "Re: "..message.subject, replyfooter, cc)
|
mail.show_compose(name, recipients, "Re: "..message.subject, interleave_msg(message.body), cc)
|
||||||
end
|
end
|
||||||
|
|
||||||
function mail.forward(name, message)
|
function mail.forward(name, message)
|
||||||
local fwfooter = "Type your message here.\n\n--Original message follows--\n" .. (message.body or "")
|
mail.show_compose(name, "", "Fw: " .. (message.subject or ""), interleave_msg(message.body))
|
||||||
mail.show_compose(name, "", "Fw: " .. (message.subject or ""), fwfooter)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
core.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
if formname ~= FORMNAME then
|
if formname ~= FORMNAME then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
|
|
||||||
|
local message = mail.get_message(name, mail.selected_idxs.message[name])
|
||||||
|
|
||||||
if fields.back then
|
if fields.back then
|
||||||
mail.show_mail_menu(name)
|
mail.show_mail_menu(name)
|
||||||
return true -- don't uselessly set messages
|
return true -- don't uselessly set messages
|
||||||
|
|
||||||
elseif fields.reply then
|
elseif fields.reply then
|
||||||
local message = ""
|
|
||||||
if mail.selected_idxs.inbox[name] then
|
|
||||||
message = mail.get_message(name, mail.selected_idxs.inbox[name][#mail.selected_idxs.inbox[name]])
|
|
||||||
elseif mail.selected_idxs.sent[name] then
|
|
||||||
message = mail.get_message(name, mail.selected_idxs.sent[name][#mail.selected_idxs.sent[name]])
|
|
||||||
end
|
|
||||||
mail.reply(name, message)
|
mail.reply(name, message)
|
||||||
|
|
||||||
elseif fields.replyall then
|
elseif fields.replyall then
|
||||||
local message = ""
|
|
||||||
if mail.selected_idxs.inbox[name] then
|
|
||||||
message = mail.get_message(name, mail.selected_idxs.inbox[name][#mail.selected_idxs.inbox[name]])
|
|
||||||
elseif mail.selected_idxs.sent[name] then
|
|
||||||
message = mail.get_message(name, mail.selected_idxs.sent[name][#mail.selected_idxs.sent[name]])
|
|
||||||
end
|
|
||||||
mail.replyall(name, message)
|
mail.replyall(name, message)
|
||||||
|
|
||||||
elseif fields.forward then
|
elseif fields.forward then
|
||||||
local message = ""
|
|
||||||
if mail.selected_idxs.inbox[name] then
|
|
||||||
message = mail.get_message(name, mail.selected_idxs.inbox[name][#mail.selected_idxs.inbox[name]])
|
|
||||||
elseif mail.selected_idxs.sent[name] then
|
|
||||||
message = mail.get_message(name, mail.selected_idxs.sent[name][#mail.selected_idxs.sent[name]])
|
|
||||||
end
|
|
||||||
mail.forward(name, message)
|
mail.forward(name, message)
|
||||||
|
|
||||||
|
elseif fields.markspam then
|
||||||
|
mail.mark_spam(name, message.id)
|
||||||
|
|
||||||
|
elseif fields.unmarkspam then
|
||||||
|
mail.unmark_spam(name, message.id)
|
||||||
|
|
||||||
|
elseif fields.togglemute then
|
||||||
|
local mutes = table.copy(mail.get_setting(name, "mute_list"))
|
||||||
|
local mute_indexof = table.indexof(mutes, message.from)
|
||||||
|
if mute_indexof == -1 then -- mute
|
||||||
|
table.insert(mutes, message.from)
|
||||||
|
else -- unmute
|
||||||
|
table.remove(mutes, mute_indexof)
|
||||||
|
end
|
||||||
|
mail.set_setting(name, "mute_list", mutes)
|
||||||
|
|
||||||
elseif fields.delete then
|
elseif fields.delete then
|
||||||
if mail.selected_idxs.inbox[name] then
|
if mail.get_setting(name, "trash_move_enable") and mail.selected_idxs.boxtab[name] ~= 4 then
|
||||||
mail.delete_mail(name, mail.selected_idxs.inbox[name][#mail.selected_idxs.inbox[name]])
|
mail.trash_mail(name, message.id)
|
||||||
elseif mail.selected_idxs.sent[name] then
|
else
|
||||||
mail.delete_mail(name, mail.selected_idxs.sent[name][#mail.selected_idxs.sent[name]])
|
mail.delete_mail(name, message.id, true)
|
||||||
end
|
end
|
||||||
mail.show_mail_menu(name)
|
mail.show_mail_menu(name)
|
||||||
|
|
||||||
|
elseif fields.receivers then
|
||||||
|
mail.show_receivers(name, message.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
13
ui/options.lua
Normal file
13
ui/options.lua
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
-- helper function for tabbed options
|
||||||
|
|
||||||
|
function mail.show_options(playername)
|
||||||
|
local index = mail.selected_idxs.optionstab[playername] or 1
|
||||||
|
if not mail.selected_idxs.optionstab[playername] then
|
||||||
|
mail.selected_idxs.optionstab[playername] = 1
|
||||||
|
end
|
||||||
|
if index == 1 then
|
||||||
|
mail.show_settings(playername)
|
||||||
|
elseif index == 2 then
|
||||||
|
mail.show_about(playername)
|
||||||
|
end
|
||||||
|
end
|
130
ui/outbox.lua
130
ui/outbox.lua
|
@ -1,15 +1,41 @@
|
||||||
-- translation
|
-- translation
|
||||||
local S = minetest.get_translator("mail")
|
local S = mail.S
|
||||||
|
|
||||||
|
function mail.show_outbox(name, sortfieldindex, sortdirection, filter)
|
||||||
function mail.show_sent(name, sortfieldindex, sortdirection, filter)
|
sortfieldindex = tonumber(sortfieldindex or mail.selected_idxs.sortfield[name])
|
||||||
sortfieldindex = tonumber(sortfieldindex or mail.selected_idxs.sortfield[name]) or 3
|
or mail.get_setting(name, "defaultsortfield") or 3
|
||||||
sortdirection = sortdirection or mail.selected_idxs.sortdirection[name] or "1"
|
sortdirection = tostring(sortdirection or mail.selected_idxs.sortdirection[name]
|
||||||
|
or mail.get_setting(name, "defaultsortdirection") or "1")
|
||||||
filter = filter or mail.selected_idxs.filter[name] or ""
|
filter = filter or mail.selected_idxs.filter[name] or ""
|
||||||
mail.selected_idxs.sent[name] = mail.selected_idxs.sent[name] or {}
|
mail.selected_idxs.outbox[name] = mail.selected_idxs.outbox[name] or {}
|
||||||
|
|
||||||
local sent_formspec = "size[8.5,10;]" .. mail.theme .. [[
|
local entry = mail.get_storage_entry(name)
|
||||||
tabheader[0.3,1;boxtab;]] .. S("Inbox") .. "," .. S("Sent messages").. "," .. S("Drafts") .. [[;2;false;false]
|
local sortfield = ({"to","subject","time"})[sortfieldindex]
|
||||||
|
local messages = mail.sort_messages(entry.outbox, sortfield, sortdirection == "2", filter)
|
||||||
|
|
||||||
|
if mail.selected_idxs.outbox[name] and #mail.selected_idxs.outbox[name] > 0 then
|
||||||
|
for i, selected_msg in ipairs(mail.selected_idxs.outbox[name]) do
|
||||||
|
local is_present = false
|
||||||
|
for _, msg in ipairs(messages) do
|
||||||
|
if msg.id == selected_msg then
|
||||||
|
is_present = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not is_present then
|
||||||
|
table.remove(mail.selected_idxs.outbox[name], i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local trash_tab = ""
|
||||||
|
if mail.get_setting(name, "trash_move_enable") then
|
||||||
|
trash_tab = "," .. S("Trash")
|
||||||
|
end
|
||||||
|
|
||||||
|
local outbox_formspec = "size[8.5,11;]" .. mail.theme .. [[
|
||||||
|
tabheader[0.3,1;boxtab;]] ..
|
||||||
|
S("Inbox") .. "," .. S("Outbox").. "," .. S("Drafts") .. trash_tab .. [[;2;false;false]
|
||||||
|
|
||||||
button[6,0.10;2.5,0.5;new;]] .. S("New") .. [[]
|
button[6,0.10;2.5,0.5;new;]] .. S("New") .. [[]
|
||||||
button[6,0.95;2.5,0.5;read;]] .. S("Read") .. [[]
|
button[6,0.95;2.5,0.5;read;]] .. S("Read") .. [[]
|
||||||
|
@ -17,38 +43,41 @@ function mail.show_sent(name, sortfieldindex, sortdirection, filter)
|
||||||
button[6,2.45;2.5,0.5;replyall;]] .. S("Reply all") .. [[]
|
button[6,2.45;2.5,0.5;replyall;]] .. S("Reply all") .. [[]
|
||||||
button[6,3.20;2.5,0.5;forward;]] .. S("Forward") .. [[]
|
button[6,3.20;2.5,0.5;forward;]] .. S("Forward") .. [[]
|
||||||
button[6,3.95;2.5,0.5;delete;]] .. S("Delete") .. [[]
|
button[6,3.95;2.5,0.5;delete;]] .. S("Delete") .. [[]
|
||||||
button[6,6.8;2.5,0.5;contacts;]] .. S("Contacts") .. [[]
|
button[6,8.0;2.5,0.5;contacts;]] .. S("Contacts") .. [[]
|
||||||
button[6,7.6;2.5,0.5;maillists;]] .. S("Mail lists") .. [[]
|
button[6,8.8;2.5,0.5;maillists;]] .. S("Mail lists") .. [[]
|
||||||
button[6,8.7;2.5,0.5;about;]] .. S("About") .. [[]
|
button[6,9.7;2.5,0.5;options;]] .. S("Options") .. [[]
|
||||||
button_exit[6,9.5;2.5,0.5;quit;]] .. S("Close") .. [[]
|
button_exit[6,10.5;2.5,0.5;quit;]] .. S("Close") .. [[]
|
||||||
|
|
||||||
dropdown[0,8.4;2,0.5;sortfield;]] ..
|
tooltip[reply;]] .. S("Reply only to the sender") .. [[]
|
||||||
|
tooltip[replyall;]] .. S("Reply to all involved people") .. [[]
|
||||||
|
tooltip[forward;]] .. S("Transfer message to other people") .. [[]
|
||||||
|
|
||||||
|
dropdown[0,9.5;2,0.5;sortfield;]] ..
|
||||||
S("To") .. "," .. S("Subject") .. "," .. S("Date") .. [[;]] .. sortfieldindex .. [[;true]
|
S("To") .. "," .. S("Subject") .. "," .. S("Date") .. [[;]] .. sortfieldindex .. [[;true]
|
||||||
dropdown[2.0,8.4;2,0.5;sortdirection;]] ..
|
dropdown[2.0,9.5;2,0.5;sortdirection;]] ..
|
||||||
S("Ascending") .. "," .. S("Descending") .. [[;]] .. sortdirection .. [[;true]
|
S("Ascending") .. "," .. S("Descending") .. [[;]] .. sortdirection .. [[;true]
|
||||||
field[4.25,8.85;1.4,0.5;filter;]] .. S("Filter") .. [[:;]] .. filter .. [[]
|
field[4.25,9.95;1.4,0.5;filter;]] .. S("Filter") .. [[:;]] .. filter .. [[]
|
||||||
button[5.14,8.52;0.85,0.5;search;Q]
|
image_button[5.14,9.5;0.85,0.85;search.png;search;]
|
||||||
|
|
||||||
checkbox[0,9.1;multipleselection;]] .. S("Allow multiple selection") .. [[;]] ..
|
checkbox[0,10.1;multipleselection;]] .. S("Allow multiple selection") .. [[;]] ..
|
||||||
tostring(mail.selected_idxs.multipleselection[name]) .. [[]
|
tostring(mail.selected_idxs.multipleselection[name]) .. [[]
|
||||||
label[0,9.65;]] .. tostring(#mail.selected_idxs.sent[name]) .. " " .. S("selected") .. [[]
|
label[0,10.65;]] ..
|
||||||
button[3.5,9.5;2.5,0.5;selectall;]] .. S("(Un)select all") .. [[]
|
S("@1 of @2 selected", tostring(#mail.selected_idxs.outbox[name]), tostring(#messages)) .. [[]
|
||||||
|
button[3.5,10.5;2.5,0.5;selectall;]] .. S("(Un)select all") .. [[]
|
||||||
|
|
||||||
tablecolumns[color;text;text]
|
tablecolumns[color;text;text]
|
||||||
table[0,0.7;5.75,7.35;sent;#999,]] .. S("To") .. "," .. S("Subject")
|
table[0,0.7;5.75,8.45;outbox;]] .. mail.get_color("header") .. "," .. S("To") .. "," .. S("Subject")
|
||||||
local formspec = { sent_formspec }
|
local formspec = { outbox_formspec }
|
||||||
local entry = mail.get_storage_entry(name)
|
|
||||||
local sortfield = ({"to","subject","time"})[sortfieldindex]
|
|
||||||
local messages = mail.sort_messages(entry.outbox, sortfield, sortdirection == "2", filter)
|
|
||||||
|
|
||||||
mail.message_drafts[name] = nil
|
mail.message_drafts[name] = nil
|
||||||
|
|
||||||
if #messages > 0 then
|
if #messages > 0 then
|
||||||
for _, message in ipairs(messages) do
|
for _, message in ipairs(messages) do
|
||||||
local selected_id = 0
|
local selected_id = 0
|
||||||
|
local displayed_color = {}
|
||||||
-- check if message is in selection list and return its id
|
-- check if message is in selection list and return its id
|
||||||
if mail.selected_idxs.sent[name] and #mail.selected_idxs.sent[name] > 0 then
|
if mail.selected_idxs.outbox[name] and #mail.selected_idxs.outbox[name] > 0 then
|
||||||
for i, selected_msg in ipairs(mail.selected_idxs.sent[name]) do
|
for i, selected_msg in ipairs(mail.selected_idxs.outbox[name]) do
|
||||||
if message.id == selected_msg then
|
if message.id == selected_msg then
|
||||||
selected_id = i
|
selected_id = i
|
||||||
break
|
break
|
||||||
|
@ -56,27 +85,32 @@ function mail.show_sent(name, sortfieldindex, sortdirection, filter)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if selected_id > 0 then
|
if selected_id > 0 then
|
||||||
formspec[#formspec + 1] = ",#466432"
|
table.insert(displayed_color, "selected")
|
||||||
else
|
end
|
||||||
formspec[#formspec + 1] = ","
|
formspec[#formspec + 1] = "," .. mail.get_color(displayed_color)
|
||||||
end
|
formspec[#formspec + 1] = ","
|
||||||
formspec[#formspec + 1] = ","
|
if string.len(message.to) > 20 then
|
||||||
formspec[#formspec + 1] = minetest.formspec_escape(message.to)
|
formspec[#formspec + 1] = core.formspec_escape(string.sub(message.to, 1, 17))
|
||||||
formspec[#formspec + 1] = ","
|
formspec[#formspec + 1] = "..."
|
||||||
if message.subject ~= "" then
|
|
||||||
if string.len(message.subject) > 30 then
|
|
||||||
formspec[#formspec + 1] = minetest.formspec_escape(string.sub(message.subject, 1, 27))
|
|
||||||
formspec[#formspec + 1] = "..."
|
|
||||||
else
|
|
||||||
formspec[#formspec + 1] = minetest.formspec_escape(message.subject)
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
formspec[#formspec + 1] = S("(No subject)")
|
formspec[#formspec + 1] = core.formspec_escape(message.to)
|
||||||
end
|
end
|
||||||
end
|
formspec[#formspec + 1] = ","
|
||||||
formspec[#formspec + 1] = "]"
|
if message.subject ~= "" then
|
||||||
else
|
if string.len(message.subject) > 30 then
|
||||||
formspec[#formspec + 1] = "]label[2.25,4.5;" .. S("No mail") .. "]"
|
formspec[#formspec + 1] = core.formspec_escape(string.sub(message.subject, 1, 27))
|
||||||
end
|
formspec[#formspec + 1] = "..."
|
||||||
minetest.show_formspec(name, "mail:sent", table.concat(formspec, ""))
|
else
|
||||||
|
formspec[#formspec + 1] = core.formspec_escape(message.subject)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
formspec[#formspec + 1] = S("(No subject)")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
formspec[#formspec + 1] = "]"
|
||||||
|
else
|
||||||
|
formspec[#formspec + 1] = "]label[2.25,4.5;" .. S("No mail") .. "]"
|
||||||
|
end
|
||||||
|
|
||||||
|
core.show_formspec(name, "mail:outbox", table.concat(formspec, ""))
|
||||||
end
|
end
|
||||||
|
|
54
ui/receivers.lua
Normal file
54
ui/receivers.lua
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
-- translation
|
||||||
|
local S = core.get_translator("mail")
|
||||||
|
|
||||||
|
local FORMNAME = "mail:receivers"
|
||||||
|
|
||||||
|
function mail.show_receivers(name, id)
|
||||||
|
local message = mail.get_message(name, id)
|
||||||
|
|
||||||
|
local formspec = [[
|
||||||
|
size[8,6]
|
||||||
|
|
||||||
|
box[0,0;7,1.1;]] .. mail.get_color("highlighted") .. [[]
|
||||||
|
|
||||||
|
button[7.25,0.15;0.75,0.5;back;X]
|
||||||
|
|
||||||
|
label[0.2,0.1;]] .. S("From") .. [[: %s]
|
||||||
|
label[0.2,0.5;]] .. S("Date") .. [[: %s]
|
||||||
|
|
||||||
|
tablecolumns[color;text]
|
||||||
|
table[0,1.5;3.8,4.5;to;%s]
|
||||||
|
|
||||||
|
tablecolumns[color;text]
|
||||||
|
table[4,1.5;3.8,4.5;cc;%s]
|
||||||
|
]] .. mail.theme
|
||||||
|
|
||||||
|
local from = core.formspec_escape(message.from) or ""
|
||||||
|
local to = mail.parse_player_list(message.to or "")
|
||||||
|
local to_str = mail.get_color("header") .. "," .. S("To") .. ",,"
|
||||||
|
to_str = to_str .. table.concat(to, ",,")
|
||||||
|
local cc = mail.parse_player_list(message.cc or "")
|
||||||
|
local cc_str = mail.get_color("header") .. "," .. S("CC") .. ",,"
|
||||||
|
cc_str = cc_str .. table.concat(cc, ",,")
|
||||||
|
local date = type(message.time) == "number"
|
||||||
|
and core.formspec_escape(os.date(mail.get_setting(name, "date_format"), message.time)) or ""
|
||||||
|
formspec = string.format(formspec, from, date, to_str, cc_str)
|
||||||
|
|
||||||
|
core.show_formspec(name, FORMNAME, formspec)
|
||||||
|
end
|
||||||
|
|
||||||
|
core.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
|
if formname ~= FORMNAME then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local name = player:get_player_name()
|
||||||
|
|
||||||
|
local message_id = mail.selected_idxs.message[name]
|
||||||
|
|
||||||
|
if fields.back then
|
||||||
|
mail.show_message(name, message_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end)
|
|
@ -1,19 +1,19 @@
|
||||||
-- translation
|
-- translation
|
||||||
local S = minetest.get_translator("mail")
|
local S = mail.S
|
||||||
|
|
||||||
local FORMNAME = "mail:selectcontact"
|
local FORMNAME = "mail:selectcontact"
|
||||||
|
|
||||||
local select_contact_formspec = "size[8,9;]" .. mail.theme .. [[
|
local select_contact_formspec = "size[8,9;]" .. mail.theme .. [[
|
||||||
tablecolumns[color;text;text]
|
tablecolumns[color;text;text]
|
||||||
table[0,0;3.5,9;contacts;#999,]] .. S("Name") .. "," .. S("Note") .. [[%s]
|
table[0,0;3.5,9;contacts;]] .. mail.get_color("header") .. "," .. S("Name") .. "," .. S("Note") .. [[%s]
|
||||||
button[3.55,2.00;1.75,0.5;toadd;→ ]] .. S("Add") .. [[]
|
button[3.55,2.00;1.75,0.5;toadd;→ ]] .. S("Add") .. [[]
|
||||||
button[3.55,2.75;1.75,0.5;toremove;← ]] .. S("Remove") .. [[]
|
button[3.55,2.75;1.75,0.5;toremove;← ]] .. S("Remove") .. [[]
|
||||||
button[3.55,6.00;1.75,0.5;ccadd;→ ]] .. S("Add") .. [[]
|
button[3.55,6.00;1.75,0.5;ccadd;→ ]] .. S("Add") .. [[]
|
||||||
button[3.55,6.75;1.75,0.5;ccremove;← ]] .. S("Remove") .. [[]
|
button[3.55,6.75;1.75,0.5;ccremove;← ]] .. S("Remove") .. [[]
|
||||||
tablecolumns[color;text;text]
|
tablecolumns[color;text;text]
|
||||||
table[5.15,0.0;2.75,4.5;to;#999,]] .. S("To") .. ":," .. S("Note") .. [[%s]
|
table[5.15,0.0;2.75,4.5;to;]] .. mail.get_color("header") .. "," .. S("To") .. ":," .. S("Note") .. [[%s]
|
||||||
tablecolumns[color;text;text]
|
tablecolumns[color;text;text]
|
||||||
table[5.15,4.6;2.75,4.5;cc;#999,]] .. S("CC") .. ":," .. S("Note") .. [[%s]
|
table[5.15,4.6;2.75,4.5;cc;]] .. mail.get_color("header") .. "," .. S("CC") .. ":," .. S("Note") .. [[%s]
|
||||||
button[3.55,8.25;1.75,0.5;back;]] .. S("Back") .. [[]
|
button[3.55,8.25;1.75,0.5;back;]] .. S("Back") .. [[]
|
||||||
]]
|
]]
|
||||||
|
|
||||||
|
@ -39,10 +39,10 @@ function mail.show_select_contact(name, to, cc)
|
||||||
bcc = ""
|
bcc = ""
|
||||||
end]]--
|
end]]--
|
||||||
formspec = string.format(formspec, contacts, to, cc)--, bcc()
|
formspec = string.format(formspec, contacts, to, cc)--, bcc()
|
||||||
minetest.show_formspec(name, FORMNAME, formspec)
|
core.show_formspec(name, FORMNAME, formspec)
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
core.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
if formname ~= FORMNAME then
|
if formname ~= FORMNAME then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -60,7 +60,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
bcc = "bccremove"
|
bcc = "bccremove"
|
||||||
}) do
|
}) do
|
||||||
if fields[k] then
|
if fields[k] then
|
||||||
local evt = minetest.explode_table_event(fields[k])
|
local evt = core.explode_table_event(fields[k])
|
||||||
mail.selected_idxs[k][name] = evt.row - 1
|
mail.selected_idxs[k][name] = evt.row - 1
|
||||||
if evt.type == "DCL" and mail.selected_idxs[k][name] then
|
if evt.type == "DCL" and mail.selected_idxs[k][name] then
|
||||||
fields[action] = true
|
fields[action] = true
|
||||||
|
@ -75,7 +75,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
if fields[v.."add"] then
|
if fields[v.."add"] then
|
||||||
update = true
|
update = true
|
||||||
if mail.selected_idxs.contacts[name] then
|
if mail.selected_idxs.contacts[name] then
|
||||||
for k, contact, i in mail.pairsByKeys(contacts) do
|
for k, contact, i in mail.pairs_by_keys(contacts) do
|
||||||
if k == mail.selected_idxs.contacts[name] or i == mail.selected_idxs.contacts[name] then
|
if k == mail.selected_idxs.contacts[name] or i == mail.selected_idxs.contacts[name] then
|
||||||
local list = mail.parse_player_list(draft[v])
|
local list = mail.parse_player_list(draft[v])
|
||||||
list[#list+1] = contact.name
|
list[#list+1] = contact.name
|
||||||
|
|
264
ui/settings.lua
Normal file
264
ui/settings.lua
Normal file
|
@ -0,0 +1,264 @@
|
||||||
|
-- translation
|
||||||
|
local S = mail.S
|
||||||
|
|
||||||
|
local FORMNAME = "mail:settings"
|
||||||
|
|
||||||
|
local function get_settings_groups(parent)
|
||||||
|
-- generate ordered list of settings
|
||||||
|
local groups = {}
|
||||||
|
for _, g in ipairs(mail.settings_groups) do
|
||||||
|
if (g.parent or 0) == parent then
|
||||||
|
table.insert(groups, g)
|
||||||
|
-- insert sub groups just after the parent group
|
||||||
|
table.insert_all(groups, get_settings_groups(g.name))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return groups
|
||||||
|
end
|
||||||
|
|
||||||
|
local groups_labels = {}
|
||||||
|
local ordered_groups = get_settings_groups(0)
|
||||||
|
local tree_indent = 0
|
||||||
|
for i, g in ipairs(ordered_groups) do
|
||||||
|
if not g.parent then tree_indent = 0
|
||||||
|
elseif i > 1 and g.parent == ordered_groups[i-1].name then tree_indent = tree_indent + 1
|
||||||
|
elseif i > 1 and g.parent ~= ordered_groups[i-1].parent then tree_indent = tree_indent - 1
|
||||||
|
end
|
||||||
|
table.insert(groups_labels, tostring(tree_indent))
|
||||||
|
table.insert(groups_labels, g.label)
|
||||||
|
end
|
||||||
|
local groups_str = table.concat(groups_labels, ",")
|
||||||
|
|
||||||
|
function mail.show_settings(name)
|
||||||
|
local group_index = 1
|
||||||
|
mail.selected_idxs.settings_group[name] = mail.selected_idxs.settings_group[name] or mail.settings_groups[1].name
|
||||||
|
|
||||||
|
for i, g in ipairs(ordered_groups) do
|
||||||
|
if g.name == mail.selected_idxs.settings_group[name] then
|
||||||
|
group_index = i
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local formspec = [[
|
||||||
|
size[10,6;]
|
||||||
|
tabheader[0,0;optionstab;]] .. S("Settings") .. "," .. S("About") .. [[;1;false;false]
|
||||||
|
button[9.35,0;0.75,0.5;back;X]
|
||||||
|
|
||||||
|
tablecolumns[tree;text]
|
||||||
|
table[0,0.775;3,4.5;groups;]] .. groups_str .. [[;]] .. group_index .. [[]
|
||||||
|
|
||||||
|
box[0,0;3,0.45;]] .. mail.get_color("highlighted") .. [[]
|
||||||
|
label[0.2,0;]] .. mail.settings_groups[group_index].label .. [[]
|
||||||
|
|
||||||
|
button[0,5.65;2.5,0.5;reset;]] .. S("Reset") .. [[]
|
||||||
|
button[7.5,5.65;2.5,0.5;save;]] .. S("Save") .. [[]
|
||||||
|
]]
|
||||||
|
|
||||||
|
local x = 3.5
|
||||||
|
local y = -0.7
|
||||||
|
-- put settings in order
|
||||||
|
local ordered_settings = {}
|
||||||
|
for setting, data in pairs(mail.settings) do
|
||||||
|
if data.group == mail.selected_idxs.settings_group[name] then
|
||||||
|
table.insert(ordered_settings, setting)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.sort(ordered_settings, function(a, b) return mail.settings[a].index < mail.settings[b].index end)
|
||||||
|
for _, setting in pairs(ordered_settings) do
|
||||||
|
local data = mail.settings[setting]
|
||||||
|
y = y + 0.4
|
||||||
|
local field_default = mail.selected_idxs[setting][name]
|
||||||
|
if field_default == nil then field_default = mail.get_setting(name, setting) end
|
||||||
|
if data.type == "bool" then
|
||||||
|
formspec = formspec .. [[
|
||||||
|
checkbox[]] .. x .. "," .. y .. ";" .. setting .. ";" ..
|
||||||
|
data.label .. ";" .. tostring(field_default) .. [[]
|
||||||
|
]]
|
||||||
|
if data.tooltip then
|
||||||
|
formspec = formspec .. [[
|
||||||
|
tooltip[]] .. setting .. ";" .. data.tooltip .. [[]
|
||||||
|
]]
|
||||||
|
end
|
||||||
|
elseif data.type == "string" then
|
||||||
|
y = y + 1
|
||||||
|
formspec = formspec .. [[
|
||||||
|
field[]] .. x+0.275 .. "," .. y .. ";3,0.5;" .. setting .. ";" .. data.label .. [[;]] ..
|
||||||
|
field_default .. [[]
|
||||||
|
]]
|
||||||
|
if data.tooltip then
|
||||||
|
formspec = formspec .. "tooltip[" .. setting .. ";" .. data.tooltip .. "]"
|
||||||
|
end
|
||||||
|
if data.dataset then
|
||||||
|
local formatted_dataset = table.copy(data.dataset)
|
||||||
|
if data.format then
|
||||||
|
for i, d in ipairs(formatted_dataset) do
|
||||||
|
formatted_dataset[i] = data.format(d)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local dataset_str = table.concat(formatted_dataset, ",")
|
||||||
|
local dataset_selected_id = 1
|
||||||
|
for i, d in ipairs(data.dataset) do
|
||||||
|
if d == field_default then
|
||||||
|
dataset_selected_id = i
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
formspec = formspec .. [[
|
||||||
|
dropdown[]] .. x+3 .. "," .. y-0.45 .. ";3,0.5;" .. "dataset_" .. setting .. ";" ..
|
||||||
|
dataset_str .. [[;]] .. dataset_selected_id .. [[;true]
|
||||||
|
]]
|
||||||
|
end
|
||||||
|
elseif data.type == "number" then
|
||||||
|
y = y + 1
|
||||||
|
formspec = formspec .. [[
|
||||||
|
field[]] .. x+0.275 .. "," .. y .. ";3,0.5;" .. setting .. ";" .. data.label .. [[;]] ..
|
||||||
|
tostring(field_default) .. [[]
|
||||||
|
]]
|
||||||
|
if data.tooltip then
|
||||||
|
formspec = formspec .. "tooltip[" .. setting .. ";" .. data.tooltip .. "]"
|
||||||
|
end
|
||||||
|
if data.dataset then
|
||||||
|
local formatted_dataset = table.copy(data.dataset)
|
||||||
|
if data.format then
|
||||||
|
for i, d in ipairs(formatted_dataset) do
|
||||||
|
formatted_dataset[i] = data.format(d)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local dataset_str = table.concat(formatted_dataset, ",")
|
||||||
|
local dataset_selected_id = 1
|
||||||
|
for i, d in ipairs(data.dataset) do
|
||||||
|
if d == field_default then
|
||||||
|
dataset_selected_id = i
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
formspec = formspec .. [[
|
||||||
|
dropdown[]] .. x+3 .. "," .. y-0.45 .. ";3,0.5;" .. "dataset_" .. setting .. ";" ..
|
||||||
|
dataset_str .. [[;]] .. dataset_selected_id .. [[;true]
|
||||||
|
]]
|
||||||
|
end
|
||||||
|
elseif data.type == "index" then
|
||||||
|
y = y + 0.2
|
||||||
|
local formatted_dataset = table.copy(data.dataset)
|
||||||
|
if data.format then
|
||||||
|
for i, d in ipairs(formatted_dataset) do
|
||||||
|
formatted_dataset[i] = data.format(d)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local dataset_str = table.concat(formatted_dataset, ",")
|
||||||
|
local dataset_selected_id = field_default
|
||||||
|
formspec = formspec .. [[
|
||||||
|
label[]] .. x .. "," .. y .. ";" .. data.label .. "]"
|
||||||
|
y = y + 0.4
|
||||||
|
formspec = formspec .. [[
|
||||||
|
dropdown[]] .. x .. "," .. y .. ";3,0.5;" .. setting .. ";" ..
|
||||||
|
dataset_str .. [[;]] .. dataset_selected_id .. [[;true]
|
||||||
|
]]
|
||||||
|
if data.tooltip then
|
||||||
|
formspec = formspec .. [[
|
||||||
|
tooltip[]] .. setting .. ";" .. data.tooltip .. [[]
|
||||||
|
]]
|
||||||
|
end
|
||||||
|
y = y + 0.2
|
||||||
|
elseif data.type == "list" then
|
||||||
|
y = y + 0.3
|
||||||
|
formspec = formspec .. [[
|
||||||
|
tablecolumns[color;text]
|
||||||
|
table[]] .. x-0.0125 .. "," .. y .. ";3.8125,2.5;" .. setting .. ";" ..
|
||||||
|
mail.get_color("header") .. "," .. data.label .. ",," ..
|
||||||
|
table.concat(field_default, ",,") .. "]"
|
||||||
|
|
||||||
|
y = y + 3.1
|
||||||
|
formspec = formspec .. [[
|
||||||
|
field[]] .. x+0.275 .. "," .. y .. ";2.975,0.5;field_" .. setting .. [[;;]
|
||||||
|
button[]] .. x+2.75 .. "," .. y-0.325 .. ";0.75,0.5;add_" .. setting .. [[;+]
|
||||||
|
button[]] .. x+3.25 .. "," .. y-0.325 .. ";0.75,0.5;remove_" .. setting .. [[;-]
|
||||||
|
]]
|
||||||
|
|
||||||
|
if data.tooltip then
|
||||||
|
formspec = formspec .. "tooltip[field_" .. setting .. ";" .. data.tooltip .. "]"
|
||||||
|
end
|
||||||
|
|
||||||
|
y = y - 0.4
|
||||||
|
end
|
||||||
|
end
|
||||||
|
formspec = formspec .. mail.theme
|
||||||
|
core.show_formspec(name, FORMNAME, formspec)
|
||||||
|
end
|
||||||
|
|
||||||
|
core.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
|
if formname ~= FORMNAME then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local playername = player:get_player_name()
|
||||||
|
|
||||||
|
for setting, data in pairs(mail.settings) do
|
||||||
|
if fields[setting] or fields["add_" .. setting] or fields["remove_" .. setting] then
|
||||||
|
if data.type == "bool" then
|
||||||
|
mail.selected_idxs[setting][playername] = fields[setting] == "true"
|
||||||
|
break
|
||||||
|
elseif data.type == "string" then
|
||||||
|
if data.dataset and fields["dataset_" .. setting] then
|
||||||
|
mail.selected_idxs[setting][playername] = data.dataset[tonumber(fields["dataset_" .. setting])]
|
||||||
|
mail.show_settings(playername)
|
||||||
|
end
|
||||||
|
elseif data.type == "number" then
|
||||||
|
if data.dataset and fields["dataset_" .. setting] then
|
||||||
|
mail.selected_idxs[setting][playername] = data.dataset[tonumber(fields["dataset_" .. setting])]
|
||||||
|
mail.show_settings(playername)
|
||||||
|
end
|
||||||
|
elseif data.type == "index" then
|
||||||
|
mail.selected_idxs[setting][playername] = tonumber(fields[setting])
|
||||||
|
elseif data.type == "list" then
|
||||||
|
mail.selected_idxs[setting][playername] = mail.selected_idxs[setting][playername] or
|
||||||
|
mail.get_setting(playername, setting)
|
||||||
|
if fields[setting] then
|
||||||
|
local evt = core.explode_table_event(fields[setting])
|
||||||
|
mail.selected_idxs["index_" .. setting][playername] = evt.row-1
|
||||||
|
elseif fields["add_" .. setting] then
|
||||||
|
table.insert(mail.selected_idxs[setting][playername], fields["field_" .. setting])
|
||||||
|
elseif fields["remove_" .. setting] and mail.selected_idxs["index_" .. setting][playername] then
|
||||||
|
table.remove(mail.selected_idxs[setting][playername],
|
||||||
|
mail.selected_idxs["index_" .. setting][playername])
|
||||||
|
end
|
||||||
|
mail.show_settings(playername)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if fields.back then
|
||||||
|
mail.show_mail_menu(playername)
|
||||||
|
return
|
||||||
|
|
||||||
|
elseif fields.groups then
|
||||||
|
local evt = core.explode_table_event(fields.groups)
|
||||||
|
mail.selected_idxs.settings_group[playername] = mail.settings_groups[tonumber(evt.row)].name
|
||||||
|
mail.show_settings(playername)
|
||||||
|
elseif fields.optionstab == "1" then
|
||||||
|
mail.selected_idxs.optionstab[playername] = 1
|
||||||
|
|
||||||
|
elseif fields.optionstab == "2" then
|
||||||
|
mail.selected_idxs.optionstab[playername] = 2
|
||||||
|
mail.show_about(playername)
|
||||||
|
return
|
||||||
|
|
||||||
|
elseif fields.save then
|
||||||
|
-- save settings
|
||||||
|
for setting, _ in pairs(mail.settings) do
|
||||||
|
local new_value = mail.selected_idxs[setting][playername]
|
||||||
|
mail.selected_idxs[setting][playername] = nil
|
||||||
|
if new_value == nil then new_value = mail.get_setting(playername, setting) end
|
||||||
|
mail.set_setting(playername, setting, new_value)
|
||||||
|
end
|
||||||
|
-- update visuals
|
||||||
|
mail.hud_update(playername, mail.get_storage_entry(playername).inbox)
|
||||||
|
mail.show_settings(playername)
|
||||||
|
|
||||||
|
elseif fields.reset then
|
||||||
|
mail.reset_settings(playername)
|
||||||
|
mail.show_settings(playername)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end)
|
53
ui/trash.lua
Normal file
53
ui/trash.lua
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
-- translation
|
||||||
|
local S = mail.S
|
||||||
|
|
||||||
|
local trash_formspec = "size[8.5,11;]" .. mail.theme .. [[
|
||||||
|
tabheader[0.3,1;boxtab;]] ..
|
||||||
|
S("Inbox") .. "," .. S("Outbox").. "," .. S("Drafts") .. "," .. S("Trash") .. [[;4;false;false]
|
||||||
|
|
||||||
|
button[6,0.10;2.5,0.5;new;]] .. S("New") .. [[]
|
||||||
|
button[6,0.95;2.5,0.5;read;]] .. S("Read") .. [[]
|
||||||
|
button[6,1.70;2.5,0.5;restore;]] .. S("Restore") .. [[]
|
||||||
|
button[6,2.45;2.5,0.5;delete;]] .. S("Delete") .. [[]
|
||||||
|
button[6,3.20;2.5,0.5;empty;]] .. S("Empty") .. [[]
|
||||||
|
button[6,8.0;2.5,0.5;contacts;]] .. S("Contacts") .. [[]
|
||||||
|
button[6,8.8;2.5,0.5;maillists;]] .. S("Mail lists") .. [[]
|
||||||
|
button[6,9.7;2.5,0.5;options;]] .. S("Options") .. [[]
|
||||||
|
button_exit[6,10.5;2.5,0.5;quit;]] .. S("Close") .. [[]
|
||||||
|
|
||||||
|
tablecolumns[color;text;text]
|
||||||
|
table[0,0.7;5.75,10.35;trash;]] .. mail.get_color("header") .. "," .. S("From/To") .. "," .. S("Subject")
|
||||||
|
|
||||||
|
|
||||||
|
function mail.show_trash(name)
|
||||||
|
local formspec = { trash_formspec }
|
||||||
|
local entry = mail.get_storage_entry(name)
|
||||||
|
local messages = entry.trash
|
||||||
|
|
||||||
|
if messages[1] then
|
||||||
|
for _, message in ipairs(messages) do
|
||||||
|
formspec[#formspec + 1] = ","
|
||||||
|
formspec[#formspec + 1] = ","
|
||||||
|
formspec[#formspec + 1] = core.formspec_escape(message.to)
|
||||||
|
formspec[#formspec + 1] = ","
|
||||||
|
if message.subject ~= "" then
|
||||||
|
if string.len(message.subject) > 30 then
|
||||||
|
formspec[#formspec + 1] = core.formspec_escape(string.sub(message.subject, 1, 27))
|
||||||
|
formspec[#formspec + 1] = "..."
|
||||||
|
else
|
||||||
|
formspec[#formspec + 1] = core.formspec_escape(message.subject)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
formspec[#formspec + 1] = S("(No subject)")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if mail.selected_idxs.trash[name] then
|
||||||
|
formspec[#formspec + 1] = ";"
|
||||||
|
formspec[#formspec + 1] = tostring(mail.selected_idxs.trash[name] + 1)
|
||||||
|
end
|
||||||
|
formspec[#formspec + 1] = "]"
|
||||||
|
else
|
||||||
|
formspec[#formspec + 1] = "]label[2.25,4.5;" .. S("Trash is empty") .. "]"
|
||||||
|
end
|
||||||
|
core.show_formspec(name, "mail:trash", table.concat(formspec, ""))
|
||||||
|
end
|
58
util/colors.lua
Normal file
58
util/colors.lua
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
local generic_colors = {
|
||||||
|
header = "#999999",
|
||||||
|
selected = "#72FF63",
|
||||||
|
important = "#FFD700",
|
||||||
|
additional = "#CCCCDD",
|
||||||
|
highlighted = "#608631",
|
||||||
|
new = "#00F529",
|
||||||
|
warning = "#FF8800",
|
||||||
|
disabled = "#332222",
|
||||||
|
muted = "#CCCCCC",
|
||||||
|
}
|
||||||
|
|
||||||
|
local function get_base_color(c)
|
||||||
|
return generic_colors[c] or ""
|
||||||
|
end
|
||||||
|
|
||||||
|
local function hex2rgb(hex)
|
||||||
|
hex = hex:gsub("#","")
|
||||||
|
return {
|
||||||
|
r = tonumber("0x" .. hex:sub(1,2)),
|
||||||
|
g = tonumber("0x" .. hex:sub(3,4)),
|
||||||
|
b = tonumber("0x" .. hex:sub(5,6))
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function rgb2hex(rgb)
|
||||||
|
return "#" .. string.format("%x", rgb.r) .. string.format("%x", rgb.g) .. string.format("%x", rgb.b)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function rgb_colors_mix(colors)
|
||||||
|
local R = 0
|
||||||
|
local G = 0
|
||||||
|
local B = 0
|
||||||
|
for _, c in ipairs(colors) do
|
||||||
|
R = R + c.r
|
||||||
|
G = G + c.g
|
||||||
|
B = B + c.b
|
||||||
|
end
|
||||||
|
R = math.floor(R / #colors + 0.5)
|
||||||
|
G = math.floor(G / #colors + 0.5)
|
||||||
|
B = math.floor(B / #colors + 0.5)
|
||||||
|
return {r=R,g=G,b=B}
|
||||||
|
end
|
||||||
|
|
||||||
|
function mail.get_color(mix)
|
||||||
|
if type(mix) == "string" then
|
||||||
|
return get_base_color(mix)
|
||||||
|
elseif #mix == 1 then
|
||||||
|
return get_base_color(mix[1])
|
||||||
|
else
|
||||||
|
local colors2mix = {}
|
||||||
|
for _, c in ipairs(mix) do
|
||||||
|
colors2mix[#colors2mix+1] = hex2rgb(get_base_color(c))
|
||||||
|
end
|
||||||
|
local mixed_color = rgb_colors_mix(colors2mix)
|
||||||
|
return rgb2hex(mixed_color)
|
||||||
|
end
|
||||||
|
end
|
75
util/contact.lua
Normal file
75
util/contact.lua
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
-- translation
|
||||||
|
local S = mail.S
|
||||||
|
|
||||||
|
function mail.compile_contact_list(name, selected, playernames)
|
||||||
|
-- TODO: refactor this - not just compiles *a* list, but *the* list for the contacts screen (too inflexible)
|
||||||
|
local formspec = {}
|
||||||
|
local contacts = mail.get_contacts(name)
|
||||||
|
|
||||||
|
if playernames == nil then
|
||||||
|
local length = 0
|
||||||
|
for k, contact, i, l in mail.pairs_by_keys(contacts) do
|
||||||
|
if i == 1 then length = l end
|
||||||
|
formspec[#formspec + 1] = ","
|
||||||
|
formspec[#formspec + 1] = ","
|
||||||
|
formspec[#formspec + 1] = core.formspec_escape(contact.name)
|
||||||
|
formspec[#formspec + 1] = ","
|
||||||
|
local note = contact.note
|
||||||
|
-- display an ellipsis if the note spans multiple lines
|
||||||
|
local idx = string.find(note, '\n')
|
||||||
|
if idx ~= nil then
|
||||||
|
note = string.sub(note, 1, idx-1) .. ' ...'
|
||||||
|
end
|
||||||
|
formspec[#formspec + 1] = core.formspec_escape(note)
|
||||||
|
if type(selected) == "string" then
|
||||||
|
if string.lower(selected) == k then
|
||||||
|
selected = i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if length > 0 then
|
||||||
|
if selected and type(selected) == "number" then
|
||||||
|
formspec[#formspec + 1] = ";"
|
||||||
|
formspec[#formspec + 1] = tostring(selected + 1)
|
||||||
|
end
|
||||||
|
formspec[#formspec + 1] = "]"
|
||||||
|
else
|
||||||
|
formspec[#formspec + 1] = "]label[2,4.5;" .. S("No contacts") .. "]"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if type(playernames) == "string" then
|
||||||
|
playernames = mail.parse_player_list(playernames)
|
||||||
|
end
|
||||||
|
for i,c in ipairs(playernames) do
|
||||||
|
formspec[#formspec + 1] = ","
|
||||||
|
formspec[#formspec + 1] = ","
|
||||||
|
formspec[#formspec + 1] = core.formspec_escape(c)
|
||||||
|
formspec[#formspec + 1] = ","
|
||||||
|
if contacts[string.lower(c)] == nil then
|
||||||
|
formspec[#formspec + 1] = ""
|
||||||
|
else
|
||||||
|
local note = contacts[string.lower(c)].note
|
||||||
|
-- display an ellipsis if the note spans multiple lines
|
||||||
|
local idx = string.find(note, '\n')
|
||||||
|
if idx ~= nil then
|
||||||
|
note = string.sub(note, 1, idx-1) .. ' ...'
|
||||||
|
end
|
||||||
|
formspec[#formspec + 1] = core.formspec_escape(note)
|
||||||
|
end
|
||||||
|
if not selected then
|
||||||
|
if type(selected) == "string" then
|
||||||
|
if string.lower(selected) == string.lower(c) then
|
||||||
|
selected = i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #playernames > 0 and selected and type(selected) == "number" then
|
||||||
|
formspec[#formspec + 1] = ";"
|
||||||
|
formspec[#formspec + 1] = tostring(selected + 1)
|
||||||
|
end
|
||||||
|
formspec[#formspec + 1] = "]"
|
||||||
|
end
|
||||||
|
return table.concat(formspec, "")
|
||||||
|
|
||||||
|
end
|
9
util/init.lua
Normal file
9
util/init.lua
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
-- sub files
|
||||||
|
local MP = core.get_modpath(core.get_current_modname())
|
||||||
|
dofile(MP .. "/util/normalize.lua")
|
||||||
|
dofile(MP .. "/util/colors.lua")
|
||||||
|
dofile(MP .. "/util/contact.lua")
|
||||||
|
dofile(MP .. "/util/settings.lua")
|
||||||
|
dofile(MP .. "/util/spam.lua")
|
||||||
|
dofile(MP .. "/util/time_ago.lua")
|
||||||
|
dofile(MP .. "/util/uuid.lua")
|
|
@ -1,18 +1,44 @@
|
||||||
local has_canonical_name = minetest.get_modpath("canonical_name")
|
-- translation
|
||||||
|
local S = mail.S
|
||||||
|
|
||||||
|
local function recursive_expand_recipient_names(sender, list, is_toplevel, recipients, undeliverable)
|
||||||
|
for _, name in ipairs(list) do
|
||||||
|
if not (recipients[name] or undeliverable[name] or (name == sender and not is_toplevel)) then
|
||||||
|
local succ, value
|
||||||
|
for _, handler in ipairs(mail.registered_recipient_handlers) do
|
||||||
|
succ, value = handler(sender, name)
|
||||||
|
if succ ~= nil then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local vtp = type(value)
|
||||||
|
if succ then
|
||||||
|
if vtp == "string" then
|
||||||
|
recursive_expand_recipient_names(sender, {value}, is_toplevel, recipients, undeliverable)
|
||||||
|
elseif vtp == "table" then
|
||||||
|
recursive_expand_recipient_names(sender, value, false, recipients, undeliverable)
|
||||||
|
elseif vtp == "function" then
|
||||||
|
recipients[name] = value
|
||||||
|
else
|
||||||
|
undeliverable[name] = S("The method of delivery to @1 is invalid.", name)
|
||||||
|
end
|
||||||
|
elseif succ == nil then
|
||||||
|
undeliverable[name] = S("The recipient @1 could not be identified.", name)
|
||||||
|
else
|
||||||
|
local reason = tostring(value) or S("@1 rejected your mail.", name)
|
||||||
|
undeliverable[name] = reason
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
return the field normalized (comma separated, single space)
|
return the field normalized (comma separated, single space)
|
||||||
and add individual player names to recipient list
|
and add individual player names to recipient list
|
||||||
--]]
|
--]]
|
||||||
function mail.normalize_players_and_add_recipients(field, recipients, undeliverable)
|
function mail.normalize_players_and_add_recipients(sender, field, recipients, undeliverable)
|
||||||
local order = mail.parse_player_list(field)
|
local order = mail.parse_player_list(field)
|
||||||
for _, recipient_name in ipairs(order) do
|
recursive_expand_recipient_names(sender, order, true, recipients, undeliverable)
|
||||||
if not minetest.player_exists(recipient_name) then
|
|
||||||
undeliverable[recipient_name] = true
|
|
||||||
else
|
|
||||||
recipients[recipient_name] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return mail.concat_player_list(order)
|
return mail.concat_player_list(order)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -21,29 +47,23 @@ function mail.parse_player_list(field)
|
||||||
return {}
|
return {}
|
||||||
end
|
end
|
||||||
|
|
||||||
local separator = ", "
|
local separator = ",%s"
|
||||||
local pattern = "([^" .. separator .. "]+)"
|
local pattern = "([^" .. separator .. "]+)"
|
||||||
|
|
||||||
-- get individual players
|
-- get individual players
|
||||||
local player_set = {}
|
|
||||||
local order = {}
|
local order = {}
|
||||||
field:gsub(pattern, function(player_name)
|
for name in field:gmatch(pattern) do
|
||||||
local lower = string.lower(player_name)
|
table.insert(order, name)
|
||||||
if not player_set[lower] then
|
end
|
||||||
if has_canonical_name then
|
|
||||||
player_name = canonical_name.get(player_name) or player_name
|
|
||||||
end
|
|
||||||
|
|
||||||
player_set[lower] = player_name
|
|
||||||
order[#order+1] = player_name
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
return order
|
return order
|
||||||
end
|
end
|
||||||
|
|
||||||
function mail.concat_player_list(order)
|
function mail.concat_player_list(order)
|
||||||
-- turn list of players back into normalized string
|
-- turn list of players back into normalized string
|
||||||
|
if order == nil or #order == 0 then
|
||||||
|
return ""
|
||||||
|
end
|
||||||
return table.concat(order, ", ")
|
return table.concat(order, ", ")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
mtt.register("util/normalize_players_and_add_recipients", function(callback)
|
mtt.register("util/normalize_players_and_add_recipients", function(callback)
|
||||||
local recipients = {}
|
local recipients = {}
|
||||||
local undeliverable = {}
|
local undeliverable = {}
|
||||||
local to = mail.normalize_players_and_add_recipients("player1,player2", recipients, undeliverable)
|
local to = mail.normalize_players_and_add_recipients("sender", "player1,player2", recipients, undeliverable)
|
||||||
|
|
||||||
assert(to == "player1, player2")
|
assert(to == "player1, player2")
|
||||||
assert(not next(undeliverable))
|
assert(not next(undeliverable))
|
||||||
assert(recipients["player1"])
|
assert(recipients["player1"])
|
||||||
assert(recipients["player2"])
|
assert(recipients["player2"])
|
||||||
callback()
|
callback()
|
||||||
end)
|
end)
|
||||||
|
|
113
util/settings.lua
Normal file
113
util/settings.lua
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
-- translation
|
||||||
|
local S = mail.S
|
||||||
|
|
||||||
|
mail.settings = {
|
||||||
|
chat_notifications = {
|
||||||
|
type = "bool", default = true, group = "notifications", index = 1,
|
||||||
|
label = S("Chat notifications"), tooltip = S("Receive a message in the chat when there is a new message")
|
||||||
|
},
|
||||||
|
onjoin_notifications = {
|
||||||
|
type = "bool", default = true, group = "notifications", index = 2,
|
||||||
|
label = S("On join notifications"), tooltip = S("Receive a message at login when inbox isn't empty") },
|
||||||
|
hud_notifications = {
|
||||||
|
type = "bool", default = true, group = "notifications", index = 3,
|
||||||
|
label = S("HUD notifications"), tooltip = S("Show an HUD notification when inbox isn't empty")
|
||||||
|
},
|
||||||
|
sound_notifications = {
|
||||||
|
type = "bool", default = true, group = "notifications", index = 4,
|
||||||
|
label = S("Sound notifications"), tooltip = S("Play a sound when there is a new message")
|
||||||
|
},
|
||||||
|
unreadcolorenable = {
|
||||||
|
type = "bool", default = true, group = "message_list", index = 1,
|
||||||
|
label = S("Show unread in different color")
|
||||||
|
},
|
||||||
|
cccolorenable = {
|
||||||
|
type = "bool", default = true, group = "message_list", index = 2,
|
||||||
|
label = S("Show CC/BCC in different color")
|
||||||
|
},
|
||||||
|
defaultsortfield = {
|
||||||
|
type = "index", default = 3, group = "box_fields", index = 1,
|
||||||
|
label = S("Default sorting field"), dataset = { S("From/To"), S("Subject"), S("Date") }
|
||||||
|
},
|
||||||
|
defaultsortdirection = {
|
||||||
|
type = "index", default = 1, group = "box_fields", index = 2,
|
||||||
|
label = S("Default sorting direction"), dataset = { S("Ascending"), S("Descending") }
|
||||||
|
},
|
||||||
|
trash_move_enable = {
|
||||||
|
type = "bool", default = true, group = "other", index = 1,
|
||||||
|
label = S("Move deleted messages to trash")
|
||||||
|
},
|
||||||
|
auto_marking_read = {
|
||||||
|
type = "bool", default = true, group = "other", index = 2,
|
||||||
|
label = S("Automatic marking read"), tooltip = S("Mark a message as read when opened")
|
||||||
|
},
|
||||||
|
date_format = {
|
||||||
|
type = "string", default = "%Y-%m-%d %X", group = "date_and_time", index = 3, label = S("Date format"),
|
||||||
|
dataset = {"%Y-%m-%d %X", "%d/%m/%y %X", "%A %d %B %Y %X"}, format = os.date
|
||||||
|
},
|
||||||
|
timezone_offset = {
|
||||||
|
type = "number", default = 0, group = "date_and_time", index = 4,
|
||||||
|
label = S("Timezone offset"), tooltip = S("Offset to add to server time."),
|
||||||
|
},
|
||||||
|
mute_list = {
|
||||||
|
type = "list", default = {}, group = "spam", index = 1,
|
||||||
|
label = S("Mute list")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
mail.settings_groups = {
|
||||||
|
{ name = "notifications", label = S("Notifications"), index = 1, parent = 0},
|
||||||
|
{ name = "message_list", label = S("Message list"), index = 2, parent = 0},
|
||||||
|
{ name = "box_fields", label = S("Fields"), index = 1, parent = "message_list"},
|
||||||
|
{ name = "spam", label = S("Spam"), index = 3, parent = 0},
|
||||||
|
{ name = "other", label = S("Other"), index = 4, parent = 0},
|
||||||
|
{ name = "date_and_time", label = S("Date and Time"), index = 1, parent = "other"}
|
||||||
|
}
|
||||||
|
|
||||||
|
for s, d in pairs(mail.settings) do
|
||||||
|
mail.selected_idxs[s] = {}
|
||||||
|
if d.type == "list" then
|
||||||
|
mail.selected_idxs["index_" .. s] = {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mail.settings.mute_list.check(name, value)
|
||||||
|
local valid_players = {}
|
||||||
|
for _, p in ipairs(value) do
|
||||||
|
if p ~= name and core.player_exists(p) then
|
||||||
|
table.insert(valid_players, p)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return valid_players
|
||||||
|
end
|
||||||
|
|
||||||
|
function mail.settings.mute_list.sync(name)
|
||||||
|
if core.get_modpath("beerchat") then
|
||||||
|
local players = {}
|
||||||
|
for other_player, _ in core.get_auth_handler().iterate() do
|
||||||
|
if beerchat.has_player_muted_player(name, other_player) then
|
||||||
|
table.insert(players, other_player)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return players
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function mail.settings.mute_list.transfer(name, value)
|
||||||
|
if core.get_modpath("beerchat") then
|
||||||
|
for other_player, _ in core.get_auth_handler().iterate() do -- unmute all
|
||||||
|
if not beerchat.execute_callbacks("before_mute", name, other_player) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
core.get_player_by_name(name):get_meta():set_string(
|
||||||
|
"beerchat:muted:" .. other_player, "")
|
||||||
|
end
|
||||||
|
for _, other_player in ipairs(value) do -- then mute only players in table
|
||||||
|
core.get_player_by_name(name):get_meta():set_string(
|
||||||
|
"beerchat:muted:" .. other_player, "true")
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
39
util/spam.lua
Normal file
39
util/spam.lua
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
local function caps_ratio(str)
|
||||||
|
local total_caps = 0
|
||||||
|
for i = 1, #str do -- iteration through each character
|
||||||
|
local c = str:sub(i,i)
|
||||||
|
if string.lower(c) ~= c then -- do not count digits as spam
|
||||||
|
total_caps = total_caps + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return total_caps/(#str or 1) -- avoid division by zero
|
||||||
|
end
|
||||||
|
|
||||||
|
local function words_ratio(str, ratio)
|
||||||
|
local words = {}
|
||||||
|
local split_str = str:split(" ")
|
||||||
|
for _, w in ipairs(split_str) do
|
||||||
|
if not words[w] then
|
||||||
|
words[w] = 0
|
||||||
|
else
|
||||||
|
words[w] = (words[w] or 0) + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for _, n in pairs(words) do
|
||||||
|
if n/#split_str >= ratio then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function mail.check_spam(message)
|
||||||
|
local spam_checks = {}
|
||||||
|
if caps_ratio(message.subject) == 1 or caps_ratio(message.body) > 0.4 then
|
||||||
|
table.insert(spam_checks, "caps")
|
||||||
|
end
|
||||||
|
if words_ratio(message.subject, 0.6) or words_ratio(message.body, 0.2) then
|
||||||
|
table.insert(spam_checks, "words")
|
||||||
|
end
|
||||||
|
return spam_checks
|
||||||
|
end
|
29
util/time_ago.lua
Normal file
29
util/time_ago.lua
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
-- translation
|
||||||
|
local S = mail.S
|
||||||
|
|
||||||
|
function mail.time_ago(t)
|
||||||
|
local elapsed = os.time() - t
|
||||||
|
local str = ""
|
||||||
|
|
||||||
|
local time_units = {
|
||||||
|
{ S("years"), 31536000 },
|
||||||
|
{ S("months"), 2592000 },
|
||||||
|
{ S("weeks"), 604800 },
|
||||||
|
{ S("days"), 86400 },
|
||||||
|
{ S("hours"), 3600 },
|
||||||
|
{ S("minuts"), 60 },
|
||||||
|
{ S("seconds"), 1 },
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, u in ipairs(time_units) do
|
||||||
|
local n = math.modf(elapsed/u[2])
|
||||||
|
if n > 0 then
|
||||||
|
str = str .. " " .. n .. " " .. u[1]
|
||||||
|
elapsed = elapsed - n * u[2]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
str = string.sub(str, 2, -1)
|
||||||
|
|
||||||
|
return S("@1 ago", str)
|
||||||
|
end
|
Loading…
Add table
Reference in a new issue