Compare commits

..

18 Commits

Author SHA1 Message Date
Athozus
8a992b7a29
Bump version to 1.5.0-dev in about.lua 2024-09-01 16:41:39 +02:00
Maksym H.
1bffd98132 Localize get_translator call 2024-09-01 16:36:55 +02:00
Athozus
59667bd35c
Add 5.9.0 to workflows 2024-08-12 00:33:36 +02:00
Athozus
09b233b039
Update credits and bump to version 1.4.1
Some checks are pending
luacheck / luacheck (push) Waiting to run
test / build (5.8.0) (push) Waiting to run
test / build (latest) (push) Waiting to run
test / build (5.0.1) (push) Waiting to run
test / build (5.1.1) (push) Waiting to run
test / build (5.2.0) (push) Waiting to run
test / build (5.3.0) (push) Waiting to run
test / build (5.4.1) (push) Waiting to run
test / build (5.5.1) (push) Waiting to run
test / build (5.6.1) (push) Waiting to run
test / build (5.7.0) (push) Waiting to run
2024-08-09 00:35:42 +02:00
Athozus
b9982f11e6
Add support for a get_keys() equivalent for lower than 5.7 Minetest versions (#153)
* Add support for a get_keys() equivalent for lower than 5.7 Minetest versions

* Do not call the function itself to check if it exists

Co-authored-by: luk3yx <luk3yx@users.noreply.github.com>

* Do not call the function itself to check if it exists (2)

Co-authored-by: luk3yx <luk3yx@users.noreply.github.com>

* Fix an occurrence of get_keys() in is_uuid_existing()

---------

Co-authored-by: luk3yx <luk3yx@users.noreply.github.com>
2024-08-09 00:31:28 +02:00
Athozus
4f15c2fe65
Update version to 1.4.1-dev in about.lua 2024-08-06 02:26:10 +02:00
1F616EMO
4cd06c5f5f Optimize performance of the inbox
Moves the `mail.get_setting(name, "mute_list")` call out of the message loop. Previously, this is called repeated, causing disastrous lag when using mail with beerchat.
2024-08-06 02:21:20 +02:00
Athozus
036d37695a
Update files to 1.4 (#149)
* Update README and screenshots

* Update version number in about.lua
2024-08-05 17:23:01 +02:00
Athozus
5cfec3a92a
Update api.md docs (#148)
* Update player entry format in API documentation

* Add spam flag
2024-08-05 17:01:20 +02:00
Athozus
a347a79e6a
Update actions workflows 2024-08-05 16:59:51 +02:00
Niklp
48b632fba2
Update German translations (#147) 2024-04-20 23:35:32 +02:00
Athozus
2938b74039
Update translation files 2024-04-20 18:23:52 +02:00
Athozus
ed6f36ab6d Move date and time settings to a sub-group of Other 2024-04-20 17:41:59 +02:00
Athozus
1dab26f0bf Add timezone offset setting
Clarify timezone offset tooltip

Co-authored-by: y5nw <37980625+y5nw@users.noreply.github.com>
2024-04-20 17:41:59 +02:00
Athozus
9a52c1c181 Add support for number type settings
Fix reset issue
2024-04-20 17:41:59 +02:00
Athozus
19be2d46a2 Move sorting fields settings to new Fields settings group 2024-04-20 17:30:42 +02:00
Athozus
dc9c4f86b7 Add support for tree-hierarchized settings groups
Compute once the ordered settings groups list
2024-04-20 17:30:42 +02:00
Athozus
1f208c6a21 Add table.insert_all() to luacheck 2024-04-20 17:30:42 +02:00
39 changed files with 493 additions and 392 deletions

View File

@ -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, latest]
ENGINE_VERSION: [5.0.1, 5.1.1, 5.2.0, 5.3.0, 5.4.1, 5.5.1, 5.6.1, 5.7.0, 5.8.0, 5.9.0, latest]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: test
run: docker-compose up --exit-code-from sut
run: docker compose up --exit-code-from sut

View File

@ -5,7 +5,7 @@ globals = {
read_globals = {
-- Stdlib
string = {fields = {"split"}},
table = {fields = {"copy", "getn", "indexof"}},
table = {fields = {"copy", "getn", "indexof", "insert_all"}},
beerchat = {fields = {"has_player_muted_player", "execute_callbacks"}},
-- Minetest

View File

@ -11,7 +11,8 @@ It adds a mail-system that allows players to send each other messages in-game an
# Screenshot
![](screenshot_1.2.0.png)
![Main view](screenshot_1.4.0_1.png)
![Message view](screenshot_1.4.0_2.png)
# Installation
@ -43,7 +44,8 @@ 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
* Translated in : English, French, German, Chinese (both traditional and simplified), Spanish, Brazilian Portuguese.
* Anti-spam detection
* Translated in : English, French, German, Chinese (both traditional and simplified), Spanish, Brazilian Portuguese, Hungarian, Indonesian.
# Compatibility / Migration
@ -51,8 +53,10 @@ Overview:
* `v1` all the data is in the `<worldfolder>/mails.db` file
* `v2` every player has its own (in-) mailbox in the `<worldfolder>/mails/<playername>.json` file
* `v3` every player has an entry in the `<playername>` `mod_storage/` (inbox, outbox, drafts, contacts, mailing lists, settings)
* `v3.1` database fix after the message id mess
# Dependencies
* None
# License
@ -72,7 +76,7 @@ See the "LICENSE" file
* fluxionary (Minor fixups)
* Toby1710 (UX fixes)
* Peter Nerlich (CC, BCC)
* Emojigit (Traditional Chinese translation)
* Emojigit (Performance, Traditional Chinese translation)
* Niklp09 (German translation)
* Dennis Jenkins (UX fixes)
* Thomas Rudin (Maintenance)
@ -84,7 +88,12 @@ See the "LICENSE" file
* 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

View File

@ -1,7 +1,7 @@
-- see: mail.md
-- translation
local S = minetest.get_translator("mail")
local S = mail.S
local f = string.format

17
api.md
View File

@ -1,4 +1,3 @@
# Mail format
The mail format in the api hooks
@ -70,6 +69,7 @@ The recipient handler should return
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,7 +99,9 @@ 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
read = true,
-- spam-flag (true: that mail is noted as a spam)
spam = false
},{
...
}
@ -107,6 +109,12 @@ 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)
@ -116,5 +124,10 @@ 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
}
}

View File

@ -1,4 +1,4 @@
version: "3.6"
version: "4.1"
services:
sut:
@ -16,4 +16,4 @@ services:
- "30000:30000/udp"
volumes:
world_data: {}
world_data: {}

View File

@ -5,6 +5,9 @@ mail = {
-- mod storage
storage = minetest.get_mod_storage(),
-- translation
S = minetest.get_translator(minetest.get_current_modname()),
-- ui theme prepend
theme = "",

View File

@ -1,16 +1,24 @@
# textdomain: mail
The mail could not be sent:=
You have mail! Type /mail to read=Sie haben Post! „/mail“ eingeben zum Lesen
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=Version
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 Spieler sehen.
Admins are able to view the messages of any player.=Admins können die Nachrichten aller Spielenden sehen.
Contributors=Mitwirkende
Group by name=Nach Name gruppieren
Group by contribution=Nach Beitrag gruppieren
Note=Anmerkung
Settings=Einstellungen
About=Über
@ -29,7 +37,7 @@ Name=Name
No drafts=Keine Entwürfe
Trash=Papierkorb
Inbox=Posteingang
Outbox=Senden
Outbox=Gesendet
Drafts=Entwürfe
Contacts=Kontakte
Mail lists=Verteilerlisten
@ -47,14 +55,14 @@ That name is already in your mailing lists.=Dieser Name ist bereits in Ihren Ver
The mailing list name cannot be empty.=Der Verteilerlistenname kann nicht leer sein.
Mark Read=Als gelesen makieren
Mark Unread=Als ungelesen makieren
Mark Spam=
Unmark Spam=
Mark Spam=Als Spam markieren
Unmark Spam=Kein Spam
Reply=Antworten
Reply all=Allen antworten
Forward=Weiterleiten
Reply only to the sender=
Reply to all involved people=
Transfer message to other people=
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
@ -68,7 +76,7 @@ Descending=Absteigend
(No description)=(Keine Beschreibung)
No maillist=Keine Verteilerliste
Receivers=Empfänger
(Un)mute sender=
(Un)mute sender=Absender stummschalten/entstummen
Add=Hinzufügen
Remove=Entfernen
Reset=Zurücksetzen
@ -77,30 +85,34 @@ Empty=Leer
Trash is empty=Papierkorb ist leer
From/To=Von/An
No contacts=Keine Kontakte
The method of delivery to @1 is invalid.=
The recipient @1 could not be identified.=
@1 rejected your mail.=
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=
On join notifications=Bei-Eintritt-Benachrichtigungen
Receive a message at login when inbox isn't empty=
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=
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=
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=
Default sorting direction=Standardmäßige Sortierrichtung
Move deleted messages to trash=Gelöschte Nachrichten in den Papierkorb verschieben
Automatic marking read=
Mark a message as read when opened=
Automatic marking read=Automatisch als gelesen markieren
Mark a message as read when opened=Nachrichten beim Öffnen als gelesen markieren
Date format=Datumsformat
Mute list=
Timezone offset=Zeitverschiebung
Offset to add to server time.=Verschiebung, die zur Serverzeit addiert wird.
Mute list=Stummgeschaltet-Liste
Notifications=Benachrichtigungen
Message list=Nachrichtenliste
Spam=
Fields=Felder
Spam=Spam
Other=Anderes
Date and Time=Datum und Uhrzeit
years=Jahren
months=Monaten
weeks=Wochen

View File

@ -1,16 +1,24 @@
# 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=Versión
Version: @1=
Licenses=Licencias
Expat (code), WTFPL (textures)=Expat (código), WTFPL (texturas)
Communication using this system is NOT guaranteed to be private!=¡NO se garantiza que la comunicación mediante este sistema sea privada!
Admins are able to view the messages of any player.=Los administradores pueden ver los mensajes de cualquier jugador.
Contributors=Colaboradores
Group by name=
Group by contribution=
Note=Nota
Settings=Ajustes
About=Acerca de
@ -96,11 +104,15 @@ 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
@ -109,3 +121,8 @@ hours=horas
minuts=minutos
seconds=segundos
@1 ago=hace @1
##### not used anymore #####
Version=Versión

View File

@ -1,16 +1,24 @@
# 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=Version
Version: @1=Version : @1
Licenses=Licences
Expat (code), WTFPL (textures)=Expat (code), WTFPL (textures)
Communication using this system is NOT guaranteed to be private!=La communication par ce système n'est pas garantie d'être privée !
Admins are able to view the messages of any player.=Les administrateurs peuvent voir les messages de chaque joueur.
Contributors=Contributeurs
Group by name=Grouper par nom
Group by contribution=Grouper par contribution
Note=Note
Settings=Paramètres
About=À propos
@ -96,11 +104,15 @@ 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

View File

@ -1,16 +1,24 @@
# 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=Verzió
Version: @1=
Licenses=License
Expat (code), WTFPL (textures)=Expat (kód), WTFPL (textúrák)
Communication using this system is NOT guaranteed to be private!=A systemben lévő komunikáció nem garantáltan privát!
Admins are able to view the messages of any player.=Az adminok megtudják nézni minden játékos üzenetjét.
Contributors=Közreműködöttek
Group by name=
Group by contribution=
Note=Jegyzet
Settings=Beállítások
About=Róla
@ -96,11 +104,15 @@ 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=
@ -109,3 +121,8 @@ hours=
minuts=
seconds=
@1 ago=
##### not used anymore #####
Version=Verzió

View File

@ -1,16 +1,24 @@
# 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=Versi
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
@ -96,11 +104,15 @@ 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
@ -109,3 +121,8 @@ hours=jam
minuts=menit
seconds=detik
@1 ago=@1 yang lalu
##### not used anymore #####
Version=Versi

View File

@ -1,16 +1,24 @@
# 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=
Version: @1=
Licenses=
Expat (code), WTFPL (textures)=
Communication using this system is NOT guaranteed to be private!=A comunicação usando este sistema não possui garantia de privacidade
Admins are able to view the messages of any player.=Administradores poderão ler as mensagens de qualquer jogador
Contributors=
Group by name=
Group by contribution=
Note=Nota
Settings=Ajustes
About=Sobre
@ -96,11 +104,15 @@ 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=

View File

@ -1,16 +1,24 @@
# 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=版本
Version: @1=
Licenses=许可证
Expat (code), WTFPL (textures)=Expat代码WTFPL材质
Communication using this system is NOT guaranteed to be private!=这个系统不适用于私密沟通!
Admins are able to view the messages of any player.=管理员可以查看所有玩家的邮件。
Contributors=贡献者
Group by name=
Group by contribution=
Note=备注
Settings=设置
About=关于
@ -97,11 +105,15 @@ 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=周
@ -110,3 +122,8 @@ hours=小时
minuts=分钟
seconds=秒
@1 ago=@1前
##### not used anymore #####
Version=版本

View File

@ -1,16 +1,24 @@
# 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=版本
Version: @1=
Licenses=許可證
Expat (code), WTFPL (textures)=Expat源碼WTFPL材質
Communication using this system is NOT guaranteed to be private!=此系統不適合私密交流!
Admins are able to view the messages of any player.=管理員可以查看所有玩家的郵件。
Contributors=貢獻者
Group by name=
Group by contribution=
Note=備註
Settings=設置
About=關於
@ -96,11 +104,15 @@ 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=周
@ -109,3 +121,8 @@ hours=小時
minuts=分鐘
seconds=秒
@1 ago=@1前
##### not used anymore #####
Version=版本

View File

@ -1,16 +1,24 @@
# 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=
Version: @1=
Licenses=
Expat (code), WTFPL (textures)=
Communication using this system is NOT guaranteed to be private!=
Admins are able to view the messages of any player.=
Contributors=
Group by name=
Group by contribution=
Note=
Settings=
About=
@ -96,11 +104,15 @@ 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=

View File

@ -91,17 +91,29 @@ local function search_box(playername, box, uuid)
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)
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
local boxes = {"inbox", "outbox", "drafts", "trash"}
for _, b in ipairs(boxes) do
result = search_box(p, b, 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 minetest.get_auth_handler().iterate() do
local result = search_boxes(p, boxes, uuid)
if result then return result end
end
end
return false
end
@ -116,55 +128,78 @@ local function are_message_sames(a, b)
and a.body == b.body
end
local function fix_duplicate_uuids(playername, box)
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
for _, k in ipairs(mail.storage:get_keys()) do
if string.sub(k,1,5) == "mail/" then
local p = string.sub(k, 6)
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
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
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
else
for p, _ in minetest.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
for _, k in ipairs(mail.storage:get_keys()) do
if string.sub(k,1,5) == "mail/" then
local p = string.sub(k, 6)
fix_duplicate_uuids(p, "inbox")
fix_duplicate_uuids(p, "outbox")
fix_duplicate_uuids(p, "drafts")
fix_duplicate_uuids(p, "trash")
-- 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
minetest.after(0, function()
for p, _ in minetest.get_auth_handler().iterate() do
fix_player_duplicate_uuids(p)
end
end)
end
end

View File

@ -1,5 +1,5 @@
-- translation
local S = minetest.get_translator("mail")
local S = mail.S
minetest.register_on_joinplayer(function(player)
minetest.after(2, function(name)

View File

@ -1,4 +1,6 @@
local S = minetest.get_translator("mail")
-- translation
local S = mail.S
local has_canonical_name = minetest.get_modpath("canonical_name")
mail.register_on_player_receive(function(name, msg)

BIN
screenshot_1.4.0_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 722 KiB

BIN
screenshot_1.4.0_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 KiB

View File

@ -1,5 +1,5 @@
-- translation
local S = minetest.get_translator("mail")
local S = mail.S
local FORMNAME = "mail:about"
@ -19,7 +19,7 @@ local contributors = {
{ name = "BuckarooBanzay", groups = {"c"} },
{ name = "Chache", groups = {"i"} },
{ name = "Dennis Jenkins", groups = {"c"} },
{ name = "Emojigit", groups = {"i"} },
{ name = "Emojigit", groups = {"c", "i"} },
{ name = "Eredin", groups = {"i"} },
{ name = "fluxionary", groups = {"c"} },
{ name = "imre84", groups = {"c"} },
@ -55,7 +55,7 @@ function mail.show_about(name)
label[0.2,0;Mail]
label[0.2,0.5;]] .. S("Provided by mt-mods") .. [[]
label[0.2,0.9;]] .. S("Version: @1", "1.4.0-dev") .. [[]
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") .. [[]

View File

@ -1,5 +1,5 @@
-- translation
local S = minetest.get_translator("mail")
local S = mail.S
local FORMNAME = "mail:compose"

View File

@ -1,5 +1,5 @@
-- translation
local S = minetest.get_translator("mail")
local S = mail.S
local FORMNAME = "mail:contacts"

View File

@ -1,34 +1,8 @@
-- translation
local S = minetest.get_translator("mail")
local S = mail.S
function mail.show_drafts(name, sortfieldindex, sortdirection, filter)
sortfieldindex = tonumber(sortfieldindex or mail.selected_idxs.sortfield[name])
or mail.get_setting(name, "defaultsortfield") or 3
sortdirection = tostring(sortdirection or mail.selected_idxs.sortdirection[name]
or mail.get_setting(name, "defaultsortdirection") or "1")
filter = filter or mail.selected_idxs.filter[name] or ""
mail.selected_idxs.drafts[name] = mail.selected_idxs.drafts[name] or {}
local entry = mail.get_storage_entry(name)
local sortfield = ({"from","subject","time"})[sortfieldindex]
local messages = mail.sort_messages(entry.drafts, sortfield, sortdirection == "2", filter)
if mail.selected_idxs.drafts[name] and #mail.selected_idxs.drafts[name] > 0 then
for i, selected_msg in ipairs(mail.selected_idxs.drafts[name]) do
local is_present = false
for _, msg in ipairs(messages) do
if msg.id == selected_msg then
is_present = true
break
end
end
if not is_present then
table.remove(mail.selected_idxs.drafts[name], i)
end
end
end
local trash_tab = ""
function mail.show_drafts(name)
local trash_tab = ""
if mail.get_setting(name, "trash_move_enable") then
trash_tab = "," .. S("Trash")
end
@ -45,66 +19,39 @@ function mail.show_drafts(name, sortfieldindex, sortdirection, filter)
button[6,9.7;2.5,0.5;options;]] .. S("Options") .. [[]
button_exit[6,10.5;2.5,0.5;quit;]] .. S("Close") .. [[]
dropdown[0,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.drafts[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;drafts;]] .. mail.get_color("header") .. "," .. S("To") .. "," .. S("Subject")
table[0,0.7;5.75,10.35;drafts;]] .. mail.get_color("header") .. "," .. S("To") .. "," .. S("Subject")
local formspec = { drafts_formspec }
local entry = mail.get_storage_entry(name)
local messages = entry.drafts
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.drafts[name] and #mail.selected_idxs.drafts[name] > 0 then
for i, selected_msg in ipairs(mail.selected_idxs.drafts[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] = minetest.formspec_escape(string.sub(message.to, 1, 17))
formspec[#formspec + 1] = "..."
if messages[1] then
for _, message in ipairs(messages) do
formspec[#formspec + 1] = ","
formspec[#formspec + 1] = ","
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] = 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] = minetest.formspec_escape(message.to)
formspec[#formspec + 1] = S("(No subject)")
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
end
if mail.selected_idxs.drafts[name] then
formspec[#formspec + 1] = ";"
formspec[#formspec + 1] = tostring(mail.selected_idxs.drafts[name] + 1)
end
formspec[#formspec + 1] = "]"
else
formspec[#formspec + 1] = "]label[2.25,4.5;" .. S("No drafts") .. "]"
end
minetest.show_formspec(name, "mail:drafts", table.concat(formspec, ""))
end

View File

@ -1,5 +1,5 @@
-- translation
local S = minetest.get_translator("mail")
local S = mail.S
local FORMNAME = "mail:editcontact"

View File

@ -1,5 +1,5 @@
-- translation
local S = minetest.get_translator("mail")
local S = mail.S
local FORMNAME = "mail:editmaillist"

View File

@ -24,8 +24,6 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
return true
end
local boxes = {"inbox", "outbox", "drafts", "trash"}
-- Get player name and handle / convert common input fields
local name = player:get_player_name()
local filter = (fields.search and fields.filter) or mail.selected_idxs.filter[name] or ""
@ -34,10 +32,9 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
local inboxsortfield = ({"from","subject","time"})[sortfieldindex]
local outboxsortfield = ({"to","subject","time"})[sortfieldindex]
-- Be sure that selected idxs aren't nil
for _, b in ipairs(boxes) do
mail.selected_idxs[b][name] = mail.selected_idxs[b][name] or {}
end
-- Be sure that inbox/outbox selected idxs aren't nil
mail.selected_idxs.inbox[name] = mail.selected_idxs.inbox[name] or {}
mail.selected_idxs.outbox[name] = mail.selected_idxs.outbox[name] or {}
-- Store common player configuration for reuse
mail.selected_idxs.sortfield[name] = sortfieldindex
@ -49,17 +46,16 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
-- Avoid several selected after disabling the multiple selection
if not mail.selected_idxs.multipleselection[name] then
for _, b in ipairs(boxes) do
mail.selected_idxs[b][name] = { mail.selected_idxs[b][name][#mail.selected_idxs[b][name]] }
end
mail.selected_idxs.inbox[name] = { mail.selected_idxs.inbox[name][#mail.selected_idxs.inbox[name]] }
mail.selected_idxs.outbox[name] = { mail.selected_idxs.outbox[name][#mail.selected_idxs.outbox[name]] }
end
-- split inbox and outbox msgs for different tests
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 getDrafts = message_getter(entry.drafts, inboxsortfield, sortdirection == "2", filter)
local getTrash = message_getter(entry.trash, outboxsortfield, sortdirection == "2", filter)
-- Hanmdle formspec event
if fields.inbox then -- inbox table
@ -162,44 +158,18 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
mail.selected_idxs.sortfield[name] = evt.column-1 -- update column
mail.show_mail_menu(name)
return true
return
end
local drafts = getDrafts()[evt.row-1]
if not drafts then
mail.show_mail_menu(name)
return true
end
if mail.selected_idxs.multipleselection[name] then
if not mail.selected_idxs.drafts[name] then
mail.selected_idxs.drafts[name] = {}
end
local selected_id = 0
if mail.selected_idxs.drafts[name] and #mail.selected_idxs.drafts[name] > 0 then
for i, selected_msg in ipairs(mail.selected_idxs.drafts[name]) do
if drafts.id == selected_msg then
selected_id = i
table.remove(mail.selected_idxs.drafts[name], i)
break
end
end
end
if selected_id == 0 then
table.insert(mail.selected_idxs.drafts[name], drafts.id)
mail.selected_idxs.message[name] = drafts.id
end
else
mail.selected_idxs.drafts[name] = { drafts }
mail.selected_idxs.message[name] = drafts.id
end
if evt.type == "DCL" then
mail.selected_idxs.message[name] = drafts.id
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,
drafts.to,
drafts.subject,
drafts.body,
drafts.cc,
drafts.bcc,
drafts.id
messagesDrafts[mail.selected_idxs.drafts[name]].to,
messagesDrafts[mail.selected_idxs.drafts[name]].subject,
messagesDrafts[mail.selected_idxs.drafts[name]].body,
messagesDrafts[mail.selected_idxs.drafts[name]].cc,
messagesDrafts[mail.selected_idxs.drafts[name]].bcc,
messagesDrafts[mail.selected_idxs.drafts[name]].id
)
end
return true
@ -213,38 +183,12 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
mail.selected_idxs.sortfield[name] = evt.column-1 -- update column
mail.show_mail_menu(name)
return true
return
end
local trash = getTrash()[evt.row-1]
if not trash then
mail.show_mail_menu(name)
return true
end
if mail.selected_idxs.multipleselection[name] then
if not mail.selected_idxs.trash[name] then
mail.selected_idxs.trash[name] = {}
end
local selected_id = 0
if mail.selected_idxs.trash[name] and #mail.selected_idxs.trash[name] > 0 then
for i, selected_msg in ipairs(mail.selected_idxs.trash[name]) do
if trash.id == selected_msg then
selected_id = i
table.remove(mail.selected_idxs.trash[name], i)
break
end
end
end
if selected_id == 0 then
table.insert(mail.selected_idxs.trash[name], trash.id)
mail.selected_idxs.message[name] = trash.id
end
else
mail.selected_idxs.trash[name] = { trash.id }
mail.selected_idxs.message[name] = trash.id
end
if evt.type == "DCL" then
mail.selected_idxs.message[name] = trash.id
mail.show_message(name, trash.id)
mail.selected_idxs.trash[name] = evt.row - 1
if evt.type == "DCL" and messagesTrash[mail.selected_idxs.trash[name]] then
mail.selected_idxs.message[name] = messagesTrash[mail.selected_idxs.trash[name]].id
mail.show_message(name, messagesTrash[mail.selected_idxs.trash[name]].id)
end
return true
end
@ -270,22 +214,22 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
mail.selected_idxs.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]]
elseif formname == "mail:trash" and mail.selected_idxs.trash[name] then
mail.selected_idxs.message[name] = mail.selected_idxs.trash[name]
elseif formname == "mail:trash" and messagesTrash[mail.selected_idxs.trash[name]] then
mail.selected_idxs.message[name] = messagesTrash[mail.selected_idxs.trash[name]].id
end
if mail.selected_idxs.message[name] then
mail.show_message(name, mail.selected_idxs.message[name])
end
elseif fields.edit then
if formname == "mail:drafts" and mail.selected_idxs.drafts[name] then
if formname == "mail:drafts" and messagesDrafts[mail.selected_idxs.drafts[name]] then
mail.show_compose(name,
mail.selected_idxs.drafts[name].to,
mail.selected_idxs.drafts[name].subject,
mail.selected_idxs.drafts[name].body,
mail.selected_idxs.drafts[name].cc,
mail.selected_idxs.drafts[name].bcc,
mail.selected_idxs.drafts[name].id
messagesDrafts[mail.selected_idxs.drafts[name]].to,
messagesDrafts[mail.selected_idxs.drafts[name]].subject,
messagesDrafts[mail.selected_idxs.drafts[name]].body,
messagesDrafts[mail.selected_idxs.drafts[name]].cc,
messagesDrafts[mail.selected_idxs.drafts[name]].bcc,
messagesDrafts[mail.selected_idxs.drafts[name]].id
)
end
@ -305,23 +249,23 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
mail.delete_mail(name, mail.selected_idxs.outbox[name])
end
mail.selected_idxs.outbox[name] = {}
elseif formname == "mail:drafts" and mail.selected_idxs.drafts[name] then -- drafts table
elseif formname == "mail:drafts" and messagesDrafts[mail.selected_idxs.drafts[name]] then -- drafts table
if trash_enabled then
mail.trash_mail(name, mail.selected_idxs.drafts[name])
mail.trash_mail(name, messagesDrafts[mail.selected_idxs.drafts[name]].id)
else
mail.delete_mail(name, mail.selected_idxs.drafts[name])
mail.delete_mail(name, messagesDrafts[mail.selected_idxs.drafts[name]].id)
end
mail.selected_idxs.drafts[name] = nil
elseif formname == "mail:trash" and mail.selected_idxs.trash[name] then -- trash table
mail.delete_mail(name, mail.selected_idxs.trash[name], true)
elseif formname == "mail:trash" and messagesTrash[mail.selected_idxs.trash[name]] then -- trash table
mail.delete_mail(name, messagesTrash[mail.selected_idxs.trash[name]].id, true)
end
mail.show_mail_menu(name, sortfieldindex, sortdirection, filter)
elseif fields.restore then
if mail.selected_idxs.trash[name] then
mail.restore_mail(name, mail.selected_idxs.trash[name])
if messagesTrash[mail.selected_idxs.trash[name]] then
mail.restore_mail(name, messagesTrash[mail.selected_idxs.trash[name]].id)
end
mail.show_mail_menu(name, sortfieldindex, sortdirection, filter)

View File

@ -1,5 +1,5 @@
-- translation
local S = minetest.get_translator("mail")
local S = mail.S
function mail.show_inbox(name, sortfieldindex, sortdirection, filter)
sortfieldindex = tonumber(sortfieldindex or mail.selected_idxs.sortfield[name])
@ -77,6 +77,7 @@ function mail.show_inbox(name, sortfieldindex, sortdirection, filter)
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
@ -103,7 +104,7 @@ function mail.show_inbox(name, sortfieldindex, sortdirection, filter)
if message.spam then
table.insert(displayed_color, "warning")
end
if table.indexof(mail.get_setting(name, "mute_list"), message.from) >= 1 then
if table.indexof(mute_list, message.from) >= 1 then
table.insert(displayed_color, "muted")
end
formspec[#formspec + 1] = "," .. mail.get_color(displayed_color)

View File

@ -1,5 +1,5 @@
-- translation
local S = minetest.get_translator("mail")
local S = mail.S
local FORMNAME = "mail:maillists"

View File

@ -1,5 +1,5 @@
-- translation
local S = minetest.get_translator("mail")
local S = mail.S
local FORMNAME = "mail:message"
@ -58,7 +58,8 @@ function mail.show_message(name, id)
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 minetest.formspec_escape(os.date(mail.get_setting(name, "date_format"), message.time)) or ""
and minetest.formspec_escape(os.date(mail.get_setting(name, "date_format"),
message.time+3600*mail.get_setting(name, "timezone_offset"))) 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)

View File

@ -1,5 +1,5 @@
-- translation
local S = minetest.get_translator("mail")
local S = mail.S
function mail.show_outbox(name, sortfieldindex, sortdirection, filter)
sortfieldindex = tonumber(sortfieldindex or mail.selected_idxs.sortfield[name])

View File

@ -1,5 +1,5 @@
-- translation
local S = minetest.get_translator("mail")
local S = mail.S
local FORMNAME = "mail:selectcontact"

View File

@ -1,26 +1,51 @@
-- translation
local S = minetest.get_translator("mail")
local S = mail.S
local FORMNAME = "mail:settings"
function mail.show_settings(name)
local groups_labels = {}
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(mail.settings_groups) do
table.insert(groups_labels, g.label)
if g.name == mail.selected_idxs.settings_group[name] then
group_index = i
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 groups_str = table.concat(groups_labels, ",")
local formspec = [[
size[10,6;]
tabheader[0,0;optionstab;]] .. S("Settings") .. "," .. S("About") .. [[;1;false;false]
button[9.35,0;0.75,0.5;back;X]
tablecolumns[text]
tablecolumns[tree;text]
table[0,0.775;3,4.5;groups;]] .. groups_str .. [[;]] .. group_index .. [[]
box[0,0;3,0.45;]] .. mail.get_color("highlighted") .. [[]
@ -84,7 +109,35 @@ function mail.show_settings(name)
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)
@ -149,8 +202,13 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
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
mail.show_settings(playername)
elseif data.type == "index" then
mail.selected_idxs[setting][playername] = tonumber(fields[setting])
elseif data.type == "list" then

View File

@ -1,105 +1,53 @@
-- translation
local S = minetest.get_translator("mail")
local S = mail.S
function mail.show_trash(name, sortfieldindex, sortdirection, filter)
sortfieldindex = tonumber(sortfieldindex or mail.selected_idxs.sortfield[name])
or mail.get_setting(name, "defaultsortfield") or 3
sortdirection = tostring(sortdirection or mail.selected_idxs.sortdirection[name]
or mail.get_setting(name, "defaultsortdirection") or "1")
filter = filter or mail.selected_idxs.filter[name] or ""
mail.selected_idxs.trash[name] = mail.selected_idxs.trash[name] or {}
local trash_formspec = "size[8.5,11;]" .. mail.theme .. [[
tabheader[0.3,1;boxtab;]] ..
S("Inbox") .. "," .. S("Outbox").. "," .. S("Drafts") .. "," .. S("Trash") .. [[;4;false;false]
local entry = mail.get_storage_entry(name)
local sortfield = ({"from","subject","time"})[sortfieldindex]
local messages = mail.sort_messages(entry.trash, sortfield, sortdirection == "2", filter)
button[6,0.10;2.5,0.5;new;]] .. S("New") .. [[]
button[6,0.95;2.5,0.5;read;]] .. S("Read") .. [[]
button[6,1.70;2.5,0.5;restore;]] .. S("Restore") .. [[]
button[6,2.45;2.5,0.5;delete;]] .. S("Delete") .. [[]
button[6,3.20;2.5,0.5;empty;]] .. S("Empty") .. [[]
button[6,8.0;2.5,0.5;contacts;]] .. S("Contacts") .. [[]
button[6,8.8;2.5,0.5;maillists;]] .. S("Mail lists") .. [[]
button[6,9.7;2.5,0.5;options;]] .. S("Options") .. [[]
button_exit[6,10.5;2.5,0.5;quit;]] .. S("Close") .. [[]
if mail.selected_idxs.trash[name] and #mail.selected_idxs.trash[name] > 0 then
for i, selected_msg in ipairs(mail.selected_idxs.trash[name]) do
local is_present = false
for _, msg in ipairs(messages) do
if msg.id == selected_msg then
is_present = true
break
end
end
if not is_present then
table.remove(mail.selected_idxs.trash[name], i)
end
end
end
tablecolumns[color;text;text]
table[0,0.7;5.75,10.35;trash;]] .. mail.get_color("header") .. "," .. S("From/To") .. "," .. S("Subject")
local trash_formspec = "size[8.5,11;]" .. mail.theme .. [[
tabheader[0.3,1;boxtab;]] ..
S("Inbox") .. "," .. S("Outbox").. "," .. S("Drafts") .. "," .. S("Trash") .. [[;4;false;false]
button[6,0.10;2.5,0.5;new;]] .. S("New") .. [[]
button[6,0.95;2.5,0.5;read;]] .. S("Read") .. [[]
button[6,1.70;2.5,0.5;restore;]] .. S("Restore") .. [[]
button[6,2.45;2.5,0.5;delete;]] .. S("Delete") .. [[]
button[6,3.20;2.5,0.5;empty;]] .. S("Empty") .. [[]
button[6,8.0;2.5,0.5;contacts;]] .. S("Contacts") .. [[]
button[6,8.8;2.5,0.5;maillists;]] .. S("Mail lists") .. [[]
button[6,9.7;2.5,0.5;options;]] .. S("Options") .. [[]
button_exit[6,10.5;2.5,0.5;quit;]] .. S("Close") .. [[]
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.trash[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;trash;]] .. mail.get_color("header") .. "," .. S("From/To") .. "," .. S("Subject")
function mail.show_trash(name)
local formspec = { trash_formspec }
local entry = mail.get_storage_entry(name)
local messages = entry.trash
if #messages > 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.trash[name] and #mail.selected_idxs.trash[name] > 0 then
for i, selected_msg in ipairs(mail.selected_idxs.trash[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] = minetest.formspec_escape(string.sub(message.to, 1, 17))
formspec[#formspec + 1] = "..."
if messages[1] then
for _, message in ipairs(messages) do
formspec[#formspec + 1] = ","
formspec[#formspec + 1] = ","
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] = 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] = minetest.formspec_escape(message.to)
formspec[#formspec + 1] = S("(No subject)")
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
end
if mail.selected_idxs.trash[name] then
formspec[#formspec + 1] = ";"
formspec[#formspec + 1] = tostring(mail.selected_idxs.trash[name] + 1)
end
formspec[#formspec + 1] = "]"
else
formspec[#formspec + 1] = "]label[2.25,4.5;" .. S("Trash is empty") .. "]"
end
minetest.show_formspec(name, "mail:trash", table.concat(formspec, ""))
end

View File

@ -1,5 +1,5 @@
-- translation
local S = minetest.get_translator("mail")
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)

View File

@ -1,4 +1,5 @@
local S = minetest.get_translator("mail")
-- translation
local S = mail.S
local function recursive_expand_recipient_names(sender, list, is_toplevel, recipients, undeliverable)
for _, name in ipairs(list) do

View File

@ -1,5 +1,5 @@
-- translation
local S = minetest.get_translator("mail")
local S = mail.S
mail.settings = {
chat_notifications = {
@ -26,11 +26,11 @@ mail.settings = {
label = S("Show CC/BCC in different color")
},
defaultsortfield = {
type = "index", default = 3, group = "message_list", index = 3,
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 = "message_list", index = 4,
type = "index", default = 1, group = "box_fields", index = 2,
label = S("Default sorting direction"), dataset = { S("Ascending"), S("Descending") }
},
trash_move_enable = {
@ -42,9 +42,13 @@ mail.settings = {
label = S("Automatic marking read"), tooltip = S("Mark a message as read when opened")
},
date_format = {
type = "string", default = "%Y-%m-%d %X", group = "other", index = 3, label = S("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")
@ -52,10 +56,12 @@ mail.settings = {
}
mail.settings_groups = {
{ name = "notifications", label = S("Notifications")},
{ name = "message_list", label = S("Message list")},
{ name = "spam", label = S("Spam")},
{ name = "other", label = S("Other")}
{ 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

View File

@ -1,5 +1,5 @@
-- translation
local S = minetest.get_translator("mail")
local S = mail.S
function mail.time_ago(t)
local elapsed = os.time() - t