From: Baptiste Daroussin Date: Mon, 26 Jun 2023 18:57:59 +0000 (+0200) Subject: listtexts: subtree merge X-Git-Tag: RELEASE_1_4_0rc1~28 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9595d35d8be287a84ee3037bf4d02ff3ba780c1c;p=thirdparty%2Fmlmmj.git listtexts: subtree merge Merge the listext repository keeping the history --- 9595d35d8be287a84ee3037bf4d02ff3ba780c1c diff --cc listtexts/Makefile.am index 00000000,00000000..46329280 new file mode 100644 --- /dev/null +++ b/listtexts/Makefile.am @@@ -1,0 -1,0 +1,3 @@@ ++## Process this file with automake to produce Makefile.in ++ ++nobase_dist_textlib_DATA = $(srcdir)/*/* diff --cc listtexts/ast/confirm index 00000000,11073579..11073579 mode 000000,100644..100644 --- a/listtexts/ast/confirm +++ b/listtexts/ast/confirm diff --cc listtexts/ast/deny index 00000000,4b10912d..4b10912d mode 000000,100644..100644 --- a/listtexts/ast/deny +++ b/listtexts/ast/deny diff --cc listtexts/ast/deny-post index 00000000,26cdea76..26cdea76 mode 000000,100644..100644 --- a/listtexts/ast/deny-post +++ b/listtexts/ast/deny-post diff --cc listtexts/ast/digest index 00000000,8845b4f2..8845b4f2 mode 000000,100644..100644 --- a/listtexts/ast/digest +++ b/listtexts/ast/digest diff --cc listtexts/ast/faq index 00000000,3c29fa91..3c29fa91 mode 000000,100644..100644 --- a/listtexts/ast/faq +++ b/listtexts/ast/faq diff --cc listtexts/ast/finish index 00000000,cfbeafad..cfbeafad mode 000000,100644..100644 --- a/listtexts/ast/finish +++ b/listtexts/ast/finish diff --cc listtexts/ast/finish-sub index 00000000,9ecb92a5..9ecb92a5 mode 000000,100644..100644 --- a/listtexts/ast/finish-sub +++ b/listtexts/ast/finish-sub diff --cc listtexts/ast/gatekeep-sub index 00000000,46fb5f86..46fb5f86 mode 000000,100644..100644 --- a/listtexts/ast/gatekeep-sub +++ b/listtexts/ast/gatekeep-sub diff --cc listtexts/ast/help index 00000000,2cf6eb7a..2cf6eb7a mode 000000,100644..100644 --- a/listtexts/ast/help +++ b/listtexts/ast/help diff --cc listtexts/ast/list index 00000000,7fb358af..7fb358af mode 000000,100644..100644 --- a/listtexts/ast/list +++ b/listtexts/ast/list diff --cc listtexts/ast/moderate-post index 00000000,49b65f43..49b65f43 mode 000000,100644..100644 --- a/listtexts/ast/moderate-post +++ b/listtexts/ast/moderate-post diff --cc listtexts/ast/notify index 00000000,d5241102..d5241102 mode 000000,100644..100644 --- a/listtexts/ast/notify +++ b/listtexts/ast/notify diff --cc listtexts/ast/probe index 00000000,cd309afa..cd309afa mode 000000,100644..100644 --- a/listtexts/ast/probe +++ b/listtexts/ast/probe diff --cc listtexts/ast/prologue index 00000000,df7cf43b..df7cf43b mode 000000,100644..100644 --- a/listtexts/ast/prologue +++ b/listtexts/ast/prologue diff --cc listtexts/ast/subrelease index 00000000,a8a0d0d9..a8a0d0d9 mode 000000,100644..100644 --- a/listtexts/ast/subrelease +++ b/listtexts/ast/subrelease diff --cc listtexts/ast/wait-post index 00000000,63e46549..63e46549 mode 000000,100644..100644 --- a/listtexts/ast/wait-post +++ b/listtexts/ast/wait-post diff --cc listtexts/ast/wait-sub index 00000000,07d68299..07d68299 mode 000000,100644..100644 --- a/listtexts/ast/wait-sub +++ b/listtexts/ast/wait-sub diff --cc listtexts/cs/confirm index 00000000,dc7bd56d..dc7bd56d mode 000000,100644..100644 --- a/listtexts/cs/confirm +++ b/listtexts/cs/confirm diff --cc listtexts/cs/deny index 00000000,fea660da..fea660da mode 000000,100644..100644 --- a/listtexts/cs/deny +++ b/listtexts/cs/deny diff --cc listtexts/cs/deny-post index 00000000,d672b964..d672b964 mode 000000,100644..100644 --- a/listtexts/cs/deny-post +++ b/listtexts/cs/deny-post diff --cc listtexts/cs/digest index 00000000,9a32e62e..9a32e62e mode 000000,100644..100644 --- a/listtexts/cs/digest +++ b/listtexts/cs/digest diff --cc listtexts/cs/faq index 00000000,1233412b..1233412b mode 000000,100644..100644 --- a/listtexts/cs/faq +++ b/listtexts/cs/faq diff --cc listtexts/cs/finish index 00000000,557d143a..557d143a mode 000000,100644..100644 --- a/listtexts/cs/finish +++ b/listtexts/cs/finish diff --cc listtexts/cs/finish-sub index 00000000,76e67e34..76e67e34 mode 000000,100644..100644 --- a/listtexts/cs/finish-sub +++ b/listtexts/cs/finish-sub diff --cc listtexts/cs/gatekeep-sub index 00000000,ff3f83fb..ff3f83fb mode 000000,100644..100644 --- a/listtexts/cs/gatekeep-sub +++ b/listtexts/cs/gatekeep-sub diff --cc listtexts/cs/help index 00000000,8f499e53..8f499e53 mode 000000,100644..100644 --- a/listtexts/cs/help +++ b/listtexts/cs/help diff --cc listtexts/cs/list index 00000000,9acf848c..9acf848c mode 000000,100644..100644 --- a/listtexts/cs/list +++ b/listtexts/cs/list diff --cc listtexts/cs/moderate-post index 00000000,467ca742..467ca742 mode 000000,100644..100644 --- a/listtexts/cs/moderate-post +++ b/listtexts/cs/moderate-post diff --cc listtexts/cs/notify index 00000000,21506f0a..21506f0a mode 000000,100644..100644 --- a/listtexts/cs/notify +++ b/listtexts/cs/notify diff --cc listtexts/cs/probe index 00000000,8b867ed7..8b867ed7 mode 000000,100644..100644 --- a/listtexts/cs/probe +++ b/listtexts/cs/probe diff --cc listtexts/cs/prologue index 00000000,bb4daa47..bb4daa47 mode 000000,100644..100644 --- a/listtexts/cs/prologue +++ b/listtexts/cs/prologue diff --cc listtexts/cs/subrelease index 00000000,db74f3f4..db74f3f4 mode 000000,100644..100644 --- a/listtexts/cs/subrelease +++ b/listtexts/cs/subrelease diff --cc listtexts/cs/wait-post index 00000000,50e976da..50e976da mode 000000,100644..100644 --- a/listtexts/cs/wait-post +++ b/listtexts/cs/wait-post diff --cc listtexts/cs/wait-sub index 00000000,ce332878..ce332878 mode 000000,100644..100644 --- a/listtexts/cs/wait-sub +++ b/listtexts/cs/wait-sub diff --cc listtexts/de/confirm index 00000000,7e926d43..7e926d43 mode 000000,100644..100644 --- a/listtexts/de/confirm +++ b/listtexts/de/confirm diff --cc listtexts/de/deny index 00000000,3ef5e1fa..3ef5e1fa mode 000000,100644..100644 --- a/listtexts/de/deny +++ b/listtexts/de/deny diff --cc listtexts/de/deny-post index 00000000,26919c0b..26919c0b mode 000000,100644..100644 --- a/listtexts/de/deny-post +++ b/listtexts/de/deny-post diff --cc listtexts/de/digest index 00000000,06736075..06736075 mode 000000,100644..100644 --- a/listtexts/de/digest +++ b/listtexts/de/digest diff --cc listtexts/de/faq index 00000000,e1915511..e1915511 mode 000000,100644..100644 --- a/listtexts/de/faq +++ b/listtexts/de/faq diff --cc listtexts/de/finish index 00000000,46c12bee..46c12bee mode 000000,100644..100644 --- a/listtexts/de/finish +++ b/listtexts/de/finish diff --cc listtexts/de/finish-sub index 00000000,e1b67f4b..e1b67f4b mode 000000,100644..100644 --- a/listtexts/de/finish-sub +++ b/listtexts/de/finish-sub diff --cc listtexts/de/gatekeep-sub index 00000000,1f9a48ac..1f9a48ac mode 000000,100644..100644 --- a/listtexts/de/gatekeep-sub +++ b/listtexts/de/gatekeep-sub diff --cc listtexts/de/help index 00000000,b4b208b0..b4b208b0 mode 000000,100644..100644 --- a/listtexts/de/help +++ b/listtexts/de/help diff --cc listtexts/de/list index 00000000,faa9fceb..faa9fceb mode 000000,100644..100644 --- a/listtexts/de/list +++ b/listtexts/de/list diff --cc listtexts/de/moderate-post index 00000000,d214684e..d214684e mode 000000,100644..100644 --- a/listtexts/de/moderate-post +++ b/listtexts/de/moderate-post diff --cc listtexts/de/notify index 00000000,aa962024..aa962024 mode 000000,100644..100644 --- a/listtexts/de/notify +++ b/listtexts/de/notify diff --cc listtexts/de/probe index 00000000,d4c8a9d0..d4c8a9d0 mode 000000,100644..100644 --- a/listtexts/de/probe +++ b/listtexts/de/probe diff --cc listtexts/de/prologue index 00000000,a3a44ae6..a3a44ae6 mode 000000,100644..100644 --- a/listtexts/de/prologue +++ b/listtexts/de/prologue diff --cc listtexts/de/subrelease index 00000000,a68ec711..a68ec711 mode 000000,100644..100644 --- a/listtexts/de/subrelease +++ b/listtexts/de/subrelease diff --cc listtexts/de/wait-post index 00000000,49bc99fc..49bc99fc mode 000000,100644..100644 --- a/listtexts/de/wait-post +++ b/listtexts/de/wait-post diff --cc listtexts/de/wait-sub index 00000000,594fcfb4..594fcfb4 mode 000000,100644..100644 --- a/listtexts/de/wait-sub +++ b/listtexts/de/wait-sub diff --cc listtexts/en/confirm index 00000000,ae8cbddd..ae8cbddd mode 000000,100644..100644 --- a/listtexts/en/confirm +++ b/listtexts/en/confirm diff --cc listtexts/en/deny index 00000000,e02b1be3..e02b1be3 mode 000000,100644..100644 --- a/listtexts/en/deny +++ b/listtexts/en/deny diff --cc listtexts/en/deny-post index 00000000,9de308a0..9de308a0 mode 000000,100644..100644 --- a/listtexts/en/deny-post +++ b/listtexts/en/deny-post diff --cc listtexts/en/digest index 00000000,e9fa8592..e9fa8592 mode 000000,100644..100644 --- a/listtexts/en/digest +++ b/listtexts/en/digest diff --cc listtexts/en/faq index 00000000,28f22fe1..28f22fe1 mode 000000,100644..100644 --- a/listtexts/en/faq +++ b/listtexts/en/faq diff --cc listtexts/en/finish index 00000000,8560bae1..8560bae1 mode 000000,100644..100644 --- a/listtexts/en/finish +++ b/listtexts/en/finish diff --cc listtexts/en/finish-sub index 00000000,64337a36..64337a36 mode 000000,100644..100644 --- a/listtexts/en/finish-sub +++ b/listtexts/en/finish-sub diff --cc listtexts/en/gatekeep-sub index 00000000,ba460886..ba460886 mode 000000,100644..100644 --- a/listtexts/en/gatekeep-sub +++ b/listtexts/en/gatekeep-sub diff --cc listtexts/en/help index 00000000,3b104bc7..3b104bc7 mode 000000,100644..100644 --- a/listtexts/en/help +++ b/listtexts/en/help diff --cc listtexts/en/list index 00000000,52f3be87..52f3be87 mode 000000,100644..100644 --- a/listtexts/en/list +++ b/listtexts/en/list diff --cc listtexts/en/moderate-post index 00000000,18944c3a..18944c3a mode 000000,100644..100644 --- a/listtexts/en/moderate-post +++ b/listtexts/en/moderate-post diff --cc listtexts/en/notify index 00000000,6c2876c0..6c2876c0 mode 000000,100644..100644 --- a/listtexts/en/notify +++ b/listtexts/en/notify diff --cc listtexts/en/probe index 00000000,397ebbec..397ebbec mode 000000,100644..100644 --- a/listtexts/en/probe +++ b/listtexts/en/probe diff --cc listtexts/en/prologue index 00000000,ef76595f..ef76595f mode 000000,100644..100644 --- a/listtexts/en/prologue +++ b/listtexts/en/prologue diff --cc listtexts/en/subrelease index 00000000,7cdae70c..7cdae70c mode 000000,100644..100644 --- a/listtexts/en/subrelease +++ b/listtexts/en/subrelease diff --cc listtexts/en/wait-post index 00000000,d30fb5d2..d30fb5d2 mode 000000,100644..100644 --- a/listtexts/en/wait-post +++ b/listtexts/en/wait-post diff --cc listtexts/en/wait-sub index 00000000,84df549e..84df549e mode 000000,100644..100644 --- a/listtexts/en/wait-sub +++ b/listtexts/en/wait-sub diff --cc listtexts/fi/confirm index 00000000,6170eaba..6170eaba mode 000000,100644..100644 --- a/listtexts/fi/confirm +++ b/listtexts/fi/confirm diff --cc listtexts/fi/deny index 00000000,cbd85dea..cbd85dea mode 000000,100644..100644 --- a/listtexts/fi/deny +++ b/listtexts/fi/deny diff --cc listtexts/fi/deny-post index 00000000,0cc151be..0cc151be mode 000000,100644..100644 --- a/listtexts/fi/deny-post +++ b/listtexts/fi/deny-post diff --cc listtexts/fi/digest index 00000000,c4d61798..c4d61798 mode 000000,100644..100644 --- a/listtexts/fi/digest +++ b/listtexts/fi/digest diff --cc listtexts/fi/faq index 00000000,d03db261..d03db261 mode 000000,100644..100644 --- a/listtexts/fi/faq +++ b/listtexts/fi/faq diff --cc listtexts/fi/finish index 00000000,1f25fba0..1f25fba0 mode 000000,100644..100644 --- a/listtexts/fi/finish +++ b/listtexts/fi/finish diff --cc listtexts/fi/finish-sub index 00000000,4a8c3f09..4a8c3f09 mode 000000,100644..100644 --- a/listtexts/fi/finish-sub +++ b/listtexts/fi/finish-sub diff --cc listtexts/fi/gatekeep-sub index 00000000,26aa7012..26aa7012 mode 000000,100644..100644 --- a/listtexts/fi/gatekeep-sub +++ b/listtexts/fi/gatekeep-sub diff --cc listtexts/fi/help index 00000000,51bc9da3..51bc9da3 mode 000000,100644..100644 --- a/listtexts/fi/help +++ b/listtexts/fi/help diff --cc listtexts/fi/list index 00000000,d6be9956..d6be9956 mode 000000,100644..100644 --- a/listtexts/fi/list +++ b/listtexts/fi/list diff --cc listtexts/fi/moderate-post index 00000000,9f7b46ee..9f7b46ee mode 000000,100644..100644 --- a/listtexts/fi/moderate-post +++ b/listtexts/fi/moderate-post diff --cc listtexts/fi/notify index 00000000,a086dede..a086dede mode 000000,100644..100644 --- a/listtexts/fi/notify +++ b/listtexts/fi/notify diff --cc listtexts/fi/probe index 00000000,3b64737f..3b64737f mode 000000,100644..100644 --- a/listtexts/fi/probe +++ b/listtexts/fi/probe diff --cc listtexts/fi/prologue index 00000000,f7b46339..f7b46339 mode 000000,100644..100644 --- a/listtexts/fi/prologue +++ b/listtexts/fi/prologue diff --cc listtexts/fi/subrelease index 00000000,665c1637..665c1637 mode 000000,100644..100644 --- a/listtexts/fi/subrelease +++ b/listtexts/fi/subrelease diff --cc listtexts/fi/wait-post index 00000000,ef63c9cb..ef63c9cb mode 000000,100644..100644 --- a/listtexts/fi/wait-post +++ b/listtexts/fi/wait-post diff --cc listtexts/fi/wait-sub index 00000000,e0fd8d7f..e0fd8d7f mode 000000,100644..100644 --- a/listtexts/fi/wait-sub +++ b/listtexts/fi/wait-sub diff --cc listtexts/fr/confirm index 00000000,b0ad3a8c..b0ad3a8c mode 000000,100644..100644 --- a/listtexts/fr/confirm +++ b/listtexts/fr/confirm diff --cc listtexts/fr/deny index 00000000,ba1b6043..ba1b6043 mode 000000,100644..100644 --- a/listtexts/fr/deny +++ b/listtexts/fr/deny diff --cc listtexts/fr/deny-post index 00000000,b7b05dd3..b7b05dd3 mode 000000,100644..100644 --- a/listtexts/fr/deny-post +++ b/listtexts/fr/deny-post diff --cc listtexts/fr/digest index 00000000,91b6c196..91b6c196 mode 000000,100644..100644 --- a/listtexts/fr/digest +++ b/listtexts/fr/digest diff --cc listtexts/fr/faq index 00000000,004af38c..004af38c mode 000000,100644..100644 --- a/listtexts/fr/faq +++ b/listtexts/fr/faq diff --cc listtexts/fr/finish index 00000000,4e021bcc..4e021bcc mode 000000,100644..100644 --- a/listtexts/fr/finish +++ b/listtexts/fr/finish diff --cc listtexts/fr/finish-sub index 00000000,116af457..116af457 mode 000000,100644..100644 --- a/listtexts/fr/finish-sub +++ b/listtexts/fr/finish-sub diff --cc listtexts/fr/gatekeep-sub index 00000000,df1fa87c..df1fa87c mode 000000,100644..100644 --- a/listtexts/fr/gatekeep-sub +++ b/listtexts/fr/gatekeep-sub diff --cc listtexts/fr/help index 00000000,9d13b8b0..9d13b8b0 mode 000000,100644..100644 --- a/listtexts/fr/help +++ b/listtexts/fr/help diff --cc listtexts/fr/list index 00000000,14c61bb2..14c61bb2 mode 000000,100644..100644 --- a/listtexts/fr/list +++ b/listtexts/fr/list diff --cc listtexts/fr/moderate-post index 00000000,6b1f5292..6b1f5292 mode 000000,100644..100644 --- a/listtexts/fr/moderate-post +++ b/listtexts/fr/moderate-post diff --cc listtexts/fr/notify index 00000000,20867b3c..20867b3c mode 000000,100644..100644 --- a/listtexts/fr/notify +++ b/listtexts/fr/notify diff --cc listtexts/fr/probe index 00000000,ee421ee0..ee421ee0 mode 000000,100644..100644 --- a/listtexts/fr/probe +++ b/listtexts/fr/probe diff --cc listtexts/fr/prologue index 00000000,06ae06de..06ae06de mode 000000,100644..100644 --- a/listtexts/fr/prologue +++ b/listtexts/fr/prologue diff --cc listtexts/fr/subrelease index 00000000,3f3bdcbf..3f3bdcbf mode 000000,100644..100644 --- a/listtexts/fr/subrelease +++ b/listtexts/fr/subrelease diff --cc listtexts/fr/wait-post index 00000000,0d4196ef..0d4196ef mode 000000,100644..100644 --- a/listtexts/fr/wait-post +++ b/listtexts/fr/wait-post diff --cc listtexts/fr/wait-sub index 00000000,2f584484..2f584484 mode 000000,100644..100644 --- a/listtexts/fr/wait-sub +++ b/listtexts/fr/wait-sub diff --cc listtexts/gr/confirm index 00000000,32b43c5a..32b43c5a mode 000000,100644..100644 --- a/listtexts/gr/confirm +++ b/listtexts/gr/confirm diff --cc listtexts/gr/deny index 00000000,dc7b8fc3..dc7b8fc3 mode 000000,100644..100644 --- a/listtexts/gr/deny +++ b/listtexts/gr/deny diff --cc listtexts/gr/deny-post index 00000000,32a8dc84..32a8dc84 mode 000000,100644..100644 --- a/listtexts/gr/deny-post +++ b/listtexts/gr/deny-post diff --cc listtexts/gr/digest index 00000000,e2c5970f..e2c5970f mode 000000,100644..100644 --- a/listtexts/gr/digest +++ b/listtexts/gr/digest diff --cc listtexts/gr/faq index 00000000,a563bf60..a563bf60 mode 000000,100644..100644 --- a/listtexts/gr/faq +++ b/listtexts/gr/faq diff --cc listtexts/gr/finish index 00000000,388187ab..388187ab mode 000000,100644..100644 --- a/listtexts/gr/finish +++ b/listtexts/gr/finish diff --cc listtexts/gr/finish-sub index 00000000,e884e510..e884e510 mode 000000,100644..100644 --- a/listtexts/gr/finish-sub +++ b/listtexts/gr/finish-sub diff --cc listtexts/gr/gatekeep-sub index 00000000,1c0a2efd..1c0a2efd mode 000000,100644..100644 --- a/listtexts/gr/gatekeep-sub +++ b/listtexts/gr/gatekeep-sub diff --cc listtexts/gr/help index 00000000,30b6459f..30b6459f mode 000000,100644..100644 --- a/listtexts/gr/help +++ b/listtexts/gr/help diff --cc listtexts/gr/list index 00000000,53004e6d..53004e6d mode 000000,100644..100644 --- a/listtexts/gr/list +++ b/listtexts/gr/list diff --cc listtexts/gr/moderate-post index 00000000,cb41e8ff..cb41e8ff mode 000000,100644..100644 --- a/listtexts/gr/moderate-post +++ b/listtexts/gr/moderate-post diff --cc listtexts/gr/notify index 00000000,dd51bc1f..dd51bc1f mode 000000,100644..100644 --- a/listtexts/gr/notify +++ b/listtexts/gr/notify diff --cc listtexts/gr/probe index 00000000,e043a97c..e043a97c mode 000000,100644..100644 --- a/listtexts/gr/probe +++ b/listtexts/gr/probe diff --cc listtexts/gr/prologue index 00000000,b774bfe2..b774bfe2 mode 000000,100644..100644 --- a/listtexts/gr/prologue +++ b/listtexts/gr/prologue diff --cc listtexts/gr/subrelease index 00000000,4c808727..4c808727 mode 000000,100644..100644 --- a/listtexts/gr/subrelease +++ b/listtexts/gr/subrelease diff --cc listtexts/gr/wait-post index 00000000,4e42928b..4e42928b mode 000000,100644..100644 --- a/listtexts/gr/wait-post +++ b/listtexts/gr/wait-post diff --cc listtexts/gr/wait-sub index 00000000,c3c70a89..c3c70a89 mode 000000,100644..100644 --- a/listtexts/gr/wait-sub +++ b/listtexts/gr/wait-sub diff --cc listtexts/it/confirm index 00000000,b586b11c..b586b11c mode 000000,100644..100644 --- a/listtexts/it/confirm +++ b/listtexts/it/confirm diff --cc listtexts/it/deny index 00000000,e9079811..e9079811 mode 000000,100644..100644 --- a/listtexts/it/deny +++ b/listtexts/it/deny diff --cc listtexts/it/deny-post index 00000000,03b2e08f..03b2e08f mode 000000,100644..100644 --- a/listtexts/it/deny-post +++ b/listtexts/it/deny-post diff --cc listtexts/it/digest index 00000000,d2143154..d2143154 mode 000000,100644..100644 --- a/listtexts/it/digest +++ b/listtexts/it/digest diff --cc listtexts/it/faq index 00000000,b32adf5a..b32adf5a mode 000000,100644..100644 --- a/listtexts/it/faq +++ b/listtexts/it/faq diff --cc listtexts/it/finish index 00000000,d0d1f2b3..d0d1f2b3 mode 000000,100644..100644 --- a/listtexts/it/finish +++ b/listtexts/it/finish diff --cc listtexts/it/finish-sub index 00000000,e8c70559..e8c70559 mode 000000,100644..100644 --- a/listtexts/it/finish-sub +++ b/listtexts/it/finish-sub diff --cc listtexts/it/gatekeep-sub index 00000000,3c14b0f7..3c14b0f7 mode 000000,100644..100644 --- a/listtexts/it/gatekeep-sub +++ b/listtexts/it/gatekeep-sub diff --cc listtexts/it/help index 00000000,e124f69a..e124f69a mode 000000,100644..100644 --- a/listtexts/it/help +++ b/listtexts/it/help diff --cc listtexts/it/list index 00000000,a40342a9..a40342a9 mode 000000,100644..100644 --- a/listtexts/it/list +++ b/listtexts/it/list diff --cc listtexts/it/moderate-post index 00000000,6d9f2d54..6d9f2d54 mode 000000,100644..100644 --- a/listtexts/it/moderate-post +++ b/listtexts/it/moderate-post diff --cc listtexts/it/notify index 00000000,09297f4b..09297f4b mode 000000,100644..100644 --- a/listtexts/it/notify +++ b/listtexts/it/notify diff --cc listtexts/it/probe index 00000000,d3bfaa3a..d3bfaa3a mode 000000,100644..100644 --- a/listtexts/it/probe +++ b/listtexts/it/probe diff --cc listtexts/it/prologue index 00000000,50621f2b..50621f2b mode 000000,100644..100644 --- a/listtexts/it/prologue +++ b/listtexts/it/prologue diff --cc listtexts/it/subrelease index 00000000,f97453c1..f97453c1 mode 000000,100644..100644 --- a/listtexts/it/subrelease +++ b/listtexts/it/subrelease diff --cc listtexts/it/wait-post index 00000000,b057ea8b..b057ea8b mode 000000,100644..100644 --- a/listtexts/it/wait-post +++ b/listtexts/it/wait-post diff --cc listtexts/it/wait-sub index 00000000,38b3493a..38b3493a mode 000000,100644..100644 --- a/listtexts/it/wait-sub +++ b/listtexts/it/wait-sub diff --cc listtexts/pt/confirm index 00000000,5d24f55e..5d24f55e mode 000000,100644..100644 --- a/listtexts/pt/confirm +++ b/listtexts/pt/confirm diff --cc listtexts/pt/deny index 00000000,efecda7e..efecda7e mode 000000,100644..100644 --- a/listtexts/pt/deny +++ b/listtexts/pt/deny diff --cc listtexts/pt/deny-post index 00000000,62ec9c3a..62ec9c3a mode 000000,100644..100644 --- a/listtexts/pt/deny-post +++ b/listtexts/pt/deny-post diff --cc listtexts/pt/digest index 00000000,e5958222..e5958222 mode 000000,100644..100644 --- a/listtexts/pt/digest +++ b/listtexts/pt/digest diff --cc listtexts/pt/faq index 00000000,45454bca..45454bca mode 000000,100644..100644 --- a/listtexts/pt/faq +++ b/listtexts/pt/faq diff --cc listtexts/pt/finish index 00000000,31a8a0e8..31a8a0e8 mode 000000,100644..100644 --- a/listtexts/pt/finish +++ b/listtexts/pt/finish diff --cc listtexts/pt/finish-sub index 00000000,b15ae664..b15ae664 mode 000000,100644..100644 --- a/listtexts/pt/finish-sub +++ b/listtexts/pt/finish-sub diff --cc listtexts/pt/gatekeep-sub index 00000000,eb8fec06..eb8fec06 mode 000000,100644..100644 --- a/listtexts/pt/gatekeep-sub +++ b/listtexts/pt/gatekeep-sub diff --cc listtexts/pt/help index 00000000,28b0ce20..28b0ce20 mode 000000,100644..100644 --- a/listtexts/pt/help +++ b/listtexts/pt/help diff --cc listtexts/pt/list index 00000000,3f3590d1..3f3590d1 mode 000000,100644..100644 --- a/listtexts/pt/list +++ b/listtexts/pt/list diff --cc listtexts/pt/moderate-post index 00000000,d5bf0dc0..d5bf0dc0 mode 000000,100644..100644 --- a/listtexts/pt/moderate-post +++ b/listtexts/pt/moderate-post diff --cc listtexts/pt/notify index 00000000,62527909..62527909 mode 000000,100644..100644 --- a/listtexts/pt/notify +++ b/listtexts/pt/notify diff --cc listtexts/pt/probe index 00000000,07ced0db..07ced0db mode 000000,100644..100644 --- a/listtexts/pt/probe +++ b/listtexts/pt/probe diff --cc listtexts/pt/prologue index 00000000,1b3d4e6b..1b3d4e6b mode 000000,100644..100644 --- a/listtexts/pt/prologue +++ b/listtexts/pt/prologue diff --cc listtexts/pt/subrelease index 00000000,26be9eb2..26be9eb2 mode 000000,100644..100644 --- a/listtexts/pt/subrelease +++ b/listtexts/pt/subrelease diff --cc listtexts/pt/wait-post index 00000000,eb6d781d..eb6d781d mode 000000,100644..100644 --- a/listtexts/pt/wait-post +++ b/listtexts/pt/wait-post diff --cc listtexts/pt/wait-sub index 00000000,fa3f582c..fa3f582c mode 000000,100644..100644 --- a/listtexts/pt/wait-sub +++ b/listtexts/pt/wait-sub diff --cc listtexts/sk/confirm index 00000000,2ce420ee..2ce420ee mode 000000,100644..100644 --- a/listtexts/sk/confirm +++ b/listtexts/sk/confirm diff --cc listtexts/sk/deny index 00000000,3fba9c0c..3fba9c0c mode 000000,100644..100644 --- a/listtexts/sk/deny +++ b/listtexts/sk/deny diff --cc listtexts/sk/deny-post index 00000000,752d1c2d..752d1c2d mode 000000,100644..100644 --- a/listtexts/sk/deny-post +++ b/listtexts/sk/deny-post diff --cc listtexts/sk/digest index 00000000,3742a253..3742a253 mode 000000,100644..100644 --- a/listtexts/sk/digest +++ b/listtexts/sk/digest diff --cc listtexts/sk/faq index 00000000,2570955c..2570955c mode 000000,100644..100644 --- a/listtexts/sk/faq +++ b/listtexts/sk/faq diff --cc listtexts/sk/finish index 00000000,7a31b7f0..7a31b7f0 mode 000000,100644..100644 --- a/listtexts/sk/finish +++ b/listtexts/sk/finish diff --cc listtexts/sk/finish-sub index 00000000,3f8a6200..3f8a6200 mode 000000,100644..100644 --- a/listtexts/sk/finish-sub +++ b/listtexts/sk/finish-sub diff --cc listtexts/sk/gatekeep-sub index 00000000,09feab42..09feab42 mode 000000,100644..100644 --- a/listtexts/sk/gatekeep-sub +++ b/listtexts/sk/gatekeep-sub diff --cc listtexts/sk/help index 00000000,4b95ff66..4b95ff66 mode 000000,100644..100644 --- a/listtexts/sk/help +++ b/listtexts/sk/help diff --cc listtexts/sk/list index 00000000,30f0706b..30f0706b mode 000000,100644..100644 --- a/listtexts/sk/list +++ b/listtexts/sk/list diff --cc listtexts/sk/moderate-post index 00000000,4f834336..4f834336 mode 000000,100644..100644 --- a/listtexts/sk/moderate-post +++ b/listtexts/sk/moderate-post diff --cc listtexts/sk/notify index 00000000,d63415cd..d63415cd mode 000000,100644..100644 --- a/listtexts/sk/notify +++ b/listtexts/sk/notify diff --cc listtexts/sk/probe index 00000000,69609414..69609414 mode 000000,100644..100644 --- a/listtexts/sk/probe +++ b/listtexts/sk/probe diff --cc listtexts/sk/prologue index 00000000,b1197d48..b1197d48 mode 000000,100644..100644 --- a/listtexts/sk/prologue +++ b/listtexts/sk/prologue diff --cc listtexts/sk/subrelease index 00000000,e94137e6..e94137e6 mode 000000,100644..100644 --- a/listtexts/sk/subrelease +++ b/listtexts/sk/subrelease diff --cc listtexts/sk/wait-post index 00000000,9f7c8a3d..9f7c8a3d mode 000000,100644..100644 --- a/listtexts/sk/wait-post +++ b/listtexts/sk/wait-post diff --cc listtexts/sk/wait-sub index 00000000,3b2e8ebb..3b2e8ebb mode 000000,100644..100644 --- a/listtexts/sk/wait-sub +++ b/listtexts/sk/wait-sub diff --cc listtexts/zh-cn/confirm index 00000000,3d4cabe9..3d4cabe9 mode 000000,100644..100644 --- a/listtexts/zh-cn/confirm +++ b/listtexts/zh-cn/confirm diff --cc listtexts/zh-cn/deny index 00000000,9e3e7b50..9e3e7b50 mode 000000,100644..100644 --- a/listtexts/zh-cn/deny +++ b/listtexts/zh-cn/deny diff --cc listtexts/zh-cn/deny-post index 00000000,2fc74203..2fc74203 mode 000000,100644..100644 --- a/listtexts/zh-cn/deny-post +++ b/listtexts/zh-cn/deny-post diff --cc listtexts/zh-cn/digest index 00000000,613a48e9..613a48e9 mode 000000,100644..100644 --- a/listtexts/zh-cn/digest +++ b/listtexts/zh-cn/digest diff --cc listtexts/zh-cn/faq index 00000000,7ba7cca3..7ba7cca3 mode 000000,100644..100644 --- a/listtexts/zh-cn/faq +++ b/listtexts/zh-cn/faq diff --cc listtexts/zh-cn/finish index 00000000,1a863022..1a863022 mode 000000,100644..100644 --- a/listtexts/zh-cn/finish +++ b/listtexts/zh-cn/finish diff --cc listtexts/zh-cn/finish-sub index 00000000,955d199d..955d199d mode 000000,100644..100644 --- a/listtexts/zh-cn/finish-sub +++ b/listtexts/zh-cn/finish-sub diff --cc listtexts/zh-cn/gatekeep-sub index 00000000,9e8e343e..9e8e343e mode 000000,100644..100644 --- a/listtexts/zh-cn/gatekeep-sub +++ b/listtexts/zh-cn/gatekeep-sub diff --cc listtexts/zh-cn/help index 00000000,30e1a2e2..30e1a2e2 mode 000000,100644..100644 --- a/listtexts/zh-cn/help +++ b/listtexts/zh-cn/help diff --cc listtexts/zh-cn/list index 00000000,df70c032..df70c032 mode 000000,100644..100644 --- a/listtexts/zh-cn/list +++ b/listtexts/zh-cn/list diff --cc listtexts/zh-cn/moderate-post index 00000000,d2003f14..d2003f14 mode 000000,100644..100644 --- a/listtexts/zh-cn/moderate-post +++ b/listtexts/zh-cn/moderate-post diff --cc listtexts/zh-cn/notify index 00000000,880472ff..880472ff mode 000000,100644..100644 --- a/listtexts/zh-cn/notify +++ b/listtexts/zh-cn/notify diff --cc listtexts/zh-cn/probe index 00000000,45cff7c3..45cff7c3 mode 000000,100644..100644 --- a/listtexts/zh-cn/probe +++ b/listtexts/zh-cn/probe diff --cc listtexts/zh-cn/prologue index 00000000,f1c31e27..f1c31e27 mode 000000,100644..100644 --- a/listtexts/zh-cn/prologue +++ b/listtexts/zh-cn/prologue diff --cc listtexts/zh-cn/subrelease index 00000000,62e22a20..62e22a20 mode 000000,100644..100644 --- a/listtexts/zh-cn/subrelease +++ b/listtexts/zh-cn/subrelease diff --cc listtexts/zh-cn/wait-post index 00000000,ba6ec1c4..ba6ec1c4 mode 000000,100644..100644 --- a/listtexts/zh-cn/wait-post +++ b/listtexts/zh-cn/wait-post diff --cc listtexts/zh-cn/wait-sub index 00000000,8219ec55..8219ec55 mode 000000,100644..100644 --- a/listtexts/zh-cn/wait-sub +++ b/listtexts/zh-cn/wait-sub diff --cc src/mlmmj-sub.c index cc39bc80,00000000..66802719 mode 100644,000000..100644 --- a/src/mlmmj-sub.c +++ b/src/mlmmj-sub.c @@@ -1,509 -1,0 +1,511 @@@ +/* Copyright (C) 2002, 2003 Mads Martin Joergensen + * + * $Id$ + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xmalloc.h" +#include "mlmmj.h" +#include "mlmmj-sub.h" +#include "wrappers.h" +#include "strgen.h" +#include "subscriberfuncs.h" +#include "log_error.h" +#include "statctrl.h" +#include "prepstdreply.h" +#include "ctrlvalues.h" +#include "chomp.h" +#include "utils.h" +#include "send_help.h" +#include "xstring.h" + +static char *subtypes[7] = { + "SUB_NORMAL", + "SUB_DIGEST", + "SUB_NOMAIL", + NULL, + NULL, + "SUB_BOTH", + NULL, +}; + +static void moderate_sub(struct ml *ml, const char *subaddr, + const char *mlmmjsend, enum subtype typesub, + enum subreason reasonsub) +{ + int fd, status; + text *txt; + memory_lines_state *mls; + char *a = NULL, *queuefilename, *from; + char *modfilename, *mods, *to, *replyto, *moderators = NULL; + char *cookie, *obstruct; + strlist *submods; + const char *type; + pid_t childpid, pid; + xstring *str = NULL; + int modfd = -1; + + type = subtypes[typesub]; + + for (;;) { + cookie = random_str(); + xasprintf(&modfilename, "moderation/subscribe%s", cookie); + fd = openat(ml->fd, modfilename, O_RDWR|O_CREAT|O_EXCL, + S_IRUSR|S_IWUSR); + if (fd < 0) { + if (errno == EEXIST) { + free(cookie); + free(modfilename); + continue; + } + log_error(LOG_ARGS, "could not create %s" + "ignoring request for: %s", subaddr); + exit(EXIT_FAILURE); + } + break; + } + + if (dprintf(fd, "%s\n%s\n", subaddr, type) < 0) { + log_error(LOG_ARGS, "could not write to %s" + "ignoring request for: %s", subaddr); + exit(EXIT_FAILURE); + } + close(fd); + + submods = ctrlvalues(ml->ctrlfd, "submod"); + if (submods == NULL) + return; + /* check to see if there's adresses in the submod control file */ + tll_foreach(*submods, it) + a = strchr(it->item, '@'); + + /* no addresses in submod control file, use owner */ + if(a == NULL) { + /* free the submods struct from above */ + tll_free_and_free(*submods, free); + free(submods); + submods = ctrlvalues(ml->ctrlfd, "owner"); + modfd = openat(ml->ctrlfd, "owner", O_RDONLY); + } + if (modfd == -1) + modfd = openat(ml->ctrlfd, "submod", O_RDONLY); + + gen_addr(from, ml, "owner"); + xasprintf(&to, "%s-moderators@%s", ml->name, ml->fqdn); + gen_addr_cookie(replyto, ml, "permit-", cookie); + gen_addr_cookie(obstruct, ml, "obstruct-", cookie); + free(cookie); + tll_foreach(*submods, sm) { + if (str == NULL) + str = xstring_new(); + fprintf(str->fp, "%s\n", sm->item); + } + moderators = xstring_get(str); + mls = init_memory_lines(moderators); + free(moderators); + + txt = open_text(ml->fd, + "gatekeep", "sub", + subreason_strs[reasonsub], subtype_strs[typesub], + "submod-moderator"); + MY_ASSERT(txt); + register_default_unformatted(txt, ml); + register_unformatted(txt, "subaddr", subaddr); + register_unformatted(txt, "moderateaddr", replyto); /* DEPRECATED */ + register_unformatted(txt, "permitaddr", replyto); + register_unformatted(txt, "obstructaddr", obstruct); + register_unformatted(txt, "moderators", "%gatekeepers%"); /* DEPRECATED */ + register_formatted(txt, "gatekeepers", + rewind_memory_lines, get_memory_line, mls); + queuefilename = prepstdreply(txt, ml, "$listowner$", to, replyto); + MY_ASSERT(queuefilename); + close_text(txt); + + /* we might need to exec more than one mlmmj-send */ + + if (statctrl(ml->ctrlfd, "nosubmodmails")) + childpid = -1; + else { + childpid = fork(); + if(childpid < 0) + log_error(LOG_ARGS, "Could not fork; requester not notified"); + } + + if(childpid != 0) { + if(childpid > 0) { + do /* Parent waits for the child */ + pid = waitpid(childpid, &status, 0); + while(pid == -1 && errno == EINTR); + } + finish_memory_lines(mls); + xasprintf(&mods, "%d", modfd); + execl(mlmmjsend, mlmmjsend, + "-a", + "-l", "4", + "-L", ml->dir, + "-s", mods, + "-F", from, + "-R", replyto, + "-m", queuefilename, (char *)NULL); + log_error(LOG_ARGS, "execl() of '%s' failed", mlmmjsend); + exit(EXIT_FAILURE); + } + + free(to); + free(replyto); + + /* send mail to requester that the list is submod'ed */ + + txt = open_text(ml->fd, + "wait", "sub", + subreason_strs[reasonsub], subtype_strs[typesub], + "submod-requester"); + MY_ASSERT(txt); + register_default_unformatted(txt, ml); + register_unformatted(txt, "subaddr", subaddr); + register_unformatted(txt, "moderators", "%gatekeepers"); /* DEPRECATED */ + register_formatted(txt, "gatekeepers", + rewind_memory_lines, get_memory_line, mls); + queuefilename = prepstdreply(txt, ml, "$listowner$", subaddr, NULL); + MY_ASSERT(queuefilename); + close_text(txt); + + finish_memory_lines(mls); + send_help(ml, queuefilename, subaddr); +} + +void getaddrandtype(struct ml *ml, const char *modstr, + char **addrptr, enum subtype *subtypeptr) +{ + int fd; + char *readaddr, *readtype, *modfilename, *line = NULL; + FILE *f; + size_t linecap = 0; + + if (strncmp(modstr, "subscribe", 9) == 0) + modstr += 9; + + xasprintf(&modfilename, "moderation/subscribe%s", modstr); + + fd = openat(ml->fd, modfilename, O_RDONLY); + if(fd < 0) { + log_error(LOG_ARGS, "Could not open %s/%s", ml->dir, modfilename); + exit(EXIT_FAILURE); + } + f = fdopen(fd, "r"); + + if (getline(&line, &linecap, f) <= 0) { + log_error(LOG_ARGS, "Could not parse %s/%s", ml->dir, modfilename); + exit(EXIT_FAILURE); + } + chomp(line); + readaddr = xstrdup(line); + if (getline(&line, &linecap, f) <= 0) { + log_error(LOG_ARGS, "Could not parse %s/%s", ml->dir, modfilename); + exit(EXIT_FAILURE); + } + chomp(line); + readtype = xstrdup(line); + fclose(f); + + *addrptr = readaddr; + + for (size_t i = 0; i < NELEM(subtypes); i++) { + if (subtypes[i] == NULL) + continue; + if (strcmp(subtypes[i], readtype) == 0) { + *subtypeptr = i; + goto freedone; + } + } + + log_error(LOG_ARGS, "Type %s not valid in %s/%s", readtype, + ml->dir, modfilename); + +freedone: + free(readtype); + unlinkat(ml->fd, modfilename, 0); + free(modfilename); +} + +static void print_help(const char *prg) +{ + printf("Usage: %s -L /path/to/list {-a john@doe.org | -m str}\n" + " [-c] [-C] [-f] [-h] [-L] [-d | -n] [-q] [-r | -R] [-s] [-U] [-V]\n" + " -a: Email address to subscribe \n" + " -c: Send welcome mail (unless requesting confirmation)\n" + " -C: Request mail confirmation (unless switching versions)\n" + " -d: Subscribe to digest of list\n" + " -f: Force subscription (do not moderate)\n" + " -h: This help\n" + " -L: Full path to list directory\n" + " -m: moderation string\n" + " -n: Subscribe to no mail version of list\n", prg); + printf(" -q: Be quiet (don't notify owner about the subscription)\n" + " -r: Behave as if request arrived via email (internal use)\n" + " -R: Behave as if confirmation arrived via email (internal use)\n" + " -s: Don't send a mail to subscriber if already subscribed\n" + " -U: Don't switch to the user id of the listdir owner\n" + " -V: Print version\n" + "To ensure a silent subscription, use -f -q -s\n"); + exit(EXIT_SUCCESS); +} + +static void subscribe_type(int listfd, char *address, enum subtype typesub) { + int dirfd;; + char chstr[2]; + const char *subdir; + int groupwritable = 0, subfilefd; + struct stat st; + + dirfd = open_subscriber_directory(listfd, typesub, &subdir); + if (dirfd == -1) + err(EXIT_FAILURE, "cannot open(%s)", subdir); + if (fstat(dirfd, &st) == 0) { + if(st.st_mode & S_IWGRP) { + groupwritable = S_IRGRP|S_IWGRP; + umask(S_IWOTH); + setgid(st.st_gid); + } + } + + chstr[0] = address[0]; + chstr[1] = '\0'; + + subfilefd = openat(dirfd, chstr, O_RDWR|O_CREAT|O_APPEND, + S_IRUSR|S_IWUSR|groupwritable); + if(subfilefd == -1 && !lock(subfilefd, true)) { + log_error(LOG_ARGS, "Could not open '%s/%s'", subdir, chstr); + exit(EXIT_FAILURE); + } + + dprintf(subfilefd, "%s\n", address); + close(dirfd); + close(subfilefd); +} + +int main(int argc, char **argv) +{ + char *mlmmjsend, *bindir; + char *address = NULL, *modstr = NULL; + bool send_welcome_mail = false; + int opt; + bool subconfirm = false, notifysub; + bool changeuid = true, digest = false, nomail = false, both = false; + bool nogensubscribed = false; + bool force = false, quiet = false; + enum subtype subbed; + struct stat st; + uid_t uid; + enum subtype typesub = SUB_NORMAL; + enum subreason reasonsub = SUB_ADMIN; + struct ml ml; + + ml_init(&ml); + CHECKFULLPATH(argv[0]); + + log_set_name(argv[0]); + + bindir = mydirname(argv[0]); + xasprintf(&mlmmjsend, "%s/mlmmj-send", bindir); + free(bindir); + + while ((opt = getopt(argc, argv, "hbcCdfm:nsVUL:a:qrR")) != -1) { + switch(opt) { + case 'a': + if (strchr(optarg, '@') == NULL) + errx(EXIT_FAILURE, "No '@' in the provided email address '%s'", + optarg); + address = optarg; + break; + case 'b': + both = true; + break; + case 'c': + send_welcome_mail = true; + break; + case 'C': + subconfirm = true; + break; + case 'd': + digest = true; + break; + case 'f': + force = true; + break; + case 'h': + print_help(argv[0]); + break; + case 'L': + ml.dir = optarg; + break; + case 'm': + modstr = optarg; + break; + case 'n': + nomail = true; + break; + case 'q': + quiet = true; + break; + case 'r': + reasonsub = SUB_REQUEST; + break; + case 'R': + reasonsub = SUB_CONFIRM; + break; + case 's': + nogensubscribed = true; + break; + case 'U': + changeuid = false; + break; + case 'V': + print_version(argv[0]); + exit(0); + } + } + + if(ml.dir == NULL) { + errx(EXIT_FAILURE, "You have to specify -L\n" + "%s -h for help", argv[0]); + } + if (!ml_open(&ml, false)) + exit(EXIT_FAILURE); + + if(address == NULL && modstr == NULL) { + errx(EXIT_FAILURE, "You have to specify -a or -m\n" + "%s -h for help", argv[0]); + } + + if(both + digest + nomail > 1) { + errx(EXIT_FAILURE, "Specify at most one of -b, -d and -n\n" + "%s -h for help", argv[0]); + } + + if(digest) + typesub = SUB_DIGEST; + if(nomail) + typesub = SUB_NOMAIL; + if(both) + typesub = SUB_BOTH; + + if(reasonsub == SUB_CONFIRM && subconfirm) { + errx(EXIT_FAILURE, "Cannot specify both -C and -R\n" + "%s -h for help", argv[0]); + } + + if(modstr) { + getaddrandtype(&ml, modstr, &address, &typesub); + reasonsub = SUB_PERMIT; + } + + /* Make the address lowercase */ + address = lowercase(address); + - if(strncasecmp(ml.addr, address, strlen(ml.addr)) == 0) ++ if(strncasecmp(ml.addr, address, strlen(ml.addr)) == 0) { ++ free(address); + errx(EXIT_FAILURE, "Cannot subscribe the list address to the list"); ++ } + + if(changeuid) { + uid = getuid(); + if(!uid && fstat(ml.fd, &st) == 0 && uid != st.st_uid) { + printf("Changing to uid %d, owner of %s.\n", + (int)st.st_uid, ml.dir); + if(setuid(st.st_uid) < 0) { + perror("setuid"); + fprintf(stderr, "Continuing as uid %d\n", + (int)uid); + } + } + } + + subbed = is_subbed(ml.fd, address, 1); + + if(subbed == typesub) { + if(!nogensubscribed) + generate_subscription(&ml, address, typesub, true); + return EXIT_SUCCESS; + } else if(subbed != SUB_NONE) { + reasonsub = SUB_SWITCH; + /* If we want to subscribe to both, we can just subscribe the + * missing version, so don't unsub. */ + if (!(typesub == SUB_BOTH && + subbed != SUB_NOMAIL)) { + enum subtype ts = SUB_ALL; + if (subbed == SUB_BOTH) { + if (typesub == SUB_NORMAL) ts = SUB_DIGEST; + if (typesub == SUB_DIGEST) ts = SUB_NORMAL; + } + if (!unsubscribe(ml.fd, address, ts)) + log_error(LOG_ARGS, "not unsubscribed from " + "current version"); + } + } + + if(subbed == SUB_NONE && subconfirm) + generate_subconfirm(&ml, address, typesub, reasonsub, true); + + if(modstr == NULL && subbed == SUB_NONE && !force && + statctrl(ml.ctrlfd, "submod")) { + moderate_sub(&ml, address, mlmmjsend, typesub, reasonsub); + } + + if (typesub == SUB_BOTH) { + if (subbed != SUB_NORMAL) { + subscribe_type(ml.fd, address, SUB_NORMAL); + } + if (subbed != SUB_DIGEST) { + subscribe_type(ml.fd, address, SUB_DIGEST); + } + } else if (!(subbed == SUB_BOTH && typesub != SUB_NOMAIL)) { + subscribe_type(ml.fd, address, typesub); + } + + if(send_welcome_mail) + send_confirmation_mail(&ml, address, typesub, reasonsub, true); + + notifysub = !quiet && reasonsub != SUB_SWITCH && + statctrl(ml.ctrlfd, "notifysub"); + + /* Notify list owner about subscription */ + if (notifysub) + notify_sub(&ml, address, typesub, reasonsub, true); + + free(address); + free(mlmmjsend); + + return EXIT_SUCCESS; +} diff --cc src/send_mail.c index d88df0e2,00000000..4b26e897 mode 100644,000000..100644 --- a/src/send_mail.c +++ b/src/send_mail.c @@@ -1,518 -1,0 +1,520 @@@ +/* + * Copyright (C) 2004, 2003, 2004 Mads Martin Joergensen + * Copyright (C) 2022-2023 Baptiste Daroussin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include + +#include +#include +#include + +#include "checkwait_smtpreply.h" +#include "mail-functions.h" +#include "getlistdelim.h" +#include "send_mail.h" +#include "log_error.h" +#include "init_sockfd.h" +#include "mlmmj.h" +#include "strgen.h" +#include "tllist.h" +#include "xmalloc.h" +#include "ctrlvalue.h" +#include "utils.h" + +int +initsmtp(int *sockfd, const char *relayhost, unsigned short port, const char *heloname) +{ + int retval = 0; + int try_ehlo = 1; + char *reply = NULL; + + do { + init_sockfd(sockfd, relayhost, port); + + if(*sockfd == -1) { + retval = EBADF; + break; + } + + if((reply = checkwait_smtpreply(*sockfd, MLMMJ_CONNECT)) != NULL) { + log_error(LOG_ARGS, "No proper greeting to our connect" + "Reply: [%s]", reply); + free(reply); + retval = MLMMJ_CONNECT; + /* FIXME: Queue etc. */ + break; + } + + if (try_ehlo) { + write_ehlo(*sockfd, heloname); + if((reply = checkwait_smtpreply(*sockfd, MLMMJ_EHLO)) + == NULL) { + /* EHLO successful don't try more */ + break; + } + + /* RFC 1869 - 4.5. - In the case of any error response, + * the client SMTP should issue either the HELO or QUIT + * command. + * RFC 1869 - 4.5. - If the server SMTP recognizes the + * EHLO command, but the command argument is + * unacceptable, it will return code 501. + */ + if (strncmp(reply, "501", 3) == 0) { + free(reply); + /* Commmand unacceptable; we choose to QUIT but + * ignore any QUIT errors; return that EHLO was + * the error. + */ + endsmtp(sockfd); + retval = MLMMJ_EHLO; + break; + } + + /* RFC 1869 - 4.6. - A server SMTP that conforms to RFC + * 821 but does not support the extensions specified + * here will not recognize the EHLO command and will + * consequently return code 500, as specified in RFC + * 821. The server SMTP should stay in the same state + * after returning this code (see section 4.1.1 of RFC + * 821). The client SMTP may then issue either a HELO + * or a QUIT command. + */ + + if (reply[0] != '5') { + free(reply); + /* Server doesn't understand EHLO, but gives a + * broken response. Try with new connection. + */ + endsmtp(sockfd); + try_ehlo = 0; + continue; + } + + free(reply); + + /* RFC 1869 - 4.7. - Other improperly-implemented + * servers will not accept a HELO command after EHLO has + * been sent and rejected. In some cases, this problem + * can be worked around by sending a RSET after the + * failure response to EHLO, then sending the HELO. + */ + write_rset(*sockfd); + reply = checkwait_smtpreply(*sockfd, MLMMJ_RSET); + + /* RFC 1869 - 4.7. - Clients that do this should be + * aware that many implementations will return a failure + * code (e.g., 503 Bad sequence of commands) in response + * to the RSET. This code can be safely ignored. + */ + free(reply); + + /* Try HELO on the same connection + */ + } + + write_helo(*sockfd, heloname); + if((reply = checkwait_smtpreply(*sockfd, MLMMJ_HELO)) + == NULL) { + /* EHLO successful don't try more */ + break; + } + if (try_ehlo) { + free(reply); + /* We reused a connection we tried EHLO on. Maybe + * that's why it failed. Try with new connection. + */ + endsmtp(sockfd); + try_ehlo = 0; + continue; + } + + log_error(LOG_ARGS, "Error with HELO. Reply: " + "[%s]", reply); + free(reply); + /* FIXME: quit and tell admin to configure + * correctly */ + retval = MLMMJ_HELO; + break; + + } while (1); + + return retval; +} + +int +endsmtp(int *sockfd) +{ + int retval = 0; + char *reply = NULL; + + if(*sockfd == -1) + return retval; + + write_quit(*sockfd); + reply = checkwait_smtpreply(*sockfd, MLMMJ_QUIT); + if(reply) { + log_error(LOG_ARGS, "Mailserver would not let us QUIT. " + "We close the socket anyway though. " + "Mailserver reply = [%s]", reply); + free(reply); + retval = MLMMJ_QUIT; + } + + close(*sockfd); + *sockfd = -1; + + return retval; +} + +int do_bouncemail(int listfd, int ctrlfd, const char *from) +{ + /* expected format for the from: "something+anything--anything@anything" */ + char *tofree; + char *myfrom = xstrdup(from); + char *listdelim = getlistdelim(ctrlfd); + char *addr, *num, *c; + + tofree = myfrom; + if((c = strchr(myfrom, '@')) == NULL) { + free(myfrom); + free(listdelim); + return 0; /* Success when malformed 'from' */ + } + *c = '\0'; + num = strrchr(myfrom, '-'); + if (num == NULL) { + free(tofree); + return (0); /* Success when malformed 'from' */ + } + num++; + c = strstr(myfrom, listdelim); + if (c == NULL) { + free(tofree); + return (0); /* Success when malformed 'from' */ + } + myfrom = strchr(c, '-'); /* malformed entry with delimiter after the -num */ + if (myfrom == NULL) { + free(tofree); + return (0); + } + myfrom++; + if (num <= myfrom) { + free(tofree); + return (0); /* Success when malformed 'from' */ + } + addr = xstrndup(myfrom, num - myfrom - 1); + free(listdelim); + + bouncemail(listfd, num, addr); ++ free(tofree); ++ free(addr); + return 1; +} + +int +send_mail(int sockfd, struct mail *mail, int listfd, int ctrlfd, bool bounce) +{ + int retval = 0; + char *reply, *reply2; + + if(sockfd == -1) + return EBADF; + + if (mail->to == NULL) { + errno = 0; + log_error(LOG_ARGS, "No 'to' address, ignoring"); + return (0); + } + + if(strchr(mail->to, '@') == NULL) { + errno = 0; + log_error(LOG_ARGS, "No @ in address, ignoring %s", + mail->to); + return 0; + } + + if (mail->from == NULL) { + errno = 0; + log_error(LOG_ARGS, "No from address, ignoring"); + return 0; + } + + if (mail->fp == NULL) { + errno = 0; + log_error(LOG_ARGS, "No mail to send, ignoring"); + return 0; + } + rewind(mail->fp); + + retval = write_mail_from(sockfd, mail->from, ""); + if(retval) { + log_error(LOG_ARGS, "Could not write MAIL FROM\n"); + return retval; + } + reply = checkwait_smtpreply(sockfd, MLMMJ_FROM); + if(reply) { + log_error(LOG_ARGS, "Error in MAIL FROM. Reply = [%s]", + reply); + free(reply); + write_rset(sockfd); + reply2 = checkwait_smtpreply(sockfd, MLMMJ_RSET); + if (reply2 != NULL) free(reply2); + return MLMMJ_FROM; + } + retval = write_rcpt_to(sockfd, mail->to); + if(retval) { + log_error(LOG_ARGS, "Could not write RCPT TO:\n"); + return retval; + } + + reply = checkwait_smtpreply(sockfd, MLMMJ_RCPTTO); + if(reply) { + write_rset(sockfd); + reply2 = checkwait_smtpreply(sockfd, MLMMJ_RSET); + if (reply2 != NULL) free(reply2); + if(bounce && ((reply[0] == '4') || (reply[0] == '5')) + && (reply[1] == '5')) { + free(reply); + return do_bouncemail(listfd, ctrlfd, mail->from); + } else { + log_error(LOG_ARGS, "Error in RCPT TO. Reply = [%s]", + reply); + free(reply); + return MLMMJ_RCPTTO; + } + } + + retval = write_data(sockfd); + if(retval) { + log_error(LOG_ARGS, "Could not write DATA\b"); + return retval; + } + + reply = checkwait_smtpreply(sockfd, MLMMJ_DATA); + if(reply) { + log_error(LOG_ARGS, "Error with DATA. Reply = [%s]", reply); + free(reply); + write_rset(sockfd); + reply2 = checkwait_smtpreply(sockfd, MLMMJ_RSET); + if (reply2 != NULL) free(reply2); + return MLMMJ_DATA; + } + + if(mail->replyto) { + retval = write_replyto(sockfd, mail->replyto); + if(retval) { + log_error(LOG_ARGS, "Could not write reply-to addr.\n"); + return retval; + } + } + + write_mailbody(sockfd, mail->fp, mail->addtohdr ? mail->to : NULL); + + retval = write_dot(sockfd); + if(retval) { + log_error(LOG_ARGS, "Could not write .\n"); + return retval; + } + + reply = checkwait_smtpreply(sockfd, MLMMJ_DOT); + if(reply) { + log_error(LOG_ARGS, "Mailserver did not ack end of mail.\n" + ". was written, to no" + "avail. Reply = [%s]", reply); + free(reply); + write_rset(sockfd); + reply2 = checkwait_smtpreply(sockfd, MLMMJ_RSET); + if (reply2 != NULL) free(reply2); + return MLMMJ_DOT; + } + + return 0; +} + +int +newsmtp(struct ml *ml) +{ + int sockfd; + char *relayhost, *smtphelo; + unsigned short smtpport = ctrlushort(ml->ctrlfd, "smtpport", 25); + + relayhost = ctrlvalue(ml->ctrlfd, "relayhost"); + if (relayhost == NULL) + relayhost = xstrdup(RELAYHOST); + smtphelo = ctrlvalue(ml->ctrlfd, "smtphelo"); + if (smtphelo == NULL) + smtphelo = hostnamestr(); + if (initsmtp(&sockfd, relayhost, smtpport, smtphelo) != 0) + return (-1); + return (sockfd); +} + +static bool +save_file(const char *name, const char *ext, const char *content) +{ + char *tmpstr; + int fd; + + xasprintf(&tmpstr, "%s.%s", name, ext); + fd = open(tmpstr, O_WRONLY|O_CREAT|O_EXCL|O_SYNC, S_IRUSR|S_IWUSR); + if (fd == -1) { + free(tmpstr); + return (false); + } + dprintf(fd, "%s", content); + close(fd); + free(tmpstr); + return (true); +} + +void +save_queue(const char *queuefilename, struct mail *mail) +{ + if (!save_file(queuefilename, "mailfrom", mail->from)) + return; + if (!save_file(queuefilename, "reciptto", mail->to)) + return; + if (mail->replyto != NULL) + save_file(queuefilename, "reply-to", mail->replyto); +} + +bool +send_single_mail(struct mail *mail, struct ml *ml, bool bounce) +{ + int sockfd; + + sockfd = newsmtp(ml); + if (sockfd == -1) + return (false); + if (send_mail(sockfd, mail, ml->fd, ml->ctrlfd, bounce)) { + endsmtp(&sockfd); + return (false); + } + endsmtp(&sockfd); + return (true); +} + +bool +requeuemail(int listfd, int index, strlist *addrs, const char *addr) +{ + int addrfd, dfd; + char *dirname; + + if (addrs == NULL || tll_length(*addrs) == 0) + return (false); + xasprintf(&dirname, "requeue/%d", index); + if(mkdirat(listfd, dirname, 0750) < 0 && errno != EEXIST) { + log_error(LOG_ARGS, "Could not mkdir(%s) for " + "requeueing. Mail cannot " + "be requeued.", dirname); + free(dirname); + return (false); + } + dfd = openat(listfd, dirname, O_DIRECTORY); + addrfd = openat(dfd, "subscribers", O_WRONLY|O_CREAT|O_APPEND, + S_IRUSR|S_IWUSR); + if(addrfd < 0) { + log_error(LOG_ARGS, "Could not open %s/subscribers", + dirname); + free(dirname); + close(dfd); + return (false); + } + free(dirname); + close(dfd); + /* Dump the remaining addresses. We dump the remaining before + * we write the failing address to ensure the potential good + * ones will be tried first when mlmmj-maintd sends out mails + * that have been requeued. addrcount was so far we were */ + tll_foreach(*addrs, it) { + dprintf(addrfd, "%s\n", it->item); + } + if (addr != NULL) + dprintf(addrfd, "%s\n", addr); + close(addrfd); + + return (true); +} + +char * +get_bounce_from_adr(const char *recipient, struct ml *ml, int index) +{ + char *bounceaddr, *myrecipient; + char *a = NULL; + char *staticbounceaddr, *staticbounceaddr_localpart = NULL; + const char *staticbounceaddr_domain = NULL; + + myrecipient = xstrdup(recipient); + a = strchr(myrecipient, '@'); + if (a) + *a = '='; + + staticbounceaddr = ctrlvalue(ml->ctrlfd, "staticbounceaddr"); + if (staticbounceaddr) { + staticbounceaddr_localpart = genlistname(staticbounceaddr); + staticbounceaddr_domain = genlistfqdn(staticbounceaddr); + } + + if (staticbounceaddr) { + xasprintf(&bounceaddr, "%s%s%s-bounces-%d-%s@%s", + staticbounceaddr_localpart, ml->delim, ml->name, + index, myrecipient, staticbounceaddr_domain); + + free(staticbounceaddr); + free(staticbounceaddr_localpart); + } else { + xasprintf(&bounceaddr, "%s%sbounces-%d-%s@%s", ml->name, + ml->delim, index, myrecipient, ml->fqdn); + } + + free(myrecipient); + + return bounceaddr; +} + +int +get_index_from_filename(const char *filename) +{ + char *myfilename, *indexstr; + int ret; + size_t len; + + myfilename = xstrdup(filename); + len = strlen(myfilename); + if (len > 9 && (strcmp(myfilename + len - 9, "/mailfile") == 0)) { + myfilename[len - 9] = '\0'; + } + + indexstr = strrchr(myfilename, '/'); + if (indexstr) { + indexstr++; /* skip the slash */ + } else { + indexstr = myfilename; + } + + ret = strtoim(indexstr, 0, INT_MAX, NULL); + free(myfilename); + + return ret; +} +