diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 05588a5..0000000 --- a/.gitattributes +++ /dev/null @@ -1,5 +0,0 @@ -mtt.lua export-ignore -docker-compose.yml export-ignore -*.spec.lua export-ignore -test/* export-ignore -screenshot_* export-ignore diff --git a/.github/workflows/luacheck.yml b/.github/workflows/luacheck.yml index 3c99a99..d00f53a 100644 --- a/.github/workflows/luacheck.yml +++ b/.github/workflows/luacheck.yml @@ -1,10 +1,17 @@ name: luacheck + on: [push, pull_request] + jobs: - luacheck: + build: + runs-on: ubuntu-latest + steps: - - name: Checkout - uses: actions/checkout@master - - name: Luacheck - uses: lunarmodules/luacheck@master + - uses: actions/checkout@v1 + - name: apt + run: sudo apt-get install -y luarocks + - name: luacheck install + run: luarocks install --local luacheck + - name: luacheck run + run: $HOME/.luarocks/bin/luacheck ./ diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2a2f903..f181b6e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,9 +9,9 @@ jobs: timeout-minutes: 10 strategy: matrix: - 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] + 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, latest] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - name: test - run: docker compose up --exit-code-from sut + run: docker-compose up --exit-code-from sut diff --git a/.gitignore b/.gitignore index 7792f71..e4faeef 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,2 @@ i18n.py -mod_translation_updater.py locale/*.tr.old -*.patch diff --git a/.luacheckrc b/.luacheckrc index 7714aa4..3b22541 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -5,16 +5,15 @@ globals = { read_globals = { -- Stdlib string = {fields = {"split"}}, - table = {fields = {"copy", "getn", "indexof", "insert_all"}}, - beerchat = {fields = {"has_player_muted_player", "execute_callbacks"}}, + table = {fields = {"copy", "getn"}}, - -- Luanti - "core", + -- Minetest + "minetest", "vector", "ItemStack", "dump", -- Deps - "unified_inventory", "default", "sfinv_buttons", + "unified_inventory", "default", -- optional mods "mtt", "canonical_name" diff --git a/README.md b/README.md index 848eed8..0c7aec4 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,7 @@ It adds a mail-system that allows players to send each other messages in-game an # Screenshot -![Main view](screenshot_1.4.0_1.png) -![Message view](screenshot_1.4.0_2.png) +![](screenshot_1.1.0.png) # Installation @@ -44,8 +43,7 @@ Mails can be deleted, marked as read or unread, replied to and forwarded to anot * 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. +* Translated in : English, French, German, Chinese (both traditional and simplified), Spanish, Brazilian Portuguese. # Compatibility / Migration @@ -53,10 +51,8 @@ Overview: * `v1` all the data is in the `/mails.db` file * `v2` every player has its own (in-) mailbox in the `/mails/.json` file * `v3` every player has an entry in the `` `mod_storage/` (inbox, outbox, drafts, contacts, mailing lists, settings) -* `v3.1` database fix after the message id mess # Dependencies - * None # License @@ -76,7 +72,7 @@ See the "LICENSE" file * fluxionary (Minor fixups) * Toby1710 (UX fixes) * Peter Nerlich (CC, BCC) -* Emojigit (Performance, Traditional Chinese translation) +* Emojigit (Traditional Chinese translation) * Niklp09 (German translation) * Dennis Jenkins (UX fixes) * Thomas Rudin (Maintenance) @@ -87,13 +83,6 @@ See the "LICENSE" file * 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 diff --git a/api.lua b/api.lua index 159efea..48c398b 100644 --- a/api.lua +++ b/api.lua @@ -1,7 +1,7 @@ -- see: mail.md -- translation -local S = mail.S +local S = minetest.get_translator("mail") local f = string.format @@ -10,22 +10,9 @@ function mail.register_on_receive(func) mail.registered_on_receives[#mail.registered_on_receives + 1] = func end -mail.registered_on_player_receives = {} -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) if type(m.from) ~= "string" then return false, "'from' 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.to) ~= "string" then return false, "'to' is not a string" end if type(m.body) ~= "string" then return false, "'body' is not a string" end -- defaults @@ -34,25 +21,23 @@ function mail.send(m) -- normalize to, cc and bcc while compiling a list of all recipients local recipients = {} local undeliverable = {} - m.to = mail.concat_player_list(mail.extract_maillists(m.to, m.from)) - m.to = mail.normalize_players_and_add_recipients(m.from, m.to, recipients, undeliverable) + m.to = mail.concat_player_list(mail.extractMaillists(m.to, m.from)) + m.to = mail.normalize_players_and_add_recipients(m.to, recipients, undeliverable) if m.cc then - m.cc = mail.concat_player_list(mail.extract_maillists(m.cc, m.from)) - m.cc = mail.normalize_players_and_add_recipients(mail.from, m.cc, recipients, undeliverable) + m.cc = mail.concat_player_list(mail.extractMaillists(m.cc, m.from)) + m.cc = mail.normalize_players_and_add_recipients(m.cc, recipients, undeliverable) end if m.bcc then - m.bcc = mail.concat_player_list(mail.extract_maillists(m.bcc, m.from)) - m.bcc = mail.normalize_players_and_add_recipients(m.from, m.bcc, recipients, undeliverable) + m.bcc = mail.concat_player_list(mail.extractMaillists(m.bcc, m.from)) + m.bcc = mail.normalize_players_and_add_recipients(m.bcc, recipients, undeliverable) end if next(undeliverable) then -- table is not empty - local undeliverable_reason = {S("The mail could not be sent:")} - for _, reason in pairs(undeliverable) do - table.insert(undeliverable_reason, reason) + local undeliverable_names = {} + for name in pairs(undeliverable) do + undeliverable_names[#undeliverable_names + 1] = '"' .. name .. '"' end - return false, table.concat(undeliverable_reason, "\n") - elseif not next(recipients) then - return false, S("You did not specify any valid recipient.") + return false, f("recipients %s don't exist; cannot send mail.", table.concat(undeliverable_names, ", ")) end local extra = {} @@ -69,7 +54,7 @@ function mail.send(m) extra_log = "" end - core.log("action", f("[mail] %q send mail to %q%s with subject %q and body %q", + minetest.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 )) @@ -95,11 +80,34 @@ function mail.send(m) local entry = mail.get_storage_entry(m.from) table.insert(entry.outbox, 1, msg) mail.set_storage_entry(m.from, entry) - msg.spam = #mail.check_spam(msg) >= 1 -- add in every receivers inbox - for _, deliver in pairs(recipients) do - deliver(msg) + for recipient in pairs(recipients) do + entry = mail.get_storage_entry(recipient) + table.insert(entry.inbox, msg) + mail.set_storage_entry(recipient, entry) + end + + -- notify recipients that happen to be online + local mail_alert = S("You have a new message from @1! Subject: @2", m.from, m.subject) .. + "\n" .. S("To view it, type /mail") + local unified_inventory_alert = S("You could also use the button in your inventory.") + for _, player in ipairs(minetest.get_connected_players()) do + local name = player:get_player_name() + if recipients[name] then + if mail.get_setting(name, "chat_notifications") == true then + minetest.chat_send_player(name, mail_alert) + if minetest.get_modpath("unified_inventory") then + minetest.chat_send_player(name, unified_inventory_alert) + end + end + if mail.get_setting(name, "sound_notifications") == true then + minetest.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 for i=1, #mail.registered_on_receives do @@ -113,16 +121,13 @@ end function mail.save_draft(m) if type(m.from) ~= "string" then return false, "'from' 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.to) ~= "string" then return false, "'to' is not a string" end if type(m.body) ~= "string" then return false, "'body' is not a string" end -- defaults m.subject = m.subject or "(No subject)" - core.log("verbose", f("[mail] %q saves draft with subject %q and body %q", + minetest.log("verbose", f("[mail] %q saves draft with subject %q and body %q", m.from, m.subject, m.body )) diff --git a/api.md b/api.md index aec8232..7ef2ea9 100644 --- a/api.md +++ b/api.md @@ -1,3 +1,4 @@ + # Mail format The mail format in the api hooks @@ -33,7 +34,7 @@ local success, error = mail.send({ ``` # Hooks -Generic on-receive mail hook: +On-receive mail hook: ```lua mail.register_on_receive(function(m) @@ -41,35 +42,11 @@ mail.register_on_receive(function(m) 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 mod-storage entry for a player (indexed by playername and serialized with json): ```lua { - contacts = { { -- name of the player (unique key in the list) @@ -99,9 +76,7 @@ mod-storage entry for a player (indexed by playername and serialized with json): -- timestamp (os.time()) time = 1234, -- read-flag (true: player has read the mail, inbox only) - read = true, - -- spam-flag (true: that mail is noted as a spam) - spam = false + read = true },{ ... } @@ -109,12 +84,6 @@ mod-storage entry for a player (indexed by playername and serialized with json): outbox = { -- same format as "inbox" }, - drafts = { - -- same format as "inbox" - }, - trash = { - -- same format as "inbox" - }, lists = { { -- name of the maillist (unique key in the list) @@ -124,10 +93,5 @@ mod-storage entry for a player (indexed by playername and serialized with json): -- playername list players = {"playername", "playername2"} } - }, - settings = { - setting1 = "value", - setting2 = true, - setting3 = 123 } } diff --git a/api.spec.lua b/api.spec.lua index 56fc676..a9f9d2f 100644 --- a/api.spec.lua +++ b/api.spec.lua @@ -1,76 +1,12 @@ -mail.register_recipient_handler(function(_, name) - if name:sub(1, 6) == "alias/" then - return true, name:sub(7) - elseif name == "list/test" then - 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) + -- send a mail + local success, err = mail.send({from = "player1", to = "player2", subject = "something", body = "blah"}) + assert(success) + assert(not err) + -- check the receivers inbox + local entry = mail.get_storage_entry("player2") + assert(entry) + assert(#entry.inbox > 0) callback() end) diff --git a/chatcommands.lua b/chatcommands.lua index 544350f..a152274 100644 --- a/chatcommands.lua +++ b/chatcommands.lua @@ -1,4 +1,4 @@ -core.register_chatcommand("mail",{ +minetest.register_chatcommand("mail",{ description = "Open the mail interface", func = function(name, param) if #param > 0 then -- if param is not empty diff --git a/docker-compose.yml b/docker-compose.yml index fd2a4ce..f7f9976 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,4 @@ -version: "4.1" +version: "3.6" services: sut: @@ -16,4 +16,4 @@ services: - "30000:30000/udp" volumes: - world_data: {} + world_data: {} \ No newline at end of file diff --git a/gui.lua b/gui.lua index fe399e5..3287360 100644 --- a/gui.lua +++ b/gui.lua @@ -1,5 +1,5 @@ -if core.get_modpath("unified_inventory") then +if minetest.get_modpath("unified_inventory") then unified_inventory.register_button("mail", { type = "image", @@ -10,13 +10,3 @@ if core.get_modpath("unified_inventory") then 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 diff --git a/hud.lua b/hud.lua index f4b98d3..7eca2a2 100644 --- a/hud.lua +++ b/hud.lua @@ -1,12 +1,12 @@ local huddata = {} -core.register_on_joinplayer(function(player) +minetest.register_on_joinplayer(function(player) local name = player:get_player_name() local data = {} data.imageid = player:hud_add({ - type = "image", + hud_elem_type = "image", name = "MailIcon", position = {x=0.52, y=0.52}, text="", @@ -15,7 +15,7 @@ core.register_on_joinplayer(function(player) }) data.textid = player:hud_add({ - type = "text", + hud_elem_type = "text", name = "MailText", position = {x=0.55, y=0.52}, text= "", @@ -27,7 +27,7 @@ core.register_on_joinplayer(function(player) huddata[name] = data end) -core.register_on_leaveplayer(function(player) +minetest.register_on_leaveplayer(function(player) local name = player:get_player_name() huddata[name] = nil end) @@ -35,7 +35,7 @@ end) function mail.hud_update(playername, messages) local data = huddata[playername] - local player = core.get_player_by_name(playername) + local player = minetest.get_player_by_name(playername) if not data or not player then return diff --git a/init.lua b/init.lua index 2643f42..23f41f4 100644 --- a/init.lua +++ b/init.lua @@ -3,10 +3,7 @@ mail = { version = 3, -- mod storage - storage = core.get_mod_storage(), - - -- translation - S = core.get_translator(core.get_current_modname()), + storage = minetest.get_mod_storage(), -- ui theme prepend theme = "", @@ -20,7 +17,6 @@ mail = { outbox = {}, drafts = {}, trash = {}, - message = {}, contacts = {}, maillists = {}, to = {}, @@ -32,20 +28,40 @@ mail = { filter = {}, multipleselection = {}, optionstab = {}, - settings_group = {}, - contributor_grouping = {}, + chat_notifications = {}, + onjoin_notifications = {}, + hud_notifications = {}, + sound_notifications = {}, + unreadcolorenable = {}, + cccolorenable = {}, + trash_move_enable = {} + }, + + colors = { + header = "#999", + selected = "#72FF63", + important = "#FFD700", + additional = "#CCCCDD", + imp_sel = "#B9EB32", + add_sel = "#9FE6A0", + imp_add = "#E6D26F", + imp_add_sel = "#BFE16B", + highlighted = "#466432", + new = "#00F529" }, message_drafts = {} } -if core.get_modpath("default") then +if minetest.get_modpath("default") then mail.theme = default.gui_bg .. default.gui_bg_img end -- sub files -local MP = core.get_modpath(core.get_current_modname()) -dofile(MP .. "/util/init.lua") +local MP = minetest.get_modpath(minetest.get_current_modname()) +dofile(MP .. "/util/normalize.lua") +dofile(MP .. "/util/contact.lua") +dofile(MP .. "/util/uuid.lua") dofile(MP .. "/chatcommands.lua") dofile(MP .. "/migrate.lua") dofile(MP .. "/hud.lua") @@ -53,14 +69,28 @@ dofile(MP .. "/storage.lua") dofile(MP .. "/api.lua") dofile(MP .. "/gui.lua") dofile(MP .. "/onjoin.lua") -dofile(MP .. "/player_recipients.lua") --- sub directories -dofile(MP .. "/ui/init.lua") +dofile(MP .. "/ui/mail.lua") +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") -- migrate storage mail.migrate() -if core.get_modpath("mtt") then +if minetest.get_modpath("mtt") then dofile(MP .. "/mtt.lua") dofile(MP .. "/api.spec.lua") dofile(MP .. "/migrate.spec.lua") diff --git a/locale/mail.de.tr b/locale/mail.de.tr index 0bf5654..12c053d 100644 --- a/locale/mail.de.tr +++ b/locale/mail.de.tr @@ -1,123 +1,81 @@ # 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 +Provided my mt-mods= +Version= +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= +Settings= About=Über +You have a new message from @1! Subject: @2= +To view it, type /mail= +You could also use the button in your inventory.= BCC=BCC Cancel=Abbrechen -Save draft=Entwurf speichern +Save draft=Entwurf Speichern Send=Senden -Subject=Betreff -To=An -CC=CC -Delete=Löschen -New=Neu -Edit=Bearbeiten -Back=Zurück Name=Name No drafts=Keine Entwürfe -Trash=Papierkorb +Edit=Bearbeiten +Trash= Inbox=Posteingang -Outbox=Gesendet +Outbox=Senden Drafts=Entwürfe Contacts=Kontakte Mail lists=Verteilerlisten -Options=Einstellungen +Options= Close=Schließen (No subject)=(Kein Betreff) 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 +That name is already in your contacts= +The contact name cannot be empty.= 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. +That name is already in your mailing lists.= +The mailing list name cannot be empty.= +Save=Speichern Mark Read=Als gelesen makieren Mark Unread=Als ungelesen makieren -Mark Spam=Als Spam markieren -Unmark Spam=Kein Spam -Reply=Antworten -Reply all=Allen antworten -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 +New=Neu (No description)=(Keine Beschreibung) No maillist=Keine Verteilerliste -Receivers=Empfänger -(Un)mute sender=Absender stummschalten/entstummen +From=Von +Delete=Löschen +Subject=Betreff +CC=CC +To=An +You have mail! Type /mail to read= +Filter= +Allow multiple selection= +@1 of @2 selected= +(Un)select all= +No mail=Keine Nachrichten +Date=Datum +Ascending= +Descending= +Read=Lesen +Reply=Antworten +Reply all=Allen antworten +Forward=Weiter Add=Hinzufügen Remove=Entfernen -Reset=Zurücksetzen -Restore=Wiederherstellen -Empty=Leer -Trash is empty=Papierkorb ist leer +Note=Notiz +Back=Zurück +Notifications= +Chat notifications= +On join notifications= +HUD notifications= +Sound notifications= +Message list= +Show unread in different color= +Show CC/BCC in different color= +Default sorting fields= +Other= +Move deleted messages to trash= +Reset= 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 +Restore= +Empty= +Trash is empty= diff --git a/locale/mail.es.tr b/locale/mail.es.tr index 7616c0e..781ec75 100644 --- a/locale/mail.es.tr +++ b/locale/mail.es.tr @@ -1,128 +1,81 @@ # 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 +Provided my mt-mods= +Version= +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= +Settings= About=Acerca de +You have a new message from @1! Subject: @2= +To view it, type /mail= +You could also use the button in your inventory.= 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 +Edit=Editar +Trash= Inbox=Entrada Outbox=Enviados Drafts=Borradores Contacts=Contactos Mail lists=Listas de correo -Options=Opciones +Options= 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 +The contact name cannot be empty.=Ese nombre de contacto no puede estar vacío. 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. +That name is already in your mailing lists.=Ese nombre ya está entus listas de correo. +The mailing list name cannot be empty.=Ese nombre de lista de correo no puede estar vacío. +Save=Guardar Mark Read=Marcar como leído Mark Unread=Marcar como no leído -Mark Spam= -Unmark Spam= +New=Nuevo +(No description)=(Sin descripción) +No maillist=Sin lista de correo +From=De +Delete=Borrar +Subject=Asunto +CC=CC +To=Para +You have mail! Type /mail to read= +Filter=Filtrar +Allow multiple selection=Permitir selección múltiple +@1 of @2 selected= +(Un)select all=(Des)seleccionar todos +No mail=Sin correo +Date=Fecha +Ascending=Ascendente +Descending=Descendiente +Read=Leído 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 +Note=Nota +Back=Volver +Notifications= +Chat notifications= +On join notifications= +HUD notifications= +Sound notifications= +Message list= +Show unread in different color= +Show CC/BCC in different color= +Default sorting fields= +Other= +Move deleted messages to trash= +Reset= 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 +Restore= +Empty= +Trash is empty= diff --git a/locale/mail.fr.tr b/locale/mail.fr.tr index 647e4c5..062e7d2 100644 --- a/locale/mail.fr.tr +++ b/locale/mail.fr.tr @@ -1,40 +1,23 @@ # 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 +Provided my mt-mods=Fourni par mt-mods +Version=Version 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 +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 BCC=Cci Cancel=Annuler Save draft=Enregistrer le brouillon Send=Envoyer -Subject=Objet -To=À -CC=Cc -Delete=Supprimer -New=Nouveau -Edit=Modifier -Back=Retour Name=Nom No drafts=Aucun brouillon +Edit=Modifier Trash=Corbeille Inbox=Boîte de réception Outbox=Envoyés @@ -47,77 +30,52 @@ Close=Fermer 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. +Save=Sauvegarder Mark Read=Marquer comme lu Mark Unread=Marquer non lu -Mark Spam=Marquer comme spam -Unmark Spam=Marquer non-spam -Reply=Répondre -Reply all=Répondre à tous -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 +New=Nouveau +(No description)=Sans description +No maillist=Aucune liste de diffusion From=De +Delete=Supprimer +Subject=Objet +CC=Cc +To=À +You have mail! Type /mail to read=Vous avez reçu un mail ! Entrez /mail pour le consulter 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 +(Un)select all=Tout (dé)selectionner No mail=Aucun mail -Read=Lire +Date=Date Ascending=Croissant Descending=Décroissant -(No description)=(Sans description) -No maillist=Aucune liste de diffusion -Receivers=Destinataires -(Un)mute sender=(Dé)mettre en sourdine +Read=Lire +Reply=Répondre +Reply all=Répondre à tous +Forward=Transférer Add=Ajouter Remove=Enlever +Note=Note +Back=Retour +Notifications=Notifications +Chat notifications=Notifications dans le tchat +On join notifications=Notifications à la connexion +HUD notifications=Notifications ATH +Sound notifications=Notifications sonores +Message list=Liste de messages +Show unread in different color=Coloriser les non lus +Show CC/BCC in different color=Coloriser les Cc/Cci +Default sorting fields=Champs de tri par défaut +Other=Autre +Move deleted messages to trash=Supprimer les messages dans la corbeille Reset=Réinitialiser +From/To=De/À 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 diff --git a/locale/mail.hu.tr b/locale/mail.hu.tr index c35fa01..3d01387 100644 --- a/locale/mail.hu.tr +++ b/locale/mail.hu.tr @@ -1,40 +1,23 @@ # 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= +Provided my mt-mods=Feltéve, hogy az én mt-mod-om +Version=Verzió 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 +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. 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 +Edit=Szerkesztés Trash= Inbox=PostaLáda Outbox=Elküldött @@ -47,82 +30,52 @@ Close=Bezár 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 +Save=Mentés 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 +New=Új +(No description)=(Nincs leírás) +No maillist=Nincs levelező lista From=Tőle +Delete=Törlés +Subject=Cím +CC=CC +To=Neki +You have mail! Type /mail to read=Van egy leveled! Írd /mail az olvasáshoz 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 +Date=Dátum Ascending=Emelkedő Descending=Sűlyedő -(No description)=(Nincs leírás) -No maillist=Nincs levelező lista -Receivers= -(Un)mute sender= +Read=Olvasott +Reply=Válasz +Reply all=Válaszmindenkinek +Forward=Továbbítás Add=Hozzáadás Remove=Elvétel +Note=Jegyzet +Back=Visza +Notifications=Értesítések +Chat notifications=Chates értesítések +On join notifications=Belépési értesírés +HUD notifications= HUD értesítés +Sound notifications=Hang értesítés +Message list=Üzenetek listája +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 fields=Alap válogató terület +Other= +Move deleted messages to trash= Reset=Viszaállítás +From/To=Tól(től)/neki 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ó diff --git a/locale/mail.id.tr b/locale/mail.id.tr deleted file mode 100644 index f33379f..0000000 --- a/locale/mail.id.tr +++ /dev/null @@ -1,128 +0,0 @@ -# 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 diff --git a/locale/mail.pt_BR.tr b/locale/mail.pt_BR.tr index 55307aa..8c8219e 100644 --- a/locale/mail.pt_BR.tr +++ b/locale/mail.pt_BR.tr @@ -1,40 +1,23 @@ # 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= +Provided my mt-mods= +Version= 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 +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. 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 +Edit=Editar Trash= Inbox=Entrada Outbox=Enviadas @@ -47,77 +30,52 @@ Close=Fechar 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 +Save=Salvar 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 +New=Novo +(No description)=(sem descrição) +No maillist=Sem lista de discussão From=De +Delete=Apagar +Subject=Assunto +CC=CC +To=Para +You have mail! Type /mail to read=Você recebeu e-mail! Tecle /mail para ler 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 +Date=Data Ascending=Ascendente Descending=Descendente -(No description)=(sem descrição) -No maillist=Sem lista de discussão -Receivers= -(Un)mute sender= +Read=Ler +Reply=Responder +Reply all=Responder Todos +Forward=Encaminhar Add=Adicionar Remove=Remover +Note=Nota +Back=Voltar +Notifications=Notificações +Chat notifications=Notificação de conversa +On join notifications=Notificação ao entrar +HUD notifications=Notificação no HUD +Sound notifications= +Message list=Lista de mensagens +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 fields=Ordenamento de campos padrão +Other= +Move deleted messages to trash= Reset= +From/To=De/Para 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= diff --git a/locale/mail.ru.tr b/locale/mail.ru.tr deleted file mode 100644 index a832c0f..0000000 --- a/locale/mail.ru.tr +++ /dev/null @@ -1,123 +0,0 @@ -# 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 назад diff --git a/locale/mail.uk.tr b/locale/mail.uk.tr deleted file mode 100644 index 8bb5852..0000000 --- a/locale/mail.uk.tr +++ /dev/null @@ -1,123 +0,0 @@ -# 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 тому diff --git a/locale/mail.zh_CN.tr b/locale/mail.zh_CN.tr index 9665706..2933e22 100644 --- a/locale/mail.zh_CN.tr +++ b/locale/mail.zh_CN.tr @@ -1,129 +1,82 @@ # 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=设置 +Provided my mt-mods= +Version= +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= +Settings= About=关于 +You have a new message from @1! Subject: @2= +To view it, type /mail= +You could also use the button in your inventory.= 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=垃圾箱 +Edit=编辑 +Trash= Inbox=收件箱 Outbox=已发送 Drafts=草稿 Contacts=通讯录 Mail lists=建组 -Options=选项 +Options= Close=关闭 -(No subject)=(无主题) +(No subject)=(无主题) Player name=玩家名字 -That name is already in your contacts=这个玩家已经在您的通讯录里。 -The contact name cannot be empty.=联系人名字不能为空。 -Save=保存 -Maillist name=邮件列表名称 +That name is already in your contacts= +The contact name cannot be empty.= +Maillist name=建组名 Desc=描述 Players=玩家 -That name is already in your mailing lists.=这个玩家已经在您的邮件列表里。 -The mailing list name cannot be empty.=邮件列表名称不能为空。 +That name is already in your mailing lists.= +The mailing list name cannot be empty.= +Save=保存 Mark Read=标记为已读 Mark Unread=标记为未读 -Mark Spam=标记为垃圾邮件 -Unmark Spam=取消标记为垃圾邮件 +New=新 +(No description)=(无描述) +No maillist=无建组 +From=发件人 +Delete=删除 +Subject=主题 +CC=抄送 +To=收件人 +You have mail! Type /mail to read= +Filter=筛选 +Allow multiple selection=允许多选 +@1 of @2 selected= +(Un)select all=(取消)选中所有 +No mail=无邮件 +Date=时间 +Ascending=升序 +Descending=降序 +Read=浏览 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=版本 +Note=备注 +Back=返回 +Notifications= +Chat notifications= +On join notifications= +HUD notifications= +Sound notifications= +Message list= +Show unread in different color= +Show CC/BCC in different color= +Default sorting fields= +Other= +Move deleted messages to trash= +Reset= +From/To= +Restore= +Empty= +Trash is empty= diff --git a/locale/mail.zh_TW.tr b/locale/mail.zh_TW.tr index b5f947e..35b54ac 100644 --- a/locale/mail.zh_TW.tr +++ b/locale/mail.zh_TW.tr @@ -1,128 +1,81 @@ # 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=設置 +Provided my mt-mods= +Version= +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= +Settings= About=關於 +You have a new message from @1! Subject: @2= +To view it, type /mail= +You could also use the button in your inventory.= BCC=密件副本 Cancel=取消 Save draft=儲存草稿 Send=發送 -Subject=主旨 -To=收件人 -CC=副本 -Delete=刪除 -New=新建 -Edit=編輯 -Back=返回 Name=名稱 No drafts=沒有草稿 -Trash=垃圾箱 +Edit=編輯 +Trash= Inbox=收件箱 Outbox=寄件備份 Drafts=草稿 Contacts=聯繫人 Mail lists=郵件列表 -Options=選項 +Options= Close=關閉 (No subject)=(沒有主旨) Player name=玩家名稱 -That name is already in your contacts=玩家已經在您的通訊錄中。 -The contact name cannot be empty.=聯繫人名字不能為空。 -Save=儲存 +That name is already in your contacts= +The contact name cannot be empty.= Maillist name=郵件列表名稱 Desc=描述 Players=玩家 -That name is already in your mailing lists.=玩家已經在您的郵件列表中。 -The mailing list name cannot be empty.=郵件列表名稱不能為空。 +That name is already in your mailing lists.= +The mailing list name cannot be empty.= +Save=儲存 Mark Read=標記已讀 Mark Unread=標記未讀 -Mark Spam=標記垃圾郵件 -Unmark Spam=取消標記垃圾郵件 +New=新建 +(No description)=(沒有描述) +No maillist=沒有郵件列表 +From=寄件者 +Delete=刪除 +Subject=主旨 +CC=副本 +To=收件人 +You have mail! Type /mail to read= +Filter= +Allow multiple selection= +@1 of @2 selected= +(Un)select all= +No mail=沒有郵件 +Date=日期 +Ascending= +Descending= +Read=閱讀 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=版本 +Note=備註 +Back=返回 +Notifications= +Chat notifications= +On join notifications= +HUD notifications= +Sound notifications= +Message list= +Show unread in different color= +Show CC/BCC in different color= +Default sorting fields= +Other= +Move deleted messages to trash= +Reset= +From/To= +Restore= +Empty= +Trash is empty= diff --git a/locale/template.txt b/locale/template.txt index 74fc9fe..4399f79 100644 --- a/locale/template.txt +++ b/locale/template.txt @@ -1,40 +1,23 @@ # 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= +Provided my mt-mods= +Version= 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= +You have a new message from @1! Subject: @2= +To view it, type /mail= +You could also use the button in your inventory.= BCC= Cancel= Save draft= Send= -Subject= -To= -CC= -Delete= -New= -Edit= -Back= Name= No drafts= +Edit= Trash= Inbox= Outbox= @@ -47,77 +30,52 @@ Close= 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.= +Save= 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= +New= +(No description)= +No maillist= From= +Delete= +Subject= +CC= +To= +You have mail! Type /mail to read= Filter= Allow multiple selection= @1 of @2 selected= (Un)select all= No mail= -Read= +Date= Ascending= Descending= -(No description)= -No maillist= -Receivers= -(Un)mute sender= +Read= +Reply= +Reply all= +Forward= Add= Remove= +Note= +Back= +Notifications= +Chat notifications= +On join notifications= +HUD notifications= +Sound notifications= +Message list= +Show unread in different color= +Show CC/BCC in different color= +Default sorting fields= +Other= +Move deleted messages to trash= Reset= +From/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= diff --git a/mail.hu.tr b/mail.hu.tr new file mode 100644 index 0000000..5876fbe --- /dev/null +++ b/mail.hu.tr @@ -0,0 +1,76 @@ +# textdomain: mail +# author: nyomi +Provided my mt-mods=Feltéve, hogy az én mt-mod-om +Version=Verzió +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 +Note=Jegyzet +Settings=Beállítások +About=Róla +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. +BCC=BCC +Cancel=Mégse +Save draft=mentés piszkozatként +Send=Küldés +Subject=Cím +To=Neki +CC=CC +Name=Név +No drafts=Nincsenek piszkozatok +Edit=Szerkesztés +New=Új +Delete=Törlés +Inbox=PostaLáda +Outbox=Elküldött üzenetek +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 +From=Tőle +Read=Olvasott +Filter=Filterek +Allow multiple selection= +@1 selected=@1 kiválasztva +(Un)select all=(ne válaszd ki) mindegyik választása +No mail=Nincs levél +Reply=Válasz +Reply all=Válaszmindenkinek +Forward=Továbbítás +Date=Dátum +Ascending=Emelkedő +Descending=Sűlyedő +(No description)=(Nincs leírás) +No maillist=Nincs levelező lista +You have mail! Type /mail to read=Van egy leveled! Írd /mail az olvasáshoz +Add=Hozzáadás +Remove=Elvétel +Back=Visza +Notifications=Értesítések +Chat notifications=Chates értesítések +On join notifications=Belépési értesírés +HUD notifications= HUD értesítés +Sound notifications=Hang értesítés +Message list=Üzenetek listája +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 fields=Alap válogató terület +From/To=Tól(től)/neki +Reset=Viszaállítás diff --git a/migrate.lua b/migrate.lua index e4f72e6..0266e63 100644 --- a/migrate.lua +++ b/migrate.lua @@ -1,13 +1,13 @@ + local STORAGE_VERSION_KEY = "@@version" -local CURRENT_VERSION = 3.1 local function migrate_v1_to_v3() - local file = io.open(core.get_worldpath().."/mail.db", "r") + local file = io.open(minetest.get_worldpath().."/mail.db", "r") assert(file) print("[mail] Migration from v1 to v3 database") local data = file:read("*a") - local oldmails = core.deserialize(data) + local oldmails = minetest.deserialize(data) file:close() for name, oldmessages in pairs(oldmails) do @@ -28,7 +28,7 @@ local function migrate_v1_to_v3() -- rename file print("[mail,v1] migration done, renaming old mail.db") - os.rename(core.get_worldpath().."/mail.db", core.get_worldpath().."/mail.db.old") + os.rename(minetest.get_worldpath().."/mail.db", minetest.get_worldpath().."/mail.db.old") end local function read_json_file(path) @@ -36,7 +36,7 @@ local function read_json_file(path) local content = {} if file then local json = file:read("*a") - content = core.parse_json(json or "[]") or {} + content = minetest.parse_json(json or "[]") or {} file:close() end return content @@ -44,13 +44,13 @@ end -- migrate from v2 to v3 database local function migrate_v2_to_v3() - local maildir = core.get_worldpath().."/mails" - core.mkdir(maildir) -- if necessary (eg. first login) + local maildir = minetest.get_worldpath().."/mails" + minetest.mkdir(maildir) -- if necessary (eg. first login) print("[mail] Migration from v2 to v3 database") -- defer execution until auth-handler ready (first server-step) - core.after(0, function() - for playername, _ in core.get_auth_handler().iterate() do + minetest.after(0, function() + for playername, _ in minetest.get_auth_handler().iterate() do local entry = mail.get_storage_entry(playername) local player_contacts = read_json_file(maildir .. "/contacts/" .. playername .. ".json") @@ -80,149 +80,20 @@ local function migrate_v2_to_v3() 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() -- check for v2 storage first, v1-migration might have set the v3-flag already - local version = mail.storage:get_float(STORAGE_VERSION_KEY) - if version < math.floor(CURRENT_VERSION) then + local version = mail.storage:get_int(STORAGE_VERSION_KEY) + if version < 3 then -- v2 to v3 migrate_v2_to_v3() - mail.storage:set_float(STORAGE_VERSION_KEY, CURRENT_VERSION) + mail.storage:set_int(STORAGE_VERSION_KEY, 3) end -- check for v1 storage - local v1_file = io.open(core.get_worldpath().."/mail.db", "r") + local v1_file = io.open(minetest.get_worldpath().."/mail.db", "r") if v1_file then -- v1 to v3 migrate_v1_to_v3() - 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) + mail.storage:set_int(STORAGE_VERSION_KEY, 3) end end diff --git a/mod.conf b/mod.conf index 94b206f..31761be 100644 --- a/mod.conf +++ b/mod.conf @@ -1,4 +1,3 @@ name = mail description = ingame mail-system - -optional_depends = canonical_name,default,mtt,unified_inventory,sfinv_buttons,beerchat +optional_depends = canonical_name,default,mtt,unified_inventory diff --git a/mtt.lua b/mtt.lua index ba6054e..7c8cf0b 100644 --- a/mtt.lua +++ b/mtt.lua @@ -1,7 +1,7 @@ mtt.register("setup", function(callback) -- create test players - local auth_handler = core.get_auth_handler() + local auth_handler = minetest.get_auth_handler() auth_handler.set_password("player1", "") auth_handler.set_password("player2", "") auth_handler.set_password("player3", "") diff --git a/onjoin.lua b/onjoin.lua index 56ec965..f7a45e2 100644 --- a/onjoin.lua +++ b/onjoin.lua @@ -1,8 +1,8 @@ -- translation -local S = mail.S +local S = minetest.get_translator("mail") -core.register_on_joinplayer(function(player) - core.after(2, function(name) +minetest.register_on_joinplayer(function(player) + minetest.after(2, function(name) local entry = mail.get_storage_entry(name) local messages = entry.inbox mail.hud_update(name, messages) @@ -16,8 +16,8 @@ core.register_on_joinplayer(function(player) end if unreadcount > 0 and mail.get_setting(name, "onjoin_notifications") then - core.chat_send_player(name, - core.colorize(mail.get_color("new"), "(" .. unreadcount .. ") " .. S("You have mail! Type /mail to read"))) + minetest.chat_send_player(name, + minetest.colorize(mail.colors.new, "(" .. unreadcount .. ") " .. S("You have mail! Type /mail to read"))) end end, player:get_player_name()) end) diff --git a/player_recipients.lua b/player_recipients.lua deleted file mode 100644 index 2511a96..0000000 --- a/player_recipients.lua +++ /dev/null @@ -1,53 +0,0 @@ --- 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 diff --git a/screenshot_1.2.0.png b/screenshot_1.2.0.png deleted file mode 100644 index c0cfbae..0000000 Binary files a/screenshot_1.2.0.png and /dev/null differ diff --git a/screenshot_1.4.0_1.png b/screenshot_1.4.0_1.png deleted file mode 100644 index 892336e..0000000 Binary files a/screenshot_1.4.0_1.png and /dev/null differ diff --git a/screenshot_1.4.0_2.png b/screenshot_1.4.0_2.png deleted file mode 100644 index e12aa4f..0000000 Binary files a/screenshot_1.4.0_2.png and /dev/null differ diff --git a/storage.lua b/storage.lua index 77974df..3c3b994 100644 --- a/storage.lua +++ b/storage.lua @@ -31,7 +31,7 @@ function mail.get_storage_entry(playername) entry = populate_entry() else -- deserialize existing entry - local e = core.parse_json(str) + local e = minetest.parse_json(str) entry = populate_entry(e) end @@ -55,23 +55,20 @@ 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)) + mail.storage:set_string(key, minetest.write_json(entry)) end -- clear queue save_queued_entries = {} - -- clear cached entries - cache = {} - -- save every second - core.after(1, save_worker) + minetest.after(1, save_worker) end -- start save-worker loop save_worker() -- save on shutdown -core.register_on_shutdown(save_worker) +minetest.register_on_shutdown(save_worker) -- get a mail by id from the players in- or outbox function mail.get_message(playername, msg_id) @@ -154,46 +151,38 @@ function mail.sort_messages(messages, sortfield, descending, filter) return results end -local function mark_property(playername, property, msg_ids, value, hud_update) +-- marks a mail read by its id +function mail.mark_read(playername, msg_ids) 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 _, property_msg_id in ipairs(msg_ids) do + for _, read_msg_id in ipairs(msg_ids) do for _, entry_msg in ipairs(entry.inbox) do - if entry_msg.id == property_msg_id then - entry_msg[property] = value + if entry_msg.id == read_msg_id then + entry_msg.read = true 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) + mail.hud_update(playername, entry.inbox) 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) + 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 _, unread_msg_id in ipairs(msg_ids) do + for _, entry_msg in ipairs(entry.inbox) do + if entry_msg.id == unread_msg_id then + entry_msg.read = false + end + end + end + mail.set_storage_entry(playername, entry) return end @@ -346,9 +335,6 @@ function mail.get_maillist_by_name(playername, listname) local entry = mail.get_storage_entry(playername) for _, list in ipairs(entry.lists) do if list.name == listname then - if not list.players then - list.players = {} - end return list end end @@ -365,9 +351,6 @@ function mail.update_maillist(playername, list, old_list_name) end end -- insert - if not list.players then - list.players = {} - end table.insert(entry.lists, list) mail.set_storage_entry(playername, entry) end @@ -384,72 +367,61 @@ function mail.delete_maillist(playername, listname) end end -local function extract_maillists_main(receivers, maillists_owner, expanded_receivers, seen) - if type(receivers) == "string" then - receivers = mail.parse_player_list(receivers) - end +function mail.extractMaillists(receivers_string, maillists_owner) + local receivers = mail.parse_player_list(receivers_string) -- extracted 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) + -- 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 - else - seen[receiver] = true - core.log("verbose", ("mail: adding %q to receiver list during maillist expansion"):format(receiver)) - table.insert(expanded_receivers, receiver) end + receivers_string = mail.concat_player_list(receivers) end + + return receivers end -function mail.extract_maillists(receivers, maillists_owner) - local expanded_receivers = {} - extract_maillists_main(receivers, maillists_owner, expanded_receivers, {}) - return expanded_receivers +function mail.get_setting_default_value(setting_name) + local default_values = { + chat_notifications = true, + onjoin_notifications = true, + hud_notifications = true, + sound_notifications = true, + unreadcolorenable = true, + cccolorenable = true, + defaultsortfield = 3, + defaultsortdirection = 1, + trash_move_enable = true, + } + return default_values[setting_name] end -function mail.get_setting_default_value(key) - return mail.settings[key].default -end - -function mail.get_setting(playername, key) +function mail.get_setting(playername, setting_name) 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 + if entry.settings[setting_name] ~= nil then + return entry.settings[setting_name] + else + return mail.get_setting_default_value(setting_name) end - - return value end -- add or update a setting -function mail.set_setting(playername, key, value, not_transfer) +function mail.set_setting(playername, key, value) 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 + entry.settings[key] = 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) @@ -458,7 +430,7 @@ function mail.reset_settings(playername) mail.set_storage_entry(playername, entry) end -function mail.pairs_by_keys(t, f) +function mail.pairsByKeys(t, f) -- http://www.lua.org/pil/19.3.html local a = {} for n in pairs(t) do table.insert(a, n) end diff --git a/textures/search.png b/textures/search.png deleted file mode 100644 index 421b833..0000000 Binary files a/textures/search.png and /dev/null differ diff --git a/ui/about.lua b/ui/about.lua index b8db215..d08e755 100644 --- a/ui/about.lua +++ b/ui/about.lua @@ -1,128 +1,53 @@ -- translation -local S = mail.S +local S = minetest.get_translator("mail") 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) - mail.selected_idxs.contributor_grouping[name] = tonumber(mail.selected_idxs.contributor_grouping[name]) or 1 - local formspec = [[ size[10,6;] - tabheader[0,0;optionstab;]] .. S("Settings") .. "," .. S("About") .. [[;2;false;false] + tabheader[0.3,1;optionstab;]] .. S("Settings") .. "," .. S("About") .. [[;2;false;false] button[9.35,0;0.75,0.5;back;X] - - box[0,0;3,0.45;]] .. mail.get_color("highlighted") .. [[] - label[0.2,0;Mail] - - 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;;;]] .. + label[0,0.8;Mail] + label[0,1.2;]] .. S("Provided my mt-mods") .. [[] + label[0,1.6;]] .. S("Version") .. [[ : 1.2.0] + label[0,2.2;]] .. S("Licenses") .. [[ :] + label[0.2,2.6;]] .. S("Expat (code), WTFPL (textures)") .. [[] + label[0,3.2;https://github.com/mt-mods/mail] + label[0,3.6;https://content.minetest.net/packages/mt-mods/mail] + textarea[0.5,4.8;4,5.5;;]] .. S("Note") .. [[;]] .. 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] + tablecolumns[color;text;text] + table[5,0.75;4.9,5.5;contributors;]] .. + mail.colors.header .. [[,]] .. S("Contributors") .. [[,,]] .. + mail.colors.important .. [[,Cheapie,Initial idea/project,]] .. + [[,Rubenwardy,Lua/UI improvements,]] .. + [[,BuckarooBanzay,Clean-ups\, Refactoring,]] .. + [[,Athozus,Boxes\, Maillists\, UI\, Settings,]] .. + [[,fluxionary,Minor fixups,]] .. + [[,SX,Various fixes\, UI,]] .. + [[,Toby1710,UX fixes,]] .. + [[,Peter Nerlich,CC\, BCC,]] .. + [[,Niklp,German translation,]] .. + [[,Emojigit,Traditional Chinese trans.,]] .. + [[,Dennis Jenkins,UX fixes,]] .. + [[,Thomas Rudin,Maintenance,]] .. + [[,NatureFreshMilk,Maintenance,]] .. + [[,imre84,UI fixes,]] .. + [[,Chache,Spanish translation,]] .. + [[,APercy,Brazilian Portuguese trans.,]] .. + [[,Nuno Filipe Povoa,mail_notif.ogg,]] .. + [[,TheTrueBeginner,Simplified Chinese trans.,]] .. + [[,nyomi,Hungarian translation,]] .. + [[,whosit,UI fixes] + ]] .. mail.theme - 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) + minetest.show_formspec(name, FORMNAME, formspec) end -core.register_on_player_receive_fields(function(player, formname, fields) +minetest.register_on_player_receive_fields(function(player, formname, fields) if formname ~= FORMNAME then return end @@ -139,14 +64,5 @@ core.register_on_player_receive_fields(function(player, formname, fields) 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) diff --git a/ui/compose.lua b/ui/compose.lua index 71750f3..9187d10 100644 --- a/ui/compose.lua +++ b/ui/compose.lua @@ -1,7 +1,8 @@ -- translation -local S = mail.S +local S = minetest.get_translator("mail") local FORMNAME = "mail:compose" +local msg_id = {} function mail.show_compose(name, to, subject, body, cc, bcc, id) local formspec = [[ @@ -20,25 +21,32 @@ function mail.show_compose(name, to, subject, body, cc, bcc, id) ]] .. mail.theme formspec = string.format(formspec, - core.formspec_escape(to) or "", - core.formspec_escape(cc) or "", - core.formspec_escape(bcc) or "", - core.formspec_escape(subject) or "", - core.formspec_escape(body) or "") + minetest.formspec_escape(to) or "", + minetest.formspec_escape(cc) or "", + minetest.formspec_escape(bcc) or "", + minetest.formspec_escape(subject) or "", + minetest.formspec_escape(body) or "") - mail.selected_idxs.message[name] = id or mail.new_uuid() + if id then + msg_id[name] = id + else + msg_id[name] = nil + end - core.show_formspec(name, FORMNAME, formspec) + minetest.show_formspec(name, FORMNAME, formspec) end -core.register_on_player_receive_fields(function(player, formname, fields) +minetest.register_on_player_receive_fields(function(player, formname, fields) if formname ~= FORMNAME then return end local name = player:get_player_name() if fields.send then - local id = mail.selected_idxs.message[name] or mail.new_uuid() + local id = 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 mail is invalid then store it as a draft mail.save_draft({ @@ -63,7 +71,7 @@ core.register_on_player_receive_fields(function(player, formname, fields) body = fields.body, }) if not success then - core.chat_send_player(name, err) + minetest.chat_send_player(name, err) return end @@ -87,7 +95,7 @@ core.register_on_player_receive_fields(function(player, formname, fields) end end - core.after(0.5, function() + minetest.after(0.5, function() mail.selected_idxs.drafts[name] = nil mail.show_mail_menu(name) end) @@ -109,8 +117,8 @@ core.register_on_player_receive_fields(function(player, formname, fields) elseif fields.draft then local id = mail.new_uuid() - if mail.selected_idxs.message[name] then - id = mail.selected_idxs.message[name] + if msg_id[name] then + id = msg_id[name] end mail.save_draft({ id = id, diff --git a/ui/contacts.lua b/ui/contacts.lua index 7c09d65..0ee5a29 100644 --- a/ui/contacts.lua +++ b/ui/contacts.lua @@ -1,5 +1,5 @@ -- translation -local S = mail.S +local S = minetest.get_translator("mail") 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,8.25;2,0.5;back;]] .. S("Back") .. [[] tablecolumns[color;text;text] - table[0,0;5.75,9;contacts;]] .. mail.get_color("header") .. "," .. S("Name") .. "," .. S("Note") + table[0,0;5.75,9;contacts;]] .. mail.colors.header .. "," .. S("Name") .. "," .. S("Note") function mail.show_contacts(name) local formspec = contacts_formspec .. mail.compile_contact_list(name, mail.selected_idxs.contacts[name]) - core.show_formspec(name, FORMNAME, formspec) + minetest.show_formspec(name, FORMNAME, formspec) end -core.register_on_player_receive_fields(function(player, formname, fields) +minetest.register_on_player_receive_fields(function(player, formname, fields) if formname ~= FORMNAME then return end @@ -26,8 +26,8 @@ core.register_on_player_receive_fields(function(player, formname, fields) local contacts = mail.get_contacts(name) if fields.contacts then - local evt = core.explode_table_event(fields.contacts) - for k, _, i in mail.pairs_by_keys(contacts) do + local evt = minetest.explode_table_event(fields.contacts) + for k, _, i in mail.pairsByKeys(contacts) do if i == evt.row - 1 then mail.selected_idxs.contacts[name] = tonumber(k) break @@ -58,7 +58,7 @@ core.register_on_player_receive_fields(function(player, formname, fields) -- except if it was the last. Then determine the new last local found = false local last = nil - for k in mail.pairs_by_keys(contacts) do + for k in mail.pairsByKeys(contacts) do if found then mail.selected_idxs.contacts[name] = tonumber(k) break diff --git a/ui/drafts.lua b/ui/drafts.lua index 3a98b6b..082643a 100644 --- a/ui/drafts.lua +++ b/ui/drafts.lua @@ -1,5 +1,6 @@ -- translation -local S = mail.S +local S = minetest.get_translator("mail") + function mail.show_drafts(name) local trash_tab = "" @@ -7,20 +8,20 @@ function mail.show_drafts(name) trash_tab = "," .. S("Trash") end - local drafts_formspec = "size[8.5,11;]" .. mail.theme .. [[ + local drafts_formspec = "size[8.5,10;]" .. 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") .. [[] + 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;options;]] .. S("Options") .. [[] + button_exit[6,9.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") + table[0,0.7;5.75,9.35;drafts;]] .. mail.colors.header .. "," .. S("To") .. "," .. S("Subject") local formspec = { drafts_formspec } local entry = mail.get_storage_entry(name) @@ -32,14 +33,14 @@ function mail.show_drafts(name) for _, message in ipairs(messages) do formspec[#formspec + 1] = "," formspec[#formspec + 1] = "," - formspec[#formspec + 1] = core.formspec_escape(message.to) + formspec[#formspec + 1] = minetest.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] = minetest.formspec_escape(string.sub(message.subject, 1, 27)) formspec[#formspec + 1] = "..." else - formspec[#formspec + 1] = core.formspec_escape(message.subject) + formspec[#formspec + 1] = minetest.formspec_escape(message.subject) end else formspec[#formspec + 1] = S("(No subject)") @@ -53,5 +54,5 @@ function mail.show_drafts(name) else formspec[#formspec + 1] = "]label[2.25,4.5;" .. S("No drafts") .. "]" end - core.show_formspec(name, "mail:drafts", table.concat(formspec, "")) + minetest.show_formspec(name, "mail:drafts", table.concat(formspec, "")) end diff --git a/ui/edit_contact.lua b/ui/edit_contact.lua index e7885df..1eeea16 100644 --- a/ui/edit_contact.lua +++ b/ui/edit_contact.lua @@ -1,5 +1,5 @@ -- translation -local S = mail.S +local S = minetest.get_translator("mail") local FORMNAME = "mail:editcontact" @@ -24,12 +24,12 @@ function mail.show_edit_contact(name, contact_name, note, illegal_name_hint) end formspec = formspec .. mail.theme formspec = string.format(formspec, - core.formspec_escape(contact_name or ""), - core.formspec_escape(note or "")) - core.show_formspec(name, FORMNAME, formspec) + minetest.formspec_escape(contact_name or ""), + minetest.formspec_escape(note or "")) + minetest.show_formspec(name, FORMNAME, formspec) end -core.register_on_player_receive_fields(function(player, formname, fields) +minetest.register_on_player_receive_fields(function(player, formname, fields) if formname ~= FORMNAME then return end diff --git a/ui/edit_maillists.lua b/ui/edit_maillists.lua index 4e3d595..9ad3e38 100644 --- a/ui/edit_maillists.lua +++ b/ui/edit_maillists.lua @@ -1,5 +1,5 @@ -- translation -local S = mail.S +local S = minetest.get_translator("mail") local FORMNAME = "mail:editmaillist" @@ -25,13 +25,13 @@ function mail.show_edit_maillist(playername, maillist_name, desc, players, illeg end formspec = formspec .. mail.theme formspec = string.format(formspec, - core.formspec_escape(maillist_name or ""), - core.formspec_escape(desc or ""), - core.formspec_escape(players or "")) - core.show_formspec(playername, FORMNAME, formspec) + minetest.formspec_escape(maillist_name or ""), + minetest.formspec_escape(desc or ""), + minetest.formspec_escape(players or "")) + minetest.show_formspec(playername, FORMNAME, formspec) end -core.register_on_player_receive_fields(function(player, formname, fields) +minetest.register_on_player_receive_fields(function(player, formname, fields) if formname ~= FORMNAME then return end @@ -59,6 +59,7 @@ core.register_on_player_receive_fields(function(player, formname, fields) desc = fields.desc, players = mail.parse_player_list(fields.players) }, old_maillist.name) + maillists[mail.selected_idxs.maillists[name]] = nil end else mail.update_maillist(name, { diff --git a/ui/events.lua b/ui/events.lua index 34c9533..6bf0f48 100644 --- a/ui/events.lua +++ b/ui/events.lua @@ -1,6 +1,6 @@ -- Getter to filter and sort messages on demand -local function message_getter(messages, sortfield, ascending, filter) +local function messageGetter(messages, sortfield, ascending, filter) local results return function() if not results then @@ -14,14 +14,12 @@ local function nonempty(x) return ((type(x)=="table")and(#x>0)) end -core.register_on_player_receive_fields(function(player, formname, fields) +minetest.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 - end - - if fields.quit then - return true + elseif fields.quit then + return end -- Get player name and handle / convert common input fields @@ -54,24 +52,19 @@ core.register_on_player_receive_fields(function(player, formname, fields) local entry = mail.get_storage_entry(name) local messagesDrafts = entry.drafts local messagesTrash = entry.trash - local getInbox = message_getter(entry.inbox, inboxsortfield, sortdirection == "2", filter) - local getOutbox = message_getter(entry.outbox, outboxsortfield, sortdirection == "2", filter) + local getInbox = messageGetter(entry.inbox, inboxsortfield, sortdirection == "2", filter) + local getOutbox = messageGetter(entry.outbox, outboxsortfield, sortdirection == "2", filter) -- Hanmdle formspec event if fields.inbox then -- inbox table - local evt = core.explode_table_event(fields.inbox) + local evt = minetest.explode_table_event(fields.inbox) 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 true - end - local inbox = getInbox()[evt.row-1] - if not inbox then - mail.show_mail_menu(name) - return true + return end if mail.selected_idxs.multipleselection[name] then if not mail.selected_idxs.inbox[name] then @@ -80,7 +73,7 @@ core.register_on_player_receive_fields(function(player, formname, fields) local selected_id = 0 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 - if inbox.id == selected_msg then + if getInbox()[evt.row-1].id == selected_msg then selected_id = i table.remove(mail.selected_idxs.inbox[name], i) break @@ -88,16 +81,13 @@ core.register_on_player_receive_fields(function(player, formname, fields) end end if selected_id == 0 then - table.insert(mail.selected_idxs.inbox[name], inbox.id) - mail.selected_idxs.message[name] = inbox.id + table.insert(mail.selected_idxs.inbox[name], getInbox()[evt.row-1].id) end else - mail.selected_idxs.inbox[name] = { inbox.id } - mail.selected_idxs.message[name] = inbox.id + mail.selected_idxs.inbox[name] = { (getInbox()[evt.row-1] or {}).id } end - if evt.type == "DCL" then - mail.selected_idxs.message[name] = inbox.id - mail.show_message(name, inbox.id) + if evt.type == "DCL" and getInbox()[evt.row-1] then + mail.show_message(name, getInbox()[evt.row-1].id) else mail.show_mail_menu(name) end @@ -105,19 +95,14 @@ core.register_on_player_receive_fields(function(player, formname, fields) end if fields.outbox then -- outbox table - local evt = core.explode_table_event(fields.outbox) + local evt = minetest.explode_table_event(fields.outbox) 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 true - end - local outbox = getOutbox()[evt.row-1] - if not outbox then - mail.show_mail_menu(name) - return true + return end if mail.selected_idxs.multipleselection[name] then if not mail.selected_idxs.outbox[name] then @@ -126,7 +111,7 @@ core.register_on_player_receive_fields(function(player, formname, fields) local selected_id = 0 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 - if outbox.id == selected_msg then + if getOutbox()[evt.row-1].id == selected_msg then selected_id = i table.remove(mail.selected_idxs.outbox[name], i) break @@ -134,16 +119,13 @@ core.register_on_player_receive_fields(function(player, formname, fields) end end if selected_id == 0 then - table.insert(mail.selected_idxs.outbox[name], outbox.id) - mail.selected_idxs.message[name] = outbox.id + table.insert(mail.selected_idxs.outbox[name], getOutbox()[evt.row-1].id) end else - mail.selected_idxs.outbox[name] = { outbox.id } - mail.selected_idxs.message[name] = outbox.id + mail.selected_idxs.outbox[name] = { (getOutbox()[evt.row-1] or {}).id } end - if evt.type == "DCL" then - mail.selected_idxs.message[name] = outbox.id - mail.show_message(name, outbox.id) + if evt.type == "DCL" and getOutbox()[evt.row-1] then + mail.show_message(name, getOutbox()[evt.row-1].id) else mail.show_mail_menu(name) end @@ -151,7 +133,7 @@ core.register_on_player_receive_fields(function(player, formname, fields) end if fields.drafts then -- drafts table - local evt = core.explode_table_event(fields.drafts) + local evt = minetest.explode_table_event(fields.drafts) 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" @@ -162,7 +144,6 @@ core.register_on_player_receive_fields(function(player, formname, fields) end mail.selected_idxs.drafts[name] = evt.row - 1 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, messagesDrafts[mail.selected_idxs.drafts[name]].to, messagesDrafts[mail.selected_idxs.drafts[name]].subject, @@ -176,7 +157,7 @@ core.register_on_player_receive_fields(function(player, formname, fields) end if fields.trash then -- trash table - local evt = core.explode_table_event(fields.trash) + local evt = minetest.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" @@ -187,7 +168,6 @@ core.register_on_player_receive_fields(function(player, formname, fields) 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 @@ -211,14 +191,11 @@ core.register_on_player_receive_fields(function(player, formname, fields) elseif fields.read then if formname == "mail:inbox" and nonempty(mail.selected_idxs.inbox[name]) then -- inbox table - mail.selected_idxs.message[name] = mail.selected_idxs.inbox[name][#mail.selected_idxs.inbox[name]] + mail.show_message(name, mail.selected_idxs.inbox[name][#mail.selected_idxs.inbox[name]]) elseif formname == "mail:outbox" and nonempty(mail.selected_idxs.outbox[name]) then -- outbox table - mail.selected_idxs.message[name] = mail.selected_idxs.outbox[name][#mail.selected_idxs.outbox[name]] + mail.show_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]) + mail.show_message(name, messagesTrash[mail.selected_idxs.trash[name]].id) end elseif fields.edit then @@ -313,20 +290,6 @@ core.register_on_player_receive_fields(function(player, formname, fields) 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 mail.show_compose(name) diff --git a/ui/inbox.lua b/ui/inbox.lua index 0553931..5c2c67e 100644 --- a/ui/inbox.lua +++ b/ui/inbox.lua @@ -1,5 +1,5 @@ -- translation -local S = mail.S +local S = minetest.get_translator("mail") function mail.show_inbox(name, sortfieldindex, sortdirection, filter) sortfieldindex = tonumber(sortfieldindex or mail.selected_idxs.sortfield[name]) @@ -13,6 +13,109 @@ function mail.show_inbox(name, sortfieldindex, sortdirection, filter) local sortfield = ({"from","subject","time"})[sortfieldindex] local messages = mail.sort_messages(entry.inbox, sortfield, sortdirection == "2", filter) + local trash_tab = "" + if mail.get_setting(name, "trash_move_enable") then + trash_tab = "," .. S("Trash") + end + + local inbox_formspec = "size[8.5,10;]" .. 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.95;2.5,0.5;read;]] .. S("Read") .. [[] + button[6,1.70;2.5,0.5;reply;]] .. S("Reply") .. [[] + 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.95;2.5,0.5;delete;]] .. S("Delete") .. [[] + button[6,4.82;2.5,0.5;markread;]] .. S("Mark Read") .. [[] + 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,7.6;2.5,0.5;maillists;]] .. S("Mail lists") .. [[] + button[6,8.7;2.5,0.5;options;]] .. S("Options") .. [[] + button_exit[6,9.5;2.5,0.5;quit;]] .. S("Close") .. [[] + + dropdown[0,8.5;2,0.5;sortfield;]] .. + S("From") .. "," .. S("Subject") .. "," .. S("Date") .. [[;]] .. sortfieldindex .. [[;true] + dropdown[2.0,8.5;2,0.5;sortdirection;]] .. + S("Ascending") .. "," .. S("Descending") .. [[;]] .. sortdirection .. [[;true] + field[4.25,8.95;1.4,0.5;filter;]] .. S("Filter") .. [[:;]] .. filter .. [[] + button[5.14,8.62;0.85,0.5;search;Q] + + checkbox[0,9.1;multipleselection;]] .. S("Allow multiple selection") .. [[;]] .. + tostring(mail.selected_idxs.multipleselection[name]) .. [[] + label[0,9.65;]] .. S("@1 of @2 selected", tostring(#mail.selected_idxs.inbox[name]), tostring(#messages)) .. [[] + button[3.5,9.5;2.5,0.5;selectall;]] .. S("(Un)select all") .. [[] + + tablecolumns[color;text;text] + table[0,0.7;5.75,7.45;inbox;]] .. mail.colors.header .. "," .. S("From") .. "," .. S("Subject") + local formspec = { inbox_formspec } + + mail.message_drafts[name] = nil + + local unread_color_enable = mail.get_setting(name, "unreadcolorenable") + local cc_color_enable = mail.get_setting(name, "cccolorenable") + + if #messages > 0 then + for _, message in ipairs(messages) do + local selected_id = 0 + -- 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 + for i, selected_msg in ipairs(mail.selected_idxs.inbox[name]) do + if message.id == selected_msg then + selected_id = i + break + end + end + end + if selected_id > 0 then + if not message.read and unread_color_enable then + if not mail.player_in_list(name, message.to) and cc_color_enable then + formspec[#formspec + 1] = "," .. mail.colors.imp_add_sel + else + formspec[#formspec + 1] = "," .. mail.colors.imp_sel + end + else + if not mail.player_in_list(name, message.to) and cc_color_enable then + formspec[#formspec + 1] = "," .. mail.colors.add_sel + else + formspec[#formspec + 1] = "," .. mail.colors.selected + end + end + else + if not message.read and unread_color_enable then + if not mail.player_in_list(name, message.to) and cc_color_enable then + formspec[#formspec + 1] = "," .. mail.colors.imp_add + else + formspec[#formspec + 1] = "," .. mail.colors.important + end + else + if not mail.player_in_list(name, message.to) and cc_color_enable then + formspec[#formspec + 1] = "," .. mail.colors.additional + else + formspec[#formspec + 1] = "," + end + end + end + formspec[#formspec + 1] = "," + formspec[#formspec + 1] = minetest.formspec_escape(message.from) + 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 + formspec[#formspec + 1] = S("(No subject)") + end + end + formspec[#formspec + 1] = "]" + else + formspec[#formspec + 1] = "]label[2.25,4.5;" .. S("No mail") .. "]" + end + 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 @@ -28,104 +131,5 @@ function mail.show_inbox(name, sortfieldindex, sortdirection, filter) 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.95;2.5,0.5;read;]] .. S("Read") .. [[] - button[6,1.70;2.5,0.5;reply;]] .. S("Reply") .. [[] - 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.95;2.5,0.5;delete;]] .. S("Delete") .. [[] - 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,6.4;2.5,0.5;markspam;]] .. S("Mark Spam") .. [[] - button[6,7.1;2.5,0.5;unmarkspam;]] .. S("Unmark Spam") .. [[] - 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") .. [[] - - 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] - dropdown[2.0,9.5;2,0.5;sortdirection;]] .. - S("Ascending") .. "," .. S("Descending") .. [[;]] .. sortdirection .. [[;true] - field[4.25,9.95;1.4,0.5;filter;]] .. S("Filter") .. [[:;]] .. filter .. [[] - image_button[5.14,9.5;0.85,0.85;search.png;search;] - - checkbox[0,10.1;multipleselection;]] .. S("Allow multiple selection") .. [[;]] .. - tostring(mail.selected_idxs.multipleselection[name]) .. [[] - label[0,10.65;]] .. - 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] - table[0,0.7;5.75,8.45;inbox;]] .. mail.get_color("header") .. "," .. S("From") .. "," .. S("Subject") - local formspec = { inbox_formspec } - - 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 - for _, message in ipairs(messages) do - local selected_id = 0 - local displayed_color = {} - -- 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 - for i, selected_msg in ipairs(mail.selected_idxs.inbox[name]) do - if message.id == selected_msg then - selected_id = i - break - end - end - end - if selected_id > 0 then - table.insert(displayed_color, "selected") - 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] = core.formspec_escape(message.from) - 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 - formspec[#formspec + 1] = "]" - else - formspec[#formspec + 1] = "]label[2.25,4.5;" .. S("No mail") .. "]" - end - - core.show_formspec(name, "mail:inbox", table.concat(formspec, "")) + minetest.show_formspec(name, "mail:inbox", table.concat(formspec, "")) end diff --git a/ui/init.lua b/ui/mail.lua similarity index 50% rename from ui/init.lua rename to ui/mail.lua index b568620..9bf114f 100644 --- a/ui/init.lua +++ b/ui/mail.lua @@ -1,23 +1,3 @@ --- 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) diff --git a/ui/maillists.lua b/ui/maillists.lua index 2d73a78..578f97a 100644 --- a/ui/maillists.lua +++ b/ui/maillists.lua @@ -1,5 +1,5 @@ -- translation -local S = mail.S +local S = minetest.get_translator("mail") 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,8.25;2,0.5;back;]] .. S("Back") .. [[] tablecolumns[color;text;text] - table[0,0;5.75,9;maillists;]] .. mail.get_color("header") .. "," .. S("Name") .. "," .. S("Note") + table[0,0;5.75,9;maillists;]] .. mail.colors.header .. "," .. S("Name") .. "," .. S("Note") function mail.show_maillists(name) local formspec = { maillists_formspec } @@ -19,14 +19,14 @@ function mail.show_maillists(name) for _, maillist in ipairs(maillists) do formspec[#formspec + 1] = "," formspec[#formspec + 1] = "," - formspec[#formspec + 1] = "@" .. core.formspec_escape(maillist.name) + formspec[#formspec + 1] = "@" .. minetest.formspec_escape(maillist.name) formspec[#formspec + 1] = "," if maillist.desc ~= "" then - if string.len(maillist.desc or "") > 30 then - formspec[#formspec + 1] = core.formspec_escape(string.sub(maillist.desc, 1, 27)) + if string.len(maillist.desc) > 30 then + formspec[#formspec + 1] = minetest.formspec_escape(string.sub(maillist.desc, 1, 27)) formspec[#formspec + 1] = "..." else - formspec[#formspec + 1] = core.formspec_escape(maillist.desc) + formspec[#formspec + 1] = minetest.formspec_escape(maillist.desc) end else formspec[#formspec + 1] = S("(No description)") @@ -40,10 +40,10 @@ function mail.show_maillists(name) else formspec[#formspec + 1] = "]label[2.25,4.5;" .. S("No maillist") .. "]" end - core.show_formspec(name, FORMNAME, table.concat(formspec, "")) + minetest.show_formspec(name, FORMNAME, table.concat(formspec, "")) end -core.register_on_player_receive_fields(function(player, formname, fields) +minetest.register_on_player_receive_fields(function(player, formname, fields) if formname ~= FORMNAME then return end @@ -52,7 +52,7 @@ core.register_on_player_receive_fields(function(player, formname, fields) local maillists = mail.get_maillists(name) if fields.maillists then - local evt = core.explode_table_event(fields.maillists) + local evt = minetest.explode_table_event(fields.maillists) mail.selected_idxs.maillists[name] = evt.row - 1 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) @@ -85,7 +85,7 @@ core.register_on_player_receive_fields(function(player, formname, fields) -- except if it was the last. Then determine the new last local found = false local last = nil - for k in mail.pairs_by_keys(maillists) do + for k in mail.pairsByKeys(maillists) do if found then mail.selected_idxs.maillists[name] = k break diff --git a/ui/message.lua b/ui/message.lua index dae4442..d944573 100644 --- a/ui/message.lua +++ b/ui/message.lua @@ -1,95 +1,73 @@ -- translation -local S = mail.S +local S = minetest.get_translator("mail") local FORMNAME = "mail:message" -local function interleave_msg(body) - return "> " .. (body or ""):gsub("\n", "\n> ") -end - - function mail.show_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 = [[ - size[10,10] + size[8,9] - box[0,0;7,1.9;]] .. mail.get_color("highlighted") .. [[] + box[0,0;7,1.9;]] .. mail.colors.highlighted .. [[] - button[9.25,0.15;0.75,0.5;back;X] - button[7.25,-0.07;2,1;receivers;]] .. S("Receivers") .. [[] + 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("To") .. [[: %s] label[0.2,0.9;]] .. S("CC") .. [[: %s] label[0.2,1.3;]] .. S("Date") .. [[: %s] - tooltip[0.2,1.3;4.8,0.4;]] .. mail.time_ago(message.time) .. [[] + button[5.1,1;2,1;receivers;]] .. S("Receivers") .. [[] label[0,2.1;]] .. S("Subject") .. [[: %s] - textarea[0.25,2.6;7.25,8.75;;;%s] + textarea[0.25,2.6;8,7.0;;;%s] - button[7.25,1.0;2.75,1;reply;]] .. S("Reply") .. [[] - button[7.25,1.8;2.75,1;replyall;]] .. S("Reply all") .. [[] - button[7.25,2.6;2.75,1;forward;]] .. S("Forward") .. [[] - - 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") .. [[] + button[0,8.5;2,1;reply;]] .. S("Reply") .. [[] + button[2,8.5;2,1;replyall;]] .. S("Reply all") .. [[] + button[4,8.5;2,1;forward;]] .. S("Forward") .. [[] + button[6,8.5;2,1;delete;]] .. S("Delete") .. [[] ]] .. mail.theme - local from = core.formspec_escape(message.from) or "" - local to = core.formspec_escape(message.to) or "" + local from = minetest.formspec_escape(message.from) or "" + local to = minetest.formspec_escape(message.to) or "" if string.len(to) > 70 then to = string.sub(to, 1, 67) .. "..." end - local cc = core.formspec_escape(message.cc) or "" + local cc = minetest.formspec_escape(message.cc) or "" if string.len(cc) > 50 then cc = string.sub(cc, 1, 47) .. "..." end local date = type(message.time) == "number" - and core.formspec_escape(os.date(mail.get_setting(name, "date_format"), - message.time+3600*mail.get_setting(name, "timezone_offset"))) or "" - local subject = core.formspec_escape(message.subject) or "" - local body = core.formspec_escape(message.body) or "" + and minetest.formspec_escape(os.date("%Y-%m-%d %X", message.time)) or "" + local subject = minetest.formspec_escape(message.subject) or "" + local body = minetest.formspec_escape(message.body) or "" formspec = string.format(formspec, from, to, cc, date, subject, body) - if not message.read and mail.get_setting(name, "auto_marking_read") then + if not message.read then -- mark as read mail.mark_read(name, id) end - core.show_formspec(name, FORMNAME, formspec) + minetest.show_formspec(name, FORMNAME, formspec) end function mail.reply(name, message) if not message then -- 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)) + minetest.log("error", "[mail] reply called with nil message for player: " .. name) + minetest.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)) + local replyfooter = "Type your reply here.\n\n--Original message follows--\n" ..message.body + mail.show_compose(name, message.from, "Re: "..message.subject, replyfooter) end function mail.replyall(name, message) 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)) + minetest.log("error", "[mail] replyall called with nil message for player: " .. name) + minetest.log("error", "[mail] current mail-context: " .. dump(mail.selected_idxs)) return end + local replyfooter = "Type your reply here.\n\n--Original message follows--\n" ..message.body + -- new recipients are the sender plus the original recipients, minus ourselves local recipients = message.to or "" if message.from ~= nil then @@ -114,21 +92,30 @@ function mail.replyall(name, message) end cc = mail.concat_player_list(cc) - mail.show_compose(name, recipients, "Re: "..message.subject, interleave_msg(message.body), cc) + mail.show_compose(name, recipients, "Re: "..message.subject, replyfooter, cc) end function mail.forward(name, message) - mail.show_compose(name, "", "Fw: " .. (message.subject or ""), interleave_msg(message.body)) + local fwfooter = "Type your message here.\n\n--Original message follows--\n" .. (message.body or "") + mail.show_compose(name, "", "Fw: " .. (message.subject or ""), fwfooter) end -core.register_on_player_receive_fields(function(player, formname, fields) +minetest.register_on_player_receive_fields(function(player, formname, fields) if formname ~= FORMNAME then return end local name = player:get_player_name() + local entry = mail.get_storage_entry(name) - local message = mail.get_message(name, mail.selected_idxs.message[name]) + local message = "" + if mail.selected_idxs.inbox[name] and mail.selected_idxs.boxtab[name] == 1 then + message = mail.get_message(name, mail.selected_idxs.inbox[name][#mail.selected_idxs.inbox[name]]) + elseif mail.selected_idxs.outbox[name] and mail.selected_idxs.boxtab[name] == 2 then + message = mail.get_message(name, mail.selected_idxs.outbox[name][#mail.selected_idxs.outbox[name]]) + elseif mail.selected_idxs.trash[name] and mail.selected_idxs.boxtab[name] == 4 then + message = mail.get_message(name, entry.trash[mail.selected_idxs.trash[name]].id) + end if fields.back then mail.show_mail_menu(name) @@ -143,22 +130,6 @@ core.register_on_player_receive_fields(function(player, formname, fields) elseif fields.forward then 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 if mail.get_setting(name, "trash_move_enable") and mail.selected_idxs.boxtab[name] ~= 4 then mail.trash_mail(name, message.id) diff --git a/ui/outbox.lua b/ui/outbox.lua index 0a2a146..57b6635 100644 --- a/ui/outbox.lua +++ b/ui/outbox.lua @@ -1,5 +1,5 @@ -- translation -local S = mail.S +local S = minetest.get_translator("mail") function mail.show_outbox(name, sortfieldindex, sortdirection, filter) sortfieldindex = tonumber(sortfieldindex or mail.selected_idxs.sortfield[name]) @@ -13,6 +13,85 @@ function mail.show_outbox(name, sortfieldindex, sortdirection, filter) local sortfield = ({"to","subject","time"})[sortfieldindex] local messages = mail.sort_messages(entry.outbox, sortfield, sortdirection == "2", filter) + local trash_tab = "" + if mail.get_setting(name, "trash_move_enable") then + trash_tab = "," .. S("Trash") + end + + local outbox_formspec = "size[8.5,10;]" .. 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.95;2.5,0.5;read;]] .. S("Read") .. [[] + button[6,1.70;2.5,0.5;reply;]] .. S("Reply") .. [[] + 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.95;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;options;]] .. S("Options") .. [[] + button_exit[6,9.5;2.5,0.5;quit;]] .. S("Close") .. [[] + + dropdown[0,8.5;2,0.5;sortfield;]] .. + S("To") .. "," .. S("Subject") .. "," .. S("Date") .. [[;]] .. sortfieldindex .. [[;true] + dropdown[2.0,8.5;2,0.5;sortdirection;]] .. + S("Ascending") .. "," .. S("Descending") .. [[;]] .. sortdirection .. [[;true] + field[4.25,8.95;1.4,0.5;filter;]] .. S("Filter") .. [[:;]] .. filter .. [[] + button[5.14,8.62;0.85,0.5;search;Q] + + checkbox[0,9.1;multipleselection;]] .. S("Allow multiple selection") .. [[;]] .. + tostring(mail.selected_idxs.multipleselection[name]) .. [[] + label[0,9.65;]] .. S("@1 of @2 selected", tostring(#mail.selected_idxs.outbox[name]), tostring(#messages)) ..[[] + button[3.5,9.5;2.5,0.5;selectall;]] .. S("(Un)select all") .. [[] + + tablecolumns[color;text;text] + table[0,0.7;5.75,7.45;outbox;]] .. mail.colors.header .. "," .. S("To") .. "," .. S("Subject") + local formspec = { outbox_formspec } + + mail.message_drafts[name] = nil + + if #messages > 0 then + for _, message in ipairs(messages) do + local selected_id = 0 + -- check if message is in selection list and return its id + 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 + if message.id == selected_msg then + selected_id = i + break + end + end + end + if selected_id > 0 then + formspec[#formspec + 1] = "," .. mail.colors.selected + else + formspec[#formspec + 1] = "," + end + formspec[#formspec + 1] = "," + if string.len(message.to) > 20 then + formspec[#formspec + 1] = minetest.formspec_escape(string.sub(message.to, 1, 17)) + formspec[#formspec + 1] = "..." + else + formspec[#formspec + 1] = minetest.formspec_escape(message.to) + end + 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 + formspec[#formspec + 1] = S("(No subject)") + end + end + formspec[#formspec + 1] = "]" + else + formspec[#formspec + 1] = "]label[2.25,4.5;" .. S("No mail") .. "]" + end + 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 @@ -28,89 +107,5 @@ function mail.show_outbox(name, sortfieldindex, sortdirection, filter) 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.95;2.5,0.5;read;]] .. S("Read") .. [[] - button[6,1.70;2.5,0.5;reply;]] .. S("Reply") .. [[] - 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.95;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") .. [[] - - 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] - dropdown[2.0,9.5;2,0.5;sortdirection;]] .. - S("Ascending") .. "," .. S("Descending") .. [[;]] .. sortdirection .. [[;true] - field[4.25,9.95;1.4,0.5;filter;]] .. S("Filter") .. [[:;]] .. filter .. [[] - image_button[5.14,9.5;0.85,0.85;search.png;search;] - - checkbox[0,10.1;multipleselection;]] .. S("Allow multiple selection") .. [[;]] .. - tostring(mail.selected_idxs.multipleselection[name]) .. [[] - label[0,10.65;]] .. - 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] - table[0,0.7;5.75,8.45;outbox;]] .. mail.get_color("header") .. "," .. S("To") .. "," .. S("Subject") - local formspec = { outbox_formspec } - - mail.message_drafts[name] = nil - - if #messages > 0 then - for _, message in ipairs(messages) do - local selected_id = 0 - local displayed_color = {} - -- check if message is in selection list and return its id - 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 - if message.id == selected_msg then - selected_id = i - break - end - end - end - if selected_id > 0 then - table.insert(displayed_color, "selected") - end - formspec[#formspec + 1] = "," .. mail.get_color(displayed_color) - formspec[#formspec + 1] = "," - if string.len(message.to) > 20 then - formspec[#formspec + 1] = core.formspec_escape(string.sub(message.to, 1, 17)) - formspec[#formspec + 1] = "..." - else - formspec[#formspec + 1] = core.formspec_escape(message.to) - end - 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 - 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, "")) + minetest.show_formspec(name, "mail:outbox", table.concat(formspec, "")) end diff --git a/ui/receivers.lua b/ui/receivers.lua index 303c47b..af13a7d 100644 --- a/ui/receivers.lua +++ b/ui/receivers.lua @@ -1,5 +1,5 @@ -- translation -local S = core.get_translator("mail") +local S = minetest.get_translator("mail") local FORMNAME = "mail:receivers" @@ -9,7 +9,7 @@ function mail.show_receivers(name, id) local formspec = [[ size[8,6] - box[0,0;7,1.1;]] .. mail.get_color("highlighted") .. [[] + box[0,0;7,1.1;]] .. mail.colors.highlighted .. [[] button[7.25,0.15;0.75,0.5;back;X] @@ -23,28 +23,36 @@ function mail.show_receivers(name, id) table[4,1.5;3.8,4.5;cc;%s] ]] .. mail.theme - local from = core.formspec_escape(message.from) or "" + local from = minetest.formspec_escape(message.from) or "" local to = mail.parse_player_list(message.to or "") - local to_str = mail.get_color("header") .. "," .. S("To") .. ",," + local to_str = mail.colors.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") .. ",," + local cc_str = mail.colors.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 "" + and minetest.formspec_escape(os.date("%Y-%m-%d %X", message.time)) or "" formspec = string.format(formspec, from, date, to_str, cc_str) - core.show_formspec(name, FORMNAME, formspec) + minetest.show_formspec(name, FORMNAME, formspec) end -core.register_on_player_receive_fields(function(player, formname, fields) +minetest.register_on_player_receive_fields(function(player, formname, fields) if formname ~= FORMNAME then return end local name = player:get_player_name() + local entry = mail.get_storage_entry(name) - local message_id = mail.selected_idxs.message[name] + local message_id = "" + if mail.selected_idxs.inbox[name] and mail.selected_idxs.boxtab[name] == 1 then + message_id = mail.selected_idxs.inbox[name][#mail.selected_idxs.inbox[name]] + elseif mail.selected_idxs.outbox[name] and mail.selected_idxs.boxtab[name] == 2 then + message_id = mail.selected_idxs.outbox[name][#mail.selected_idxs.outbox[name]] + elseif mail.selected_idxs.trash[name] and mail.selected_idxs.boxtab[name] == 4 then + message_id = entry.trash[mail.selected_idxs.trash[name]].id + end if fields.back then mail.show_message(name, message_id) diff --git a/ui/select_contact.lua b/ui/select_contact.lua index c7eefda..4253bdf 100644 --- a/ui/select_contact.lua +++ b/ui/select_contact.lua @@ -1,19 +1,19 @@ -- translation -local S = mail.S +local S = minetest.get_translator("mail") local FORMNAME = "mail:selectcontact" local select_contact_formspec = "size[8,9;]" .. mail.theme .. [[ tablecolumns[color;text;text] - table[0,0;3.5,9;contacts;]] .. mail.get_color("header") .. "," .. S("Name") .. "," .. S("Note") .. [[%s] + table[0,0;3.5,9;contacts;]] .. mail.colors.header .. "," .. S("Name") .. "," .. S("Note") .. [[%s] 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,6.00;1.75,0.5;ccadd;→ ]] .. S("Add") .. [[] button[3.55,6.75;1.75,0.5;ccremove;← ]] .. S("Remove") .. [[] tablecolumns[color;text;text] - table[5.15,0.0;2.75,4.5;to;]] .. mail.get_color("header") .. "," .. S("To") .. ":," .. S("Note") .. [[%s] + table[5.15,0.0;2.75,4.5;to;]] .. mail.colors.header .. "," .. S("To") .. ":," .. S("Note") .. [[%s] tablecolumns[color;text;text] - table[5.15,4.6;2.75,4.5;cc;]] .. mail.get_color("header") .. "," .. S("CC") .. ":," .. S("Note") .. [[%s] + table[5.15,4.6;2.75,4.5;cc;]] .. mail.colors.header .. "," .. S("CC") .. ":," .. S("Note") .. [[%s] 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 = "" end]]-- formspec = string.format(formspec, contacts, to, cc)--, bcc() - core.show_formspec(name, FORMNAME, formspec) + minetest.show_formspec(name, FORMNAME, formspec) end -core.register_on_player_receive_fields(function(player, formname, fields) +minetest.register_on_player_receive_fields(function(player, formname, fields) if formname ~= FORMNAME then return end @@ -60,7 +60,7 @@ core.register_on_player_receive_fields(function(player, formname, fields) bcc = "bccremove" }) do if fields[k] then - local evt = core.explode_table_event(fields[k]) + local evt = minetest.explode_table_event(fields[k]) mail.selected_idxs[k][name] = evt.row - 1 if evt.type == "DCL" and mail.selected_idxs[k][name] then fields[action] = true @@ -75,7 +75,7 @@ core.register_on_player_receive_fields(function(player, formname, fields) if fields[v.."add"] then update = true if mail.selected_idxs.contacts[name] then - for k, contact, i in mail.pairs_by_keys(contacts) do + for k, contact, i in mail.pairsByKeys(contacts) do if k == mail.selected_idxs.contacts[name] or i == mail.selected_idxs.contacts[name] then local list = mail.parse_player_list(draft[v]) list[#list+1] = contact.name diff --git a/ui/settings.lua b/ui/settings.lua index a7b2c64..faf22b5 100644 --- a/ui/settings.lua +++ b/ui/settings.lua @@ -1,241 +1,63 @@ -- translation -local S = mail.S +local S = minetest.get_translator("mail") 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] + tabheader[0.3,1;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.8;3,0.45;]] .. mail.colors.highlighted .. [[] + label[0.2,0.8;]] .. S("Notifications") .. [[] + checkbox[0,1.2;chat_notifications;]] .. S("Chat notifications") .. [[;]] .. + tostring(mail.get_setting(name, "chat_notifications")) .. [[] + checkbox[0,1.6;onjoin_notifications;]] .. S("On join notifications") .. [[;]] .. + tostring(mail.get_setting(name, "onjoin_notifications")) .. [[] + checkbox[0,2.0;hud_notifications;]] .. S("HUD notifications") .. [[;]] .. + tostring(mail.get_setting(name, "hud_notifications")) .. [[] + checkbox[0,2.4;sound_notifications;]] .. S("Sound notifications") .. [[;]] .. + tostring(mail.get_setting(name, "sound_notifications")) .. [[] - box[0,0;3,0.45;]] .. mail.get_color("highlighted") .. [[] - label[0.2,0;]] .. mail.settings_groups[group_index].label .. [[] + box[5,0.8;3,0.45;]] .. mail.colors.highlighted .. [[] + label[5.2,0.8;]] .. S("Message list") .. [[] + checkbox[5,1.2;unreadcolorenable;]] .. S("Show unread in different color") .. [[;]] .. + tostring(mail.get_setting(name, "unreadcolorenable")) .. [[] + checkbox[5,1.6;cccolorenable;]] .. S("Show CC/BCC in different color") .. [[;]] .. + tostring(mail.get_setting(name, "cccolorenable")) .. [[] - button[0,5.65;2.5,0.5;reset;]] .. S("Reset") .. [[] - button[7.5,5.65;2.5,0.5;save;]] .. S("Save") .. [[] - ]] + label[5,2.6;]] .. S("Default sorting fields") .. [[] + dropdown[5.5,3.0;2,0.5;defaultsortfield;]] .. + S("From/To") .. "," .. S("Subject") .. "," .. S("Date") .. [[;]] .. + tostring(mail.get_setting(name, "defaultsortfield")) .. [[;true] + dropdown[7.5,3.0;2,0.5;defaultsortdirection;]] .. + S("Ascending") .. "," .. S("Descending") .. [[;]] .. + tostring(mail.get_setting(name, "defaultsortdirection")) .. [[;true] - 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, ",,") .. "]" + box[0,3.2;3,0.45;]] .. mail.colors.highlighted .. [[] + label[0.2,3.2;]] .. S("Other") .. [[] + checkbox[0,3.6;trash_move_enable;]] .. S("Move deleted messages to trash") .. [[;]] .. + tostring(mail.get_setting(name, "trash_move_enable")) .. [[] - 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 .. [[;-] - ]] + button[0,5.5;2.5,0.5;save;]] .. S("Save") .. [[] + button[2.7,5.5;2.5,0.5;reset;]] .. S("Reset") .. [[] + ]] .. mail.theme - 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) + minetest.show_formspec(name, FORMNAME, formspec) end -core.register_on_player_receive_fields(function(player, formname, fields) +minetest.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 @@ -244,14 +66,41 @@ core.register_on_player_receive_fields(function(player, formname, fields) mail.show_about(playername) return + elseif fields.chat_notifications then + mail.selected_idxs.chat_notifications[playername] = fields.chat_notifications == "true" + + elseif fields.onjoin_notifications then + mail.selected_idxs.onjoin_notifications[playername] = fields.onjoin_notifications == "true" + + elseif fields.hud_notifications then + mail.selected_idxs.hud_notifications[playername] = fields.hud_notifications == "true" + + elseif fields.sound_notifications then + mail.selected_idxs.sound_notifications[playername] = fields.sound_notifications == "true" + + elseif fields.unreadcolorenable then + mail.selected_idxs.unreadcolorenable[playername] = fields.unreadcolorenable == "true" + + elseif fields.cccolorenable then + mail.selected_idxs.cccolorenable[playername] = fields.cccolorenable == "true" + + elseif fields.trash_move_enable then + mail.selected_idxs.trash_move_enable[playername] = fields.trash_move_enable == "true" + 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 + -- checkboxes + mail.set_setting(playername, "chat_notifications", mail.selected_idxs.chat_notifications[playername]) + mail.set_setting(playername, "onjoin_notifications", mail.selected_idxs.onjoin_notifications[playername]) + mail.set_setting(playername, "hud_notifications", mail.selected_idxs.hud_notifications[playername]) + mail.set_setting(playername, "sound_notifications", mail.selected_idxs.sound_notifications[playername]) + mail.set_setting(playername, "unreadcolorenable", mail.selected_idxs.unreadcolorenable[playername]) + mail.set_setting(playername, "cccolorenable", mail.selected_idxs.cccolorenable[playername]) + mail.set_setting(playername, "trash_move_enable", mail.selected_idxs.trash_move_enable[playername]) + -- dropdowns + local defaultsortfield = fields.defaultsortfield or mail.get_setting("defaultsortfield") + local defaultsortdirection = fields.defaultsortdirection or mail.get_setting("defaultsortdirection") + mail.set_setting(playername, "defaultsortfield", tonumber(defaultsortfield)) + mail.set_setting(playername, "defaultsortdirection", tonumber(defaultsortdirection)) -- update visuals mail.hud_update(playername, mail.get_storage_entry(playername).inbox) mail.show_settings(playername) @@ -259,6 +108,6 @@ core.register_on_player_receive_fields(function(player, formname, fields) elseif fields.reset then mail.reset_settings(playername) mail.show_settings(playername) - end + end return end) diff --git a/ui/trash.lua b/ui/trash.lua index 5508846..7601fba 100644 --- a/ui/trash.lua +++ b/ui/trash.lua @@ -1,7 +1,7 @@ -- translation -local S = mail.S +local S = minetest.get_translator("mail") -local trash_formspec = "size[8.5,11;]" .. mail.theme .. [[ +local trash_formspec = "size[8.5,10;]" .. mail.theme .. [[ tabheader[0.3,1;boxtab;]] .. S("Inbox") .. "," .. S("Outbox").. "," .. S("Drafts") .. "," .. S("Trash") .. [[;4;false;false] @@ -10,13 +10,13 @@ local trash_formspec = "size[8.5,11;]" .. mail.theme .. [[ 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") .. [[] + 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;options;]] .. S("Options") .. [[] + button_exit[6,9.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") + table[0,0.7;5.75,9.35;trash;]] .. mail.colors.header .. "," .. S("From/To") .. "," .. S("Subject") function mail.show_trash(name) @@ -28,14 +28,14 @@ function mail.show_trash(name) for _, message in ipairs(messages) do formspec[#formspec + 1] = "," formspec[#formspec + 1] = "," - formspec[#formspec + 1] = core.formspec_escape(message.to) + formspec[#formspec + 1] = minetest.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] = minetest.formspec_escape(string.sub(message.subject, 1, 27)) formspec[#formspec + 1] = "..." else - formspec[#formspec + 1] = core.formspec_escape(message.subject) + formspec[#formspec + 1] = minetest.formspec_escape(message.subject) end else formspec[#formspec + 1] = S("(No subject)") @@ -49,5 +49,5 @@ function mail.show_trash(name) else formspec[#formspec + 1] = "]label[2.25,4.5;" .. S("Trash is empty") .. "]" end - core.show_formspec(name, "mail:trash", table.concat(formspec, "")) + minetest.show_formspec(name, "mail:trash", table.concat(formspec, "")) end diff --git a/util/colors.lua b/util/colors.lua deleted file mode 100644 index fa39af6..0000000 --- a/util/colors.lua +++ /dev/null @@ -1,58 +0,0 @@ -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 diff --git a/util/contact.lua b/util/contact.lua index 25c5db9..ff7c9c5 100644 --- a/util/contact.lua +++ b/util/contact.lua @@ -1,5 +1,3 @@ --- 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) @@ -8,11 +6,11 @@ function mail.compile_contact_list(name, selected, playernames) if playernames == nil then local length = 0 - for k, contact, i, l in mail.pairs_by_keys(contacts) do + 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] = core.formspec_escape(contact.name) + formspec[#formspec + 1] = minetest.formspec_escape(contact.name) formspec[#formspec + 1] = "," local note = contact.note -- display an ellipsis if the note spans multiple lines @@ -20,7 +18,7 @@ function mail.compile_contact_list(name, selected, playernames) if idx ~= nil then note = string.sub(note, 1, idx-1) .. ' ...' end - formspec[#formspec + 1] = core.formspec_escape(note) + formspec[#formspec + 1] = minetest.formspec_escape(note) if type(selected) == "string" then if string.lower(selected) == k then selected = i @@ -34,7 +32,7 @@ function mail.compile_contact_list(name, selected, playernames) end formspec[#formspec + 1] = "]" else - formspec[#formspec + 1] = "]label[2,4.5;" .. S("No contacts") .. "]" + formspec[#formspec + 1] = "]label[2,4.5;No contacts]" end else if type(playernames) == "string" then @@ -43,7 +41,7 @@ function mail.compile_contact_list(name, selected, playernames) for i,c in ipairs(playernames) do formspec[#formspec + 1] = "," formspec[#formspec + 1] = "," - formspec[#formspec + 1] = core.formspec_escape(c) + formspec[#formspec + 1] = minetest.formspec_escape(c) formspec[#formspec + 1] = "," if contacts[string.lower(c)] == nil then formspec[#formspec + 1] = "" @@ -54,7 +52,7 @@ function mail.compile_contact_list(name, selected, playernames) if idx ~= nil then note = string.sub(note, 1, idx-1) .. ' ...' end - formspec[#formspec + 1] = core.formspec_escape(note) + formspec[#formspec + 1] = minetest.formspec_escape(note) end if not selected then if type(selected) == "string" then @@ -72,4 +70,4 @@ function mail.compile_contact_list(name, selected, playernames) end return table.concat(formspec, "") -end +end \ No newline at end of file diff --git a/util/init.lua b/util/init.lua deleted file mode 100644 index ce916a6..0000000 --- a/util/init.lua +++ /dev/null @@ -1,9 +0,0 @@ --- 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") diff --git a/util/normalize.lua b/util/normalize.lua index 4585bd5..b817068 100644 --- a/util/normalize.lua +++ b/util/normalize.lua @@ -1,44 +1,18 @@ --- 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 +local has_canonical_name = minetest.get_modpath("canonical_name") --[[ return the field normalized (comma separated, single space) and add individual player names to recipient list --]] -function mail.normalize_players_and_add_recipients(sender, field, recipients, undeliverable) +function mail.normalize_players_and_add_recipients(field, recipients, undeliverable) local order = mail.parse_player_list(field) - recursive_expand_recipient_names(sender, order, true, recipients, undeliverable) + for _, recipient_name in ipairs(order) do + 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) end @@ -47,23 +21,29 @@ function mail.parse_player_list(field) return {} end - local separator = ",%s" + local separator = ", " local pattern = "([^" .. separator .. "]+)" -- get individual players + local player_set = {} local order = {} - for name in field:gmatch(pattern) do - table.insert(order, name) - end + field:gsub(pattern, function(player_name) + local lower = string.lower(player_name) + if not player_set[lower] then + 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 end function mail.concat_player_list(order) -- turn list of players back into normalized string - if order == nil or #order == 0 then - return "" - end return table.concat(order, ", ") end diff --git a/util/normalize.spec.lua b/util/normalize.spec.lua index b9caa0f..88628ad 100644 --- a/util/normalize.spec.lua +++ b/util/normalize.spec.lua @@ -2,11 +2,11 @@ mtt.register("util/normalize_players_and_add_recipients", function(callback) local recipients = {} local undeliverable = {} - local to = mail.normalize_players_and_add_recipients("sender", "player1,player2", recipients, undeliverable) + local to = mail.normalize_players_and_add_recipients("player1,player2", recipients, undeliverable) assert(to == "player1, player2") assert(not next(undeliverable)) assert(recipients["player1"]) assert(recipients["player2"]) callback() -end) +end) \ No newline at end of file diff --git a/util/settings.lua b/util/settings.lua deleted file mode 100644 index c666ae9..0000000 --- a/util/settings.lua +++ /dev/null @@ -1,113 +0,0 @@ --- 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 diff --git a/util/spam.lua b/util/spam.lua deleted file mode 100644 index dd8913a..0000000 --- a/util/spam.lua +++ /dev/null @@ -1,39 +0,0 @@ -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 diff --git a/util/time_ago.lua b/util/time_ago.lua deleted file mode 100644 index 0fc2c3e..0000000 --- a/util/time_ago.lua +++ /dev/null @@ -1,29 +0,0 @@ --- 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