Compare commits
659 Commits
postfixadm
...
master
Author | SHA1 | Date |
---|---|---|
![]() |
864065cd37 | 4 years ago |
![]() |
192c797fe1 | 4 years ago |
![]() |
052f2faffb | 4 years ago |
![]() |
85e15790bb | 4 years ago |
![]() |
ad4142134a | 4 years ago |
![]() |
9833a8f289 | 4 years ago |
![]() |
4e9e3db75d | 4 years ago |
![]() |
fc464d6e69 | 4 years ago |
![]() |
df9a400ea2 | 4 years ago |
![]() |
fd48714615 | 4 years ago |
![]() |
44c3ac5e20 | 4 years ago |
![]() |
be0105b33e | 4 years ago |
![]() |
f17c722f0b | 4 years ago |
![]() |
844840c6a8 | 4 years ago |
![]() |
e4158d6d7e | 4 years ago |
![]() |
f8415eef2a | 4 years ago |
![]() |
ffc7787b76 | 4 years ago |
![]() |
3cd62f9f4f | 4 years ago |
![]() |
5e8ce2b5b0 | 4 years ago |
![]() |
c69211ca5f | 4 years ago |
![]() |
eea72e0019 | 4 years ago |
![]() |
3b704715dc | 4 years ago |
![]() |
dec4b38f35 | 4 years ago |
![]() |
531a52e053 | 4 years ago |
![]() |
4d10a2c4bb | 4 years ago |
![]() |
d81363541a | 4 years ago |
![]() |
338fb8c564 | 4 years ago |
![]() |
d3295a59bb | 4 years ago |
![]() |
d540d904db | 4 years ago |
![]() |
3303f25bcc | 4 years ago |
![]() |
1c0fd02323 | 4 years ago |
![]() |
d6869a4d35 | 4 years ago |
![]() |
3b9d8f867e | 4 years ago |
![]() |
48e236ffc0 | 4 years ago |
![]() |
dd52a98d43 | 4 years ago |
![]() |
8f20c96278 | 4 years ago |
![]() |
fefe3f7df5 | 4 years ago |
![]() |
d2b8f7ac15 | 4 years ago |
![]() |
8754af58cb | 4 years ago |
![]() |
3b1fffdf22 | 4 years ago |
![]() |
5e1a4e27dd | 4 years ago |
![]() |
e49c25139e | 4 years ago |
![]() |
7f58163d65 | 4 years ago |
![]() |
70fe1f93f2 | 4 years ago |
![]() |
50bbae62f4 | 4 years ago |
![]() |
591ea333ea | 4 years ago |
![]() |
22bb34ff60 | 4 years ago |
![]() |
a00e551a8a | 4 years ago |
![]() |
71966ce917 | 4 years ago |
![]() |
3809cf905f | 4 years ago |
![]() |
fddd450df0 | 4 years ago |
![]() |
cd6386bdea | 4 years ago |
![]() |
6c3d595c0b | 4 years ago |
![]() |
e661f2445a | 4 years ago |
![]() |
b6c7d1418d | 4 years ago |
![]() |
2444b0c16b | 4 years ago |
![]() |
cffcd1c4ec | 4 years ago |
![]() |
79ee5f82cb | 4 years ago |
![]() |
01b4d6c587 | 4 years ago |
![]() |
30f97c97ee | 4 years ago |
![]() |
6a7abbe663 | 4 years ago |
![]() |
28a3f5f157 | 4 years ago |
![]() |
a4afebbe77 | 4 years ago |
![]() |
6edbda45e2 | 4 years ago |
![]() |
1ecada175c | 4 years ago |
![]() |
212415db56 | 4 years ago |
![]() |
4cbd82d750 | 4 years ago |
![]() |
2a1383ee2e | 4 years ago |
![]() |
5b16f4a483 | 4 years ago |
![]() |
9dfc866edd | 4 years ago |
![]() |
eb5fcf829e | 4 years ago |
![]() |
97c2b582a3 | 4 years ago |
![]() |
268daa892d | 4 years ago |
![]() |
6a10c869e5 | 4 years ago |
![]() |
eb83a0aa3f | 4 years ago |
![]() |
95d92a2345 | 4 years ago |
![]() |
ec2fbfd87f | 4 years ago |
![]() |
fd35dada38 | 4 years ago |
![]() |
bee61f329b | 4 years ago |
![]() |
3d0add075a | 4 years ago |
![]() |
666bb0218a | 4 years ago |
![]() |
416a71d604 | 4 years ago |
![]() |
80a0faa633 | 4 years ago |
![]() |
cabd97ff17 | 4 years ago |
![]() |
036245063e | 4 years ago |
![]() |
fc3cd79f21 | 4 years ago |
![]() |
352ae80395 | 4 years ago |
![]() |
5f772afe14 | 4 years ago |
![]() |
1ad184641d | 4 years ago |
![]() |
882b6835ed | 4 years ago |
![]() |
038a08d838 | 4 years ago |
![]() |
c0bd763c53 | 4 years ago |
![]() |
55661a80c6 | 4 years ago |
![]() |
aa37ab57e6 | 4 years ago |
![]() |
79c2e77a00 | 4 years ago |
![]() |
d0f254faee | 4 years ago |
![]() |
6582678173 | 4 years ago |
![]() |
47618bf5a3 | 5 years ago |
![]() |
52e0d3e4b0 | 5 years ago |
![]() |
4b0b6904ca | 5 years ago |
![]() |
48e07e7a5f | 5 years ago |
![]() |
d6bbecaf45 | 5 years ago |
![]() |
6a4b7ec163 | 5 years ago |
![]() |
8828d28bbc | 5 years ago |
![]() |
06f57767bd | 5 years ago |
![]() |
125113d83c | 5 years ago |
![]() |
115ff22761 | 5 years ago |
![]() |
c1bdfe5432 | 5 years ago |
![]() |
bcae218cbb | 5 years ago |
![]() |
87824ef970 | 5 years ago |
![]() |
1df7f15d40 | 5 years ago |
![]() |
4aa3110712 | 5 years ago |
![]() |
ccd74cc506 | 5 years ago |
![]() |
13549cea0f | 5 years ago |
![]() |
61cb429845 | 5 years ago |
![]() |
b8d7c0513f | 5 years ago |
![]() |
e20b2cacdb | 5 years ago |
![]() |
174b874c56 | 5 years ago |
![]() |
9526e68e3e | 5 years ago |
![]() |
907bd7ee46 | 5 years ago |
![]() |
7360407b73 | 5 years ago |
![]() |
58b064f1c8 | 5 years ago |
![]() |
9c4caf1045 | 5 years ago |
![]() |
c66755a0da | 5 years ago |
![]() |
cd8cf289b4 | 5 years ago |
![]() |
a03317e088 | 5 years ago |
![]() |
f61cb513ae | 5 years ago |
![]() |
0e9a1ff0ff | 5 years ago |
![]() |
f4a5155f7a | 5 years ago |
![]() |
a485a2d861 | 5 years ago |
![]() |
946c47dd66 | 5 years ago |
![]() |
2742849e7b | 5 years ago |
![]() |
958df260ec | 5 years ago |
![]() |
7965a83aff | 5 years ago |
![]() |
34e6f7829e | 5 years ago |
![]() |
034a50836c | 5 years ago |
![]() |
a603d36224 | 5 years ago |
![]() |
29d990f5f4 | 5 years ago |
![]() |
71e7859c91 | 5 years ago |
![]() |
f36ba9b4c2 | 5 years ago |
![]() |
28bef9e136 | 5 years ago |
![]() |
4081267cb2 | 5 years ago |
![]() |
f7c7e35b34 | 5 years ago |
![]() |
f8713651cc | 5 years ago |
![]() |
80418e6412 | 5 years ago |
![]() |
17a50c51f1 | 5 years ago |
![]() |
2ff05bc737 | 5 years ago |
![]() |
9cd7dac187 | 5 years ago |
![]() |
284d4b2eb0 | 5 years ago |
![]() |
0c94760828 | 5 years ago |
![]() |
758ccb9a19 | 5 years ago |
![]() |
34cf66110e | 5 years ago |
![]() |
3551710b82 | 5 years ago |
![]() |
86852b3dbd | 5 years ago |
![]() |
60c44a3ca3 | 5 years ago |
![]() |
53cefa1107 | 5 years ago |
![]() |
3295334dd7 | 5 years ago |
![]() |
0f64f22a7e | 5 years ago |
![]() |
bc273a97e4 | 5 years ago |
![]() |
e8fb276c2f | 5 years ago |
![]() |
1941f970bd | 5 years ago |
![]() |
6a89b9a363 | 5 years ago |
![]() |
bee5fcbe24 | 5 years ago |
![]() |
fa27c7c8b7 | 5 years ago |
![]() |
7b18d0386c | 5 years ago |
![]() |
296fc2f48e | 5 years ago |
![]() |
c3d3a9dbc8 | 5 years ago |
![]() |
a0b4e690b2 | 5 years ago |
![]() |
d788c6ac99 | 5 years ago |
![]() |
8ba1cf20a7 | 5 years ago |
![]() |
55bf13298e | 5 years ago |
![]() |
88587f4cd3 | 5 years ago |
![]() |
7583decbcb | 5 years ago |
![]() |
c3065bdace | 5 years ago |
![]() |
a46245eecc | 5 years ago |
![]() |
61ede42800 | 5 years ago |
![]() |
8b19ef21cf | 5 years ago |
![]() |
c53d17fff7 | 5 years ago |
![]() |
01477f0009 | 5 years ago |
![]() |
600248e955 | 5 years ago |
![]() |
55858bf3a0 | 5 years ago |
![]() |
651688c802 | 5 years ago |
![]() |
1d1960a476 | 5 years ago |
![]() |
ae476950f2 | 5 years ago |
![]() |
3ff2436f2f | 5 years ago |
![]() |
8e2e4eb189 | 5 years ago |
![]() |
03b9483204 | 5 years ago |
![]() |
95429a6963 | 5 years ago |
![]() |
3322b43bb6 | 5 years ago |
![]() |
78764578db | 5 years ago |
![]() |
d64eadf609 | 5 years ago |
![]() |
cc19870923 | 5 years ago |
![]() |
87746e6de8 | 5 years ago |
![]() |
5d0a587fe7 | 5 years ago |
![]() |
31de6c6d66 | 5 years ago |
![]() |
16bf5cab7f | 5 years ago |
![]() |
71402e9051 | 5 years ago |
![]() |
ad858592f4 | 5 years ago |
![]() |
7ed4df5459 | 5 years ago |
![]() |
23a7f1bfda | 5 years ago |
![]() |
3fc5c74040 | 5 years ago |
![]() |
d4d47e02cc | 5 years ago |
![]() |
684cf3d829 | 5 years ago |
![]() |
56395709f3 | 5 years ago |
![]() |
852a09f138 | 5 years ago |
![]() |
dcef888587 | 5 years ago |
![]() |
045a19ae33 | 5 years ago |
![]() |
7ed57a0cda | 5 years ago |
![]() |
9024dddf46 | 5 years ago |
![]() |
b8ee437169 | 5 years ago |
![]() |
df99e66b2d | 5 years ago |
![]() |
4a084d91b5 | 5 years ago |
![]() |
000416c401 | 5 years ago |
![]() |
e9ed15143e | 5 years ago |
![]() |
de5b739d4a | 5 years ago |
![]() |
28e687ff5b | 5 years ago |
![]() |
7718ca808d | 5 years ago |
![]() |
2a0f708529 | 5 years ago |
![]() |
215daecf29 | 5 years ago |
![]() |
361f0ccb22 | 5 years ago |
![]() |
9ccf5250cd | 5 years ago |
![]() |
81fed601a2 | 5 years ago |
![]() |
06513c2a14 | 5 years ago |
![]() |
079462bb29 | 5 years ago |
![]() |
496657aa5d | 5 years ago |
![]() |
d6fc337272 | 5 years ago |
![]() |
2e87464fc8 | 5 years ago |
![]() |
d30c122f37 | 5 years ago |
![]() |
018f5d9e05 | 5 years ago |
![]() |
fe48b35cfd | 5 years ago |
![]() |
4cb36857da | 5 years ago |
![]() |
f52aa9929a | 5 years ago |
![]() |
9cc04df973 | 5 years ago |
![]() |
8632cbd1a9 | 5 years ago |
![]() |
17a420152c | 5 years ago |
![]() |
d95ee79b9a | 5 years ago |
![]() |
69b9d9671c | 5 years ago |
![]() |
dcb60a670c | 5 years ago |
![]() |
4d7ac16bfb | 5 years ago |
![]() |
730a05cdd3 | 5 years ago |
![]() |
ed99a46ec4 | 5 years ago |
![]() |
db4aecd23c | 5 years ago |
![]() |
237f34d38f | 5 years ago |
![]() |
47bbb7c2a3 | 5 years ago |
![]() |
a05f87723f | 5 years ago |
![]() |
28870e4b45 | 5 years ago |
![]() |
0afdb5619b | 5 years ago |
![]() |
b4564958a1 | 5 years ago |
![]() |
a71669fba8 | 5 years ago |
![]() |
b37e3c859d | 5 years ago |
![]() |
637220a3fb | 5 years ago |
![]() |
5528d8be30 | 5 years ago |
![]() |
4f2dab357c | 5 years ago |
![]() |
ceae3caa37 | 5 years ago |
![]() |
92d6259cd0 | 5 years ago |
![]() |
76e30d1dd3 | 5 years ago |
![]() |
c71dd25afa | 5 years ago |
![]() |
888524af99 | 5 years ago |
![]() |
4d24ab7171 | 5 years ago |
![]() |
2cf73f704a | 5 years ago |
![]() |
93a127d7f2 | 5 years ago |
![]() |
63f63a58b7 | 5 years ago |
![]() |
5bc85bec44 | 5 years ago |
![]() |
acf20bbc9e | 5 years ago |
![]() |
a2e2cdce8c | 5 years ago |
![]() |
66747337f9 | 5 years ago |
![]() |
583b8958c7 | 5 years ago |
![]() |
7f8fd5ec1a | 5 years ago |
![]() |
83a4ee39b0 | 5 years ago |
![]() |
26d769740c | 5 years ago |
![]() |
e9d12bf918 | 5 years ago |
![]() |
7838e85ff0 | 6 years ago |
![]() |
5db463b35c | 6 years ago |
![]() |
6225899863 | 6 years ago |
![]() |
e6666e0af0 | 6 years ago |
![]() |
cef2ba5598 | 6 years ago |
![]() |
fb1bffbbf9 | 6 years ago |
![]() |
e347b4677b | 6 years ago |
![]() |
570972944d | 6 years ago |
![]() |
10446a0cad | 6 years ago |
![]() |
5d47b85b9d | 6 years ago |
![]() |
5a9efc18f0 | 6 years ago |
![]() |
3da5b64677 | 6 years ago |
![]() |
9bb00499c7 | 6 years ago |
![]() |
18312a8aaa | 6 years ago |
![]() |
cc079b773f | 6 years ago |
![]() |
020343999a | 6 years ago |
![]() |
98536f03e8 | 6 years ago |
![]() |
e26877f2f9 | 6 years ago |
![]() |
803e2342f8 | 6 years ago |
![]() |
1176c9ce78 | 6 years ago |
![]() |
ea33d9951a | 6 years ago |
![]() |
eb61141d2f | 6 years ago |
![]() |
51320919fc | 6 years ago |
![]() |
ccb000467d | 6 years ago |
![]() |
67010c86e3 | 6 years ago |
![]() |
a500d2557e | 6 years ago |
![]() |
d78fb1fbbd | 6 years ago |
![]() |
e5cacbec90 | 6 years ago |
![]() |
78276534d9 | 6 years ago |
![]() |
7e7f644952 | 6 years ago |
![]() |
897893f3ce | 6 years ago |
![]() |
8a59c9548a | 6 years ago |
![]() |
e8eea39b9d | 6 years ago |
![]() |
2b31e71d5c | 6 years ago |
![]() |
8798a65a06 | 6 years ago |
![]() |
cdacb5697f | 6 years ago |
![]() |
2ea829eb7a | 6 years ago |
![]() |
b91c7a4ef8 | 6 years ago |
![]() |
4b990ff330 | 6 years ago |
![]() |
d4e5470f7c | 6 years ago |
![]() |
4d6cb9c328 | 6 years ago |
![]() |
63ca48eb6b | 6 years ago |
![]() |
5441295e25 | 6 years ago |
![]() |
d4ef211a19 | 6 years ago |
![]() |
b2e814967f | 6 years ago |
![]() |
590c80f0bc | 6 years ago |
![]() |
e8acb609c2 | 6 years ago |
![]() |
20b1eb842e | 6 years ago |
![]() |
1dfb03ea32 | 6 years ago |
![]() |
e949e76acd | 6 years ago |
![]() |
4fcdba9cf4 | 6 years ago |
![]() |
5eba76ac36 | 6 years ago |
![]() |
19cda31849 | 6 years ago |
![]() |
d74b276192 | 6 years ago |
![]() |
9c476be17f | 6 years ago |
![]() |
93967030c7 | 6 years ago |
![]() |
5d6dde7bff | 6 years ago |
![]() |
76ec4bc84d | 6 years ago |
![]() |
5bc6e93347 | 6 years ago |
![]() |
77b87107f9 | 6 years ago |
![]() |
59dc05d746 | 6 years ago |
![]() |
766c947190 | 6 years ago |
![]() |
166574efae | 6 years ago |
![]() |
5d74ff4cc7 | 6 years ago |
![]() |
01c8b14a44 | 6 years ago |
![]() |
d146f51feb | 6 years ago |
![]() |
74002bbf57 | 6 years ago |
![]() |
8d2a592aa9 | 6 years ago |
![]() |
029c4ffe47 | 6 years ago |
![]() |
7408a3b30a | 6 years ago |
![]() |
173d5775cd | 6 years ago |
![]() |
97528f3ebd | 6 years ago |
![]() |
93cc4d9e8c | 6 years ago |
![]() |
9b8c067515 | 6 years ago |
![]() |
8cf7947f15 | 6 years ago |
![]() |
cecfe6b215 | 6 years ago |
![]() |
18be203039 | 6 years ago |
![]() |
878e4d7f11 | 6 years ago |
![]() |
3ee8b497f1 | 6 years ago |
![]() |
d35e66808b | 6 years ago |
![]() |
1fea1f8c3b | 6 years ago |
![]() |
dda0302cdf | 6 years ago |
![]() |
3960f6fdad | 6 years ago |
![]() |
55790f9835 | 6 years ago |
![]() |
9598c63fc0 | 6 years ago |
![]() |
a53165d3d8 | 6 years ago |
![]() |
69e234f668 | 6 years ago |
![]() |
78a461f07e | 6 years ago |
![]() |
b4a16a0313 | 6 years ago |
![]() |
435d97c282 | 6 years ago |
![]() |
056e8af99b | 6 years ago |
![]() |
bd847e38e6 | 6 years ago |
![]() |
9e4d64ef78 | 6 years ago |
![]() |
3a8762d785 | 6 years ago |
![]() |
9e8ce47849 | 6 years ago |
![]() |
87472af5ba | 6 years ago |
![]() |
b1795ab596 | 6 years ago |
![]() |
1e158245d6 | 6 years ago |
![]() |
afd418675c | 6 years ago |
![]() |
a8b02cfc05 | 6 years ago |
![]() |
77d1b6c2e7 | 6 years ago |
![]() |
27c2842cd2 | 6 years ago |
![]() |
a455916a6b | 6 years ago |
![]() |
8115d8d047 | 6 years ago |
![]() |
12ce418f79 | 6 years ago |
![]() |
84533224ba | 6 years ago |
![]() |
b33d79125c | 6 years ago |
![]() |
d809e0fbf7 | 6 years ago |
![]() |
72dddbc93b | 6 years ago |
![]() |
ce60b9fa59 | 6 years ago |
![]() |
ab10c9b49a | 6 years ago |
![]() |
9be8c8082f | 6 years ago |
![]() |
29a993e6fd | 6 years ago |
![]() |
e786609aa9 | 6 years ago |
![]() |
c3d3898eb2 | 6 years ago |
![]() |
cde3d7530d | 6 years ago |
![]() |
61011619a8 | 6 years ago |
![]() |
ba14535489 | 6 years ago |
![]() |
a981ff8172 | 6 years ago |
![]() |
77670f36f6 | 6 years ago |
![]() |
39bb2dbcd6 | 6 years ago |
![]() |
c5c42cfbe8 | 6 years ago |
![]() |
00877885cf | 6 years ago |
![]() |
6d328795cb | 6 years ago |
![]() |
563b8c7636 | 6 years ago |
![]() |
45fd1bf08b | 6 years ago |
![]() |
532eb09f1f | 6 years ago |
![]() |
76ee147375 | 6 years ago |
![]() |
aa38d0090d | 6 years ago |
![]() |
97c48a0fc9 | 6 years ago |
![]() |
299735773e | 6 years ago |
![]() |
ec085b668b | 6 years ago |
![]() |
9c0e1dd575 | 6 years ago |
![]() |
318ac048d5 | 6 years ago |
![]() |
c44e82cc2d | 6 years ago |
![]() |
b6f75c9c2c | 6 years ago |
![]() |
1f643a052f | 6 years ago |
![]() |
a787c0fc1e | 6 years ago |
![]() |
2df4348f09 | 6 years ago |
![]() |
48c19a1cbd | 6 years ago |
![]() |
c1b5e66e27 | 6 years ago |
![]() |
b676e8337f | 6 years ago |
![]() |
7b16e8a1c2 | 6 years ago |
![]() |
9c2161a549 | 6 years ago |
![]() |
6100ca4cf9 | 6 years ago |
![]() |
1c4a6080d7 | 6 years ago |
![]() |
9c7f60fa76 | 6 years ago |
![]() |
3754381f0e | 6 years ago |
![]() |
11f9680963 | 6 years ago |
![]() |
05bf2d2013 | 6 years ago |
![]() |
2eb5a7ed60 | 6 years ago |
![]() |
bd85b3725f | 6 years ago |
![]() |
5dcd203d8f | 6 years ago |
![]() |
fb3e968cfc | 6 years ago |
![]() |
603c5195df | 6 years ago |
![]() |
9044bed288 | 6 years ago |
![]() |
b4849b8431 | 6 years ago |
![]() |
4c6bcdbc39 | 6 years ago |
![]() |
a510981350 | 6 years ago |
![]() |
5b7f4cda48 | 6 years ago |
![]() |
7282928e6d | 6 years ago |
![]() |
7388a7ca62 | 6 years ago |
![]() |
a3feba7c73 | 6 years ago |
![]() |
bd5ac21398 | 6 years ago |
![]() |
1308c52355 | 6 years ago |
![]() |
b48f99d4c6 | 6 years ago |
![]() |
e7f9d536d9 | 6 years ago |
![]() |
f7ba904800 | 6 years ago |
![]() |
f1a15b2269 | 6 years ago |
![]() |
2f2730ffa0 | 6 years ago |
![]() |
f543c7d403 | 6 years ago |
![]() |
94f05bf9e4 | 6 years ago |
![]() |
7c0cb82be8 | 6 years ago |
![]() |
0d211949c9 | 6 years ago |
![]() |
b97decb7c2 | 6 years ago |
![]() |
a4760ef53c | 6 years ago |
![]() |
11f0ceb615 | 6 years ago |
![]() |
b25a04a43f | 6 years ago |
![]() |
3ea4f80e34 | 6 years ago |
![]() |
24ad5cc3d8 | 6 years ago |
![]() |
7c38bdd871 | 6 years ago |
![]() |
f0f6c16afa | 6 years ago |
![]() |
7f19cae57e | 6 years ago |
![]() |
f05f118d4d | 6 years ago |
![]() |
2ba2802774 | 6 years ago |
![]() |
9a07772626 | 6 years ago |
![]() |
11ded0a4d8 | 6 years ago |
![]() |
3f1866d041 | 6 years ago |
![]() |
cdf3c9acb9 | 6 years ago |
![]() |
30c61e81b3 | 6 years ago |
![]() |
cd0a718d52 | 6 years ago |
![]() |
d2588a4de2 | 6 years ago |
![]() |
5e4e0bb426 | 6 years ago |
![]() |
957657c853 | 6 years ago |
![]() |
9bd230cd46 | 6 years ago |
![]() |
c7201afa6c | 6 years ago |
![]() |
12c4a4f29e | 6 years ago |
![]() |
71d61a1d8a | 6 years ago |
![]() |
48a3709041 | 6 years ago |
![]() |
36fe1f6ccc | 6 years ago |
![]() |
5e93dfe604 | 6 years ago |
![]() |
500c847fe0 | 6 years ago |
![]() |
91c07c9eae | 6 years ago |
![]() |
4f1dd314e7 | 6 years ago |
![]() |
04b73c1879 | 6 years ago |
![]() |
4fb4d406ee | 6 years ago |
![]() |
fef2591335 | 6 years ago |
![]() |
59a220d8d2 | 6 years ago |
![]() |
bf840f93cd | 6 years ago |
![]() |
6c12800a78 | 6 years ago |
![]() |
7cb36bc0b2 | 6 years ago |
![]() |
2f7d3d9534 | 6 years ago |
![]() |
f8d7844767 | 6 years ago |
![]() |
898a8145f2 | 6 years ago |
![]() |
9ab2eaedc6 | 6 years ago |
![]() |
d986e26be8 | 6 years ago |
![]() |
b64e202508 | 6 years ago |
![]() |
50ac4c7597 | 6 years ago |
![]() |
d57aa46eb5 | 6 years ago |
![]() |
2a1d8daeba | 6 years ago |
![]() |
3228fa1fcb | 6 years ago |
![]() |
b79ad2ae28 | 6 years ago |
![]() |
6446f3f6cc | 6 years ago |
![]() |
6ed1527497 | 6 years ago |
![]() |
12242b0893 | 6 years ago |
![]() |
9462c0cb7b | 6 years ago |
![]() |
cb34da4f46 | 6 years ago |
![]() |
2dc502e684 | 6 years ago |
![]() |
68a42dd331 | 6 years ago |
![]() |
152975d05c | 6 years ago |
![]() |
c147eb053b | 6 years ago |
![]() |
43a2493876 | 6 years ago |
![]() |
4dec9cd24e | 6 years ago |
![]() |
d088651fd6 | 6 years ago |
![]() |
0b66cd6bd2 | 6 years ago |
![]() |
4e9d166765 | 6 years ago |
![]() |
45a1073b97 | 6 years ago |
![]() |
8ac94394cb | 6 years ago |
![]() |
e2b1233269 | 6 years ago |
![]() |
5e1855632a | 6 years ago |
![]() |
2615b6fece | 6 years ago |
![]() |
2b8e6ff5b4 | 6 years ago |
![]() |
d0897f625d | 6 years ago |
![]() |
9bef45aed5 | 6 years ago |
![]() |
d305374568 | 6 years ago |
![]() |
220f8289c7 | 6 years ago |
![]() |
68934539bf | 6 years ago |
![]() |
828e3b2290 | 6 years ago |
![]() |
aad433eceb | 6 years ago |
![]() |
c3b87ebb11 | 6 years ago |
![]() |
06f6c71c56 | 6 years ago |
![]() |
15df6c1d7b | 6 years ago |
![]() |
943c5a94ee | 6 years ago |
![]() |
5e8e1dd5f0 | 6 years ago |
![]() |
f0be0ebf62 | 6 years ago |
![]() |
2bb583a86a | 6 years ago |
![]() |
d259544515 | 6 years ago |
![]() |
d5c40453ac | 6 years ago |
![]() |
63f44c9b2d | 6 years ago |
![]() |
104561c419 | 6 years ago |
![]() |
3d63d8b9af | 6 years ago |
![]() |
99147d51eb | 6 years ago |
![]() |
436bbe87a8 | 6 years ago |
![]() |
e1d42ed7d3 | 6 years ago |
![]() |
2fc3af0b73 | 6 years ago |
![]() |
80d30d81e9 | 6 years ago |
![]() |
d9f66eca4c | 6 years ago |
![]() |
6f7e75dc63 | 6 years ago |
![]() |
3593d23c6f | 6 years ago |
![]() |
772a882c74 | 6 years ago |
![]() |
97f0fa2c3d | 6 years ago |
![]() |
938e7dcb7d | 6 years ago |
![]() |
e4bfae260b | 6 years ago |
![]() |
75bcf3091b | 7 years ago |
![]() |
3bd7ef2b0a | 7 years ago |
![]() |
9982783481 | 7 years ago |
![]() |
70c839cbc6 | 7 years ago |
![]() |
a52eeaf020 | 7 years ago |
![]() |
9aeec2147e | 7 years ago |
![]() |
9b7cfdf807 | 7 years ago |
![]() |
a320b67508 | 7 years ago |
![]() |
977f335a0f | 7 years ago |
![]() |
d04c82fbcb | 7 years ago |
![]() |
ddb94e24ee | 7 years ago |
![]() |
1c0cd61fff | 7 years ago |
![]() |
ab666b6b7f | 7 years ago |
![]() |
8fb67e6fbf | 7 years ago |
![]() |
a27f80c01d | 7 years ago |
![]() |
24b447f8e5 | 7 years ago |
![]() |
a4467a7e0b | 7 years ago |
![]() |
7b8626ca81 | 7 years ago |
![]() |
e478eb8b9f | 7 years ago |
![]() |
37d4279c52 | 7 years ago |
![]() |
43fb0bde77 | 7 years ago |
![]() |
b06d25de8f | 7 years ago |
![]() |
0972df8243 | 7 years ago |
![]() |
768d29623e | 7 years ago |
![]() |
7afb26fcc8 | 7 years ago |
![]() |
bdade520f4 | 7 years ago |
![]() |
5f1ac12d72 | 7 years ago |
![]() |
8bd435039b | 7 years ago |
![]() |
ebbd9025e4 | 7 years ago |
![]() |
dbbc40b327 | 7 years ago |
![]() |
ba47f2df2a | 7 years ago |
![]() |
72f32f0b3d | 7 years ago |
![]() |
f217524524 | 7 years ago |
![]() |
5720e73732 | 7 years ago |
![]() |
a77d08a92c | 7 years ago |
![]() |
699267a915 | 7 years ago |
![]() |
356ca84144 | 7 years ago |
![]() |
0f09b8c176 | 7 years ago |
![]() |
17e347de7f | 7 years ago |
![]() |
90d3a0ded7 | 7 years ago |
![]() |
56e1215994 | 7 years ago |
![]() |
4670182d79 | 7 years ago |
![]() |
fe5e256b6d | 7 years ago |
![]() |
ffb84283c2 | 7 years ago |
![]() |
8bb6000072 | 7 years ago |
![]() |
db06ac919c | 7 years ago |
![]() |
f568309ef5 | 7 years ago |
![]() |
39dca79879 | 7 years ago |
![]() |
c5136c408d | 7 years ago |
![]() |
ec2cc0041e | 7 years ago |
![]() |
ae56c2b700 | 7 years ago |
![]() |
dd06aa75e0 | 7 years ago |
![]() |
252d42dcc0 | 7 years ago |
![]() |
5c2e3d1e00 | 7 years ago |
![]() |
6258cc669d | 7 years ago |
![]() |
2fc36e82ad | 7 years ago |
![]() |
4b999b3f6b | 7 years ago |
![]() |
3c95ec4a09 | 7 years ago |
![]() |
9f30aa5ff4 | 7 years ago |
![]() |
74c29f8a10 | 7 years ago |
![]() |
82e7bdfda3 | 7 years ago |
![]() |
9dbeb68f9a | 7 years ago |
![]() |
2b04b72072 | 7 years ago |
![]() |
9b16645c0f | 7 years ago |
![]() |
72288b8402 | 7 years ago |
![]() |
0b70b5c686 | 7 years ago |
![]() |
dbe8475ed2 | 7 years ago |
![]() |
9841c7c86b | 7 years ago |
![]() |
c476a61ec4 | 7 years ago |
![]() |
14ec596cbf | 7 years ago |
![]() |
a40e99c8ed | 7 years ago |
![]() |
2251c00fb8 | 7 years ago |
![]() |
f3b2fe68f1 | 7 years ago |
![]() |
7a0b3b3750 | 7 years ago |
![]() |
9c9ba64a7f | 7 years ago |
![]() |
25f50f262d | 7 years ago |
![]() |
1f63a9df89 | 7 years ago |
![]() |
da9f674611 | 7 years ago |
![]() |
8d2223acfa | 7 years ago |
![]() |
6442c8aff4 | 7 years ago |
![]() |
ba8a4ab659 | 7 years ago |
![]() |
76f0387313 | 7 years ago |
![]() |
7f2ea1a20a | 7 years ago |
![]() |
c3a4a6ed8d | 7 years ago |
![]() |
d98e83e624 | 7 years ago |
![]() |
066a22cb42 | 7 years ago |
![]() |
f2d4e6dbcc | 7 years ago |
![]() |
34474a20e5 | 7 years ago |
![]() |
4660d65679 | 7 years ago |
![]() |
33db684562 | 7 years ago |
![]() |
466bd6834c | 7 years ago |
![]() |
3786ebc33e | 7 years ago |
![]() |
c5dcbeb48d | 7 years ago |
![]() |
79f8a63a46 | 7 years ago |
![]() |
cc3d5b13e8 | 7 years ago |
![]() |
e5e9ce7674 | 7 years ago |
![]() |
1653e58398 | 7 years ago |
![]() |
e903484692 | 7 years ago |
![]() |
3486a5c593 | 7 years ago |
![]() |
019209abab | 7 years ago |
![]() |
7de653db58 | 7 years ago |
![]() |
b781195526 | 7 years ago |
![]() |
bfaea973bd | 7 years ago |
![]() |
e318b940ce | 7 years ago |
![]() |
27e336cd2c | 7 years ago |
![]() |
db4b38ecad | 7 years ago |
![]() |
1ea38f9c43 | 7 years ago |
![]() |
f18f16c004 | 7 years ago |
![]() |
4d9a0717d0 | 7 years ago |
![]() |
e498a16da6 | 7 years ago |
![]() |
cf72bf1dcc | 7 years ago |
![]() |
be3b7412ca | 7 years ago |
![]() |
d4e77e7da6 | 7 years ago |
![]() |
6a6e1c8352 | 7 years ago |
![]() |
9aba43ee48 | 7 years ago |
@ -0,0 +1,34 @@
|
||||
name: GitHubBuild
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- name: Validate composer.json and composer.lock
|
||||
run: composer validate
|
||||
|
||||
- name: setup templates_c
|
||||
run: mkdir templates_c || true
|
||||
|
||||
- name: touch config.local.php
|
||||
run: touch config.local.php && php -v
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer install --prefer-dist --no-progress --no-suggest
|
||||
|
||||
- name: Build/test
|
||||
run: composer build
|
||||
|
||||
- name: setup coveralls
|
||||
run: mkdir -p build/logs || true
|
||||
|
||||
- name: Coveralls
|
||||
run: vendor/bin/coveralls ./clover.xml || true
|
||||
env:
|
||||
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
|
@ -1,3 +1,7 @@
|
||||
/config.local.php
|
||||
/templates_c/*.tpl.php
|
||||
/templates_c/*menu.conf.php
|
||||
|
||||
/vendor/
|
||||
/.php_cs.cache
|
||||
/.idea
|
||||
/composer.lock
|
||||
|
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
$finder = PhpCsFixer\Finder::create()
|
||||
->exclude('lib')
|
||||
->exclude('vendor')
|
||||
->exclude('templates')
|
||||
->exclude('templates_c')
|
||||
->exclude('debian')
|
||||
->files()->notName('config.inc.php')->notName('config.local.php')
|
||||
->in(__DIR__);
|
||||
|
||||
return PhpCsFixer\Config::create()
|
||||
->setFinder($finder)
|
||||
->setRules(array(
|
||||
'@PSR2' => true,
|
||||
'braces' => array(
|
||||
'position_after_functions_and_oop_constructs' => 'same',
|
||||
),
|
||||
'method_argument_space' => false, # don't break formatting in initStruct()
|
||||
'no_spaces_inside_parenthesis' => false, # don't break formatting in initStruct()
|
||||
));
|
||||
|
||||
/* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4 ft=php: */
|
@ -0,0 +1,32 @@
|
||||
language: php
|
||||
php:
|
||||
- 7.2
|
||||
- 7.3
|
||||
- 7.4
|
||||
|
||||
services:
|
||||
- mysql
|
||||
- postgresql
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.composer/cache
|
||||
- $HOME/vendor
|
||||
|
||||
before_install:
|
||||
- mysql -e 'CREATE DATABASE postfixadmin;'
|
||||
- psql -c 'create database postfixadmin;' -U postgres
|
||||
|
||||
|
||||
before_script:
|
||||
- travis_retry composer install --no-interaction --prefer-source --dev
|
||||
- mkdir -p build/logs
|
||||
|
||||
script:
|
||||
- composer build
|
||||
- DATABASE=sqlite vendor/bin/phpunit tests/
|
||||
- DATABASE=mysql vendor/bin/phpunit --coverage-clover=build/logs/clover.xml tests/
|
||||
- DATABASE=postgresql vendor/bin/phpunit tests/
|
||||
|
||||
after_success:
|
||||
- travis_retry php vendor/bin/php-coveralls
|
@ -1,185 +1,193 @@
|
||||
<?php
|
||||
/*
|
||||
Virtual Mail Delete
|
||||
by George Vieira <george at citadelcomputer dot com dot au>
|
||||
|
||||
You can run this from your crontab with something like
|
||||
|
||||
0 4 * * * * vmail php -q virtualmaildel.php >/dev/null
|
||||
|
||||
Changes:
|
||||
2017.08.31 updated to use PHP mysqli extension.
|
||||
2018.02.23 removing Sieve filters if exists.
|
||||
Tadas Ustinavičius <tadas at ring dot lt> ( https://github.com/postfixadmin/postfixadmin/pull/70 )
|
||||
|
||||
*/
|
||||
|
||||
$CONF = [];
|
||||
|
||||
// Either, uncomment this (and change to work)
|
||||
//require_once('/path/to/postfixadmin/config.inc.php');
|
||||
|
||||
// OR uncomment this.
|
||||
/*
|
||||
$CONF = [
|
||||
'database_host' => 'localhost',
|
||||
'database_user' => 'someone',
|
||||
'database_password' => 'something',
|
||||
'database_name' => 'mydb'
|
||||
];
|
||||
*/
|
||||
|
||||
|
||||
$MAKE_CHANGES = false; // change to true when you're happy this isn't going to trash your server.
|
||||
|
||||
if (empty($CONF)) {
|
||||
die("\nPlease configure me\n\n");
|
||||
}
|
||||
|
||||
// Where's the homedir accounts stored. (GET THIS RIGHT OTHERWISE IT THINK NONE EXIST AND DELETES ALL)
|
||||
$homedir = '/home/virtual';
|
||||
|
||||
if (! is_dir($homedir)) {
|
||||
die("Cannot find home directory for virtual mailboxes in $homedir\n");
|
||||
}
|
||||
|
||||
//
|
||||
// Recursive Delete Function
|
||||
//
|
||||
// Virtual Mail Delete
|
||||
// by George Vieira <george at citadelcomputer dot com dot au>
|
||||
//
|
||||
// You can run this from your crontab with something like
|
||||
//
|
||||
// 0 4 * * * * vmail php -q virtualmaildel.php >/dev/null
|
||||
|
||||
//
|
||||
// Setup location of postfixadmin config files. Needed to login to mysql
|
||||
//
|
||||
$conf = '/home/httpd/mail/admin/config.inc.php';
|
||||
|
||||
//
|
||||
// Where's the homedir accounts stored. (GET THIS RIGHT OTHERWISE IT THINK NONE EXIST AND DELETES ALL)
|
||||
//
|
||||
$homedir = '/home/virtual';
|
||||
|
||||
//
|
||||
// Make sure everything is everything before continuing
|
||||
//
|
||||
if ( ! file_exists( $conf ) )
|
||||
die( "Cannot find config file $conf\n" );
|
||||
|
||||
if ( ! is_dir( $homedir ) )
|
||||
die( "Cannot find home directory for virtual mailboxes in $homedir\n" );
|
||||
|
||||
//
|
||||
// Load mysql authentication from postfixadmin
|
||||
//
|
||||
include( $conf );
|
||||
|
||||
//
|
||||
// Recursive Delete Function
|
||||
//
|
||||
function deldir($dir)
|
||||
{
|
||||
$current_dir = opendir($dir);
|
||||
while($entryname = readdir($current_dir))
|
||||
{
|
||||
if(is_dir("$dir/$entryname") and ($entryname != "." and $entryname!=".."))
|
||||
{
|
||||
deldir("${dir}/${entryname}");
|
||||
}
|
||||
elseif($entryname != "." and $entryname!="..")
|
||||
{
|
||||
unlink("${dir}/${entryname}");
|
||||
}
|
||||
}
|
||||
closedir($current_dir);
|
||||
@rmdir(${dir});
|
||||
}
|
||||
function deldir($dir) {
|
||||
$current_dir = opendir($dir);
|
||||
while ($entryname = readdir($current_dir)) {
|
||||
if (is_dir("$dir/$entryname") and ($entryname != "." and $entryname!="..")) {
|
||||
deldir("{$dir}/{$entryname}");
|
||||
} elseif ($entryname != "." and $entryname!="..") {
|
||||
unlink("{$dir}/{$entryname}");
|
||||
}
|
||||
}
|
||||
closedir($current_dir);
|
||||
@rmdir($dir);
|
||||
}
|
||||
|
||||
// --- Main Start ---
|
||||
|
||||
//
|
||||
// Get list of directories
|
||||
//
|
||||
$fr = opendir( $homedir );
|
||||
while ( ($domain = readdir($fr)) !== false)
|
||||
{
|
||||
//
|
||||
// Check if it's a dir
|
||||
//
|
||||
if ( $domain != "." and $domain != ".." and filetype($homedir .'/'. $domain) == "dir" )
|
||||
{
|
||||
//
|
||||
// Open the (assumed) DOMAIN directory
|
||||
//
|
||||
$ff = opendir( $homedir .'/'. $domain );
|
||||
while ( ($user = readdir($ff)) !== false)
|
||||
{
|
||||
//
|
||||
// Check for directories assuming it's a user account
|
||||
//
|
||||
if ( $user!="." and $user!=".." and filetype($homedir .'/'. $domain .'/'. $user) == "dir" )
|
||||
{
|
||||
//
|
||||
// if the dir 'new' exists inside then it's an account
|
||||
//
|
||||
if ( file_exists($homedir .'/'. $domain .'/'. $user .'/'. "new") )
|
||||
{
|
||||
$dir[$domain][$user] = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Alert that the dir doesn't have a 'new' dir, possibly not an account. Leave it.
|
||||
//
|
||||
echo "UNKNOWN : " . $homedir ."/". $domain ."/". $user ."/new NOT FOUND. Possibly not an account. Leaving untouched\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// OK, got an array of accounts from the dir, Now connect to the DB and check them
|
||||
//
|
||||
$conx = mysql_connect( $CONF['database_host'],$CONF['database_user'],$CONF['database_password'] );
|
||||
//
|
||||
// Is there a problem connecting?
|
||||
//
|
||||
if ( $conx != false )
|
||||
{
|
||||
//
|
||||
// Select the database
|
||||
//
|
||||
mysql_select_db( $CONF['database_name'] , $conx) or die ("Can't access database postfix : " . mysql_error());
|
||||
|
||||
//
|
||||
// Select all mailboxes to verify against dirs listed in array
|
||||
//
|
||||
$query = "SELECT * FROM mailbox";
|
||||
$result = mysql_query( $query );
|
||||
|
||||
//
|
||||
// Query the mailbox table
|
||||
//
|
||||
if ( $result != false )
|
||||
{
|
||||
//
|
||||
// Fetch the list of results
|
||||
//
|
||||
while ( $row = mysql_fetch_assoc( $result ) )
|
||||
{
|
||||
//
|
||||
// Pull apart the maildir field, needed to figure out the directory structure to compare
|
||||
//
|
||||
$strip = explode("/",$row['maildir']);
|
||||
//
|
||||
// Unset the array if it exists. This stops it being erased later.
|
||||
//
|
||||
unset( $dir[ $strip[0] ][ $strip[1] ] );
|
||||
}
|
||||
//
|
||||
// If there are results. unset the domain too.
|
||||
//
|
||||
if ( count($dir[$strip[0]])==0 and mysql_num_rows($result)>0 )
|
||||
unset( $dir[$strip[0]] );
|
||||
}
|
||||
else
|
||||
die( "Failed SELECT in mailboxes\n" );
|
||||
}
|
||||
else
|
||||
die( 'Cannot connect to the database!\n' );
|
||||
|
||||
//
|
||||
// OK, time to clean up. All known users/domains have been removed from the list.
|
||||
//
|
||||
|
||||
//
|
||||
// If the array still exists (incase nothing there)
|
||||
//
|
||||
if ( is_array($dir) )
|
||||
{
|
||||
//
|
||||
// Go through each dir
|
||||
//
|
||||
foreach ( $dir as $key => $value )
|
||||
{
|
||||
//
|
||||
// Is this a user array?
|
||||
//
|
||||
if ( is_array( $value) )
|
||||
{
|
||||
//
|
||||
// Go through and nuke the folders
|
||||
//
|
||||
foreach ( $value as $user => $value2 )
|
||||
{
|
||||
//
|
||||
// Nuke.. need any more explanations?
|
||||
//
|
||||
echo "REMOVING : " . $homedir."/".$key."/".$user."\n" ;
|
||||
deldir( $homedir."/".$key."/".$user ) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// And we are outta here....
|
||||
//
|
||||
echo "Cleanup process completed\n";
|
||||
?>
|
||||
$dir = [];
|
||||
|
||||
//
|
||||
// Get list of directories
|
||||
//
|
||||
$fr = opendir($homedir);
|
||||
|
||||
// TODO: Would glob($homedir . '/**/*/new') be somewhat quicker/shorter/less effort?
|
||||
|
||||
while (($domain = readdir($fr)) !== false) {
|
||||
//
|
||||
// Check if it's a dir
|
||||
//
|
||||
if ($domain == "." || $domain == ".." || filetype($homedir .'/'. $domain) != "dir") {
|
||||
continue;
|
||||
}
|
||||
//
|
||||
// Open the (assumed) DOMAIN directory
|
||||
//
|
||||
$ff = opendir($homedir .'/'. $domain);
|
||||
while (($user = readdir($ff)) !== false) {
|
||||
//
|
||||
// Check for directories assuming it's a user account
|
||||
//
|
||||
if ($user == "." || $user == ".." || filetype($homedir .'/'. $domain .'/'. $user) != "dir") {
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// if the dir 'new' exists inside then it's an account
|
||||
//
|
||||
if (file_exists($homedir .'/'. $domain .'/'. $user .'/'. "new")) {
|
||||
$dir[$domain][$user] = "";
|
||||
} else {
|
||||
//
|
||||
// Alert that the dir doesn't have a 'new' dir, possibly not an account. Leave it.
|
||||
//
|
||||
echo "UNKNOWN : " . $homedir ."/". $domain ."/". $user ."/new NOT FOUND. Possibly not an account. Leaving untouched\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// OK, got an array of accounts from the dir, Now connect to the DB and check them
|
||||
//
|
||||
$conx = mysqli_connect($CONF['database_host'], $CONF['database_user'], $CONF['database_password'], $CONF['database_name']);
|
||||
//
|
||||
// Is there a problem connecting?
|
||||
//
|
||||
if (! $conx || mysqli_connect_errno()) {
|
||||
echo "DB connection failed." . mysqli_connect_error() . "\n";
|
||||
die("Problem connecting to the database. ");
|
||||
}
|
||||
|
||||
//
|
||||
// Select all mailboxes to verify against dirs listed in array
|
||||
//
|
||||
$query = "SELECT * FROM mailbox";
|
||||
$result = mysqli_query($conx, $query);
|
||||
|
||||
//
|
||||
// Query the mailbox table
|
||||
//
|
||||
if (! $result) {
|
||||
die("Failed to query mailbox table.");
|
||||
}
|
||||
|
||||
//
|
||||
// Fetch the list of results
|
||||
//
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
//
|
||||
// Pull apart the maildir field, needed to figure out the directory structure to compare
|
||||
//
|
||||
$strip = explode("/", $row['maildir']);
|
||||
//
|
||||
// Unset the array if it exists. This stops it being erased later.
|
||||
//
|
||||
unset($dir[ $strip[0] ][ $strip[1] ]);
|
||||
}
|
||||
//
|
||||
// If there are results. unset the domain too.
|
||||
//
|
||||
if (count($dir[$strip[0]])==0 and mysqli_num_rows($result)>0) {
|
||||
unset($dir[$strip[0]]);
|
||||
}
|
||||
|
||||
//
|
||||
// OK, time to clean up. All known users/domains have been removed from the list.
|
||||
//
|
||||
|
||||
//
|
||||
// If the array still exists (incase nothing there)
|
||||
//
|
||||
if (is_array($dir)) {
|
||||
//
|
||||
// Go through each dir
|
||||
//
|
||||
foreach ($dir as $key => $value) {
|
||||
//
|
||||
// Is this a user array?
|
||||
//
|
||||
if (!is_array($value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// Go through and nuke the folders
|
||||
//
|
||||
foreach ($value as $user => $value2) {
|
||||
// Nuke.. need any more explanations?
|
||||
$path = $homedir . '/' . $key . '/' . $user;
|
||||
$sieve_path = $homedir . '/.sieve/' . $key . '/' . $user;
|
||||
$sieve_exists = file_exists($sieve_path);
|
||||
// check if user has Sieve filters created
|
||||
if ($MAKE_CHANGES) {
|
||||
deldir($path);
|
||||
if ($sieve_exists) {
|
||||
deldir($sieve_path);
|
||||
}
|
||||
} else {
|
||||
echo " - Would recursively delete : $path \n";
|
||||
if ($sieve_exists) {
|
||||
echo " - Would recursively delete Sieve filters : $sieve_path \n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo "Cleanup process completed\n";
|
||||
|
@ -0,0 +1,221 @@
|
||||
# Example configuration
|
||||
|
||||
The below covers some default(ish) configuration things for using Postfix, Dovecot with PostgreSQL.
|
||||
|
||||
# Postfix
|
||||
|
||||
Assumptions :
|
||||
|
||||
* Mail is delivered into /var/mail/vmail/foo@example.com/
|
||||
* The user with id 8 is used for ownership of mail files.
|
||||
* PostgreSQL is running on the local server
|
||||
* Dovecot is running on the local server, and SASL is used to allow authenticated clients to mail out.
|
||||
|
||||
|
||||
## /etc/postfix/main.cf
|
||||
|
||||
The proxy: bits are optional, you may need to install an additional postfix package on your server to enable them.
|
||||
|
||||
i.e. proxy:pgsql:/path/to/file is equivalent to pgsql:/path/to/file. Use of 'proxy:' may lead to a small performance boost.
|
||||
|
||||
|
||||
```
|
||||
relay_domains = $mydestination, proxy:pgsql:/etc/postfix/pgsql/relay_domains.cf
|
||||
virtual_alias_maps = proxy:pgsql:/etc/postfix/pgsql/virtual_alias_maps.cf
|
||||
virtual_mailbox_domains = proxy:pgsql:/etc/postfix/pgsql/virtual_domains_maps.cf
|
||||
virtual_mailbox_maps = proxy:pgsql:/etc/postfix/pgsql/virtual_mailbox_maps.cf
|
||||
virtual_mailbox_base = /var/mail/vmail
|
||||
virtual_mailbox_limit = 512000000
|
||||
virtual_minimum_uid = 8
|
||||
virtual_transport = virtual
|
||||
virtual_uid_maps = static:8
|
||||
virtual_gid_maps = static:8
|
||||
local_transport = virtual
|
||||
local_recipient_maps = $virtual_mailbox_maps
|
||||
```
|
||||
|
||||
and for Postfix SASL support :
|
||||
|
||||
```
|
||||
# SASL Auth for SMTP relaying
|
||||
smtpd_sasl_type = dovecot
|
||||
smtpd_sasl_path = private/auth
|
||||
smtpd_sasl_authenticated_header = yes
|
||||
smtpd_sasl_auth_enable = yes
|
||||
smtpd_sasl_security_options = noanonymous
|
||||
broken_sasl_auth_clients = yes
|
||||
```
|
||||
|
||||
## /etc/postfix/pgsql/relay_domains.cf
|
||||
|
||||
```
|
||||
user = postfix
|
||||
password = whatever
|
||||
hosts = localhost
|
||||
dbname = postfix
|
||||
query = SELECT domain FROM domain WHERE domain='%s' and backupmx = true
|
||||
```
|
||||
|
||||
## /etc/postfix/pgsql/virtual_alias_maps.cf
|
||||
|
||||
```
|
||||
user = postfix
|
||||
password = whatever
|
||||
hosts = localhost
|
||||
dbname = postfix
|
||||
query = SELECT goto FROM alias WHERE address='%s' AND active = true
|
||||
```
|
||||
|
||||
## /etc/postfix/pgsql/virtual_domains_maps.cf
|
||||
|
||||
```
|
||||
user = postfix
|
||||
password = whatever
|
||||
hosts = localhost
|
||||
dbname = postfix
|
||||
#query = SELECT domain FROM domain WHERE domain='%s'
|
||||
#optional query to use when relaying for backup MX
|
||||
query = SELECT domain FROM domain WHERE domain='%s' and backupmx = false and active = true
|
||||
```
|
||||
|
||||
## /etc/postfix/pgsql/virtual_mailbox_limits.cf
|
||||
|
||||
```
|
||||
# Used for quota
|
||||
user = postfix
|
||||
password = whatever
|
||||
hosts = localhost
|
||||
dbname = postfix
|
||||
query = SELECT quota FROM mailbox WHERE username='%s'
|
||||
```
|
||||
|
||||
## /etc/postfix/pgsql/virtual_mailbox_maps.cf
|
||||
|
||||
```
|
||||
user = postfix
|
||||
password = whatever
|
||||
hosts = localhost
|
||||
dbname = postfix
|
||||
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = true
|
||||
```
|
||||
|
||||
|
||||
# Dovecot
|
||||
|
||||
(This is from version 2.2.27, Debian Stretch)
|
||||
|
||||
|
||||
## /etc/dovecot/dovecot.conf
|
||||
```
|
||||
mail_location = maildir:/var/mail/vmail/%u/
|
||||
|
||||
namespace inbox {
|
||||
type = private
|
||||
inbox = yes
|
||||
location =
|
||||
mailbox Drafts {
|
||||
special_use = \Drafts
|
||||
}
|
||||
mailbox Junk {
|
||||
special_use = \Junk
|
||||
}
|
||||
mailbox Sent {
|
||||
special_use = \Sent
|
||||
}
|
||||
mailbox "Sent Messages" {
|
||||
special_use = \Sent
|
||||
}
|
||||
mailbox Trash {
|
||||
special_use = \Trash
|
||||
}
|
||||
prefix =
|
||||
}
|
||||
|
||||
protocols = "imap pop3"
|
||||
|
||||
# Requires certificates ...
|
||||
#ssl = yes
|
||||
#ssl_cert = </etc/dovecot/private/something.pem
|
||||
#ssl_key = </etc/letsencrypt/certs/something.key
|
||||
|
||||
login_greeting = My Mail Server
|
||||
# http://wiki2.dovecot.org/Authentication/Mechanisms
|
||||
# login is for outlook express ...
|
||||
auth_mechanisms = plain login
|
||||
#auth_debug = yes
|
||||
#auth_debug_passwords=yes
|
||||
|
||||
# Postfix - Sasl auth support.
|
||||
service auth {
|
||||
# Postfix smtp-auth
|
||||
unix_listener /var/spool/postfix/private/auth {
|
||||
mode = 0660
|
||||
user = postfix
|
||||
group = postfix
|
||||
}
|
||||
# Auth process is run as this user.
|
||||
user = postfix
|
||||
group = postfix
|
||||
}
|
||||
|
||||
service imap {
|
||||
executable = imap
|
||||
}
|
||||
|
||||
userdb {
|
||||
driver = sql
|
||||
args = /etc/dovecot/dovecot-sql.conf
|
||||
}
|
||||
|
||||
passdb {
|
||||
driver = sql
|
||||
args = /etc/dovecot/dovecot-sql.conf
|
||||
}
|
||||
|
||||
# Needs to match Postfix virtual_uid_maps
|
||||
first_valid_uid = 8
|
||||
|
||||
# disallow or allow plaintext auth.
|
||||
disable_plaintext_auth = yes
|
||||
|
||||
mail_plugins = $mail_plugins zlib
|
||||
|
||||
plugin {
|
||||
zlib_save_level = 6
|
||||
zlib_save = gz
|
||||
}
|
||||
protocol imap {
|
||||
mail_plugins = $mail_plugins imap_zlib
|
||||
}
|
||||
|
||||
mail_max_userip_connections = 50
|
||||
log_path = /var/log/dovecot.log
|
||||
|
||||
```
|
||||
|
||||
|
||||
## /etc/dovecot/dovecot-sql.conf
|
||||
|
||||
Ideally dovecot has a different read only database user.
|
||||
|
||||
|
||||
```
|
||||
connect = host=localhost dbname=postfix user=dovecot password=whatever
|
||||
|
||||
driver = pgsql
|
||||
|
||||
# Default password scheme - change to match your Postfixadmin setting.
|
||||
# depends on your $CONF['encrypt'] setting:
|
||||
# md5crypt -> MD5-CRYPT
|
||||
# md5 -> PLAIN-MD5
|
||||
# cleartext -> PLAIN
|
||||
default_pass_scheme = MD5-CRYPT
|
||||
|
||||
# Query to retrieve password. user can be used to retrieve username in other
|
||||
# formats also.
|
||||
|
||||
password_query = SELECT username AS user,password FROM mailbox WHERE username = '%u' AND active='1'
|
||||
|
||||
# Query to retrieve user information, note uid matches dovecot.conf AND Postfix virtual_uid_maps parameter.
|
||||
user_query = SELECT '/var/vmail/mail/' || maildir AS home, 8 as uid, 8 as gid FROM mailbox WHERE username = '%u' AND active = '1'
|
||||
```
|
@ -0,0 +1,48 @@
|
||||
*Description
|
||||
|
||||
This extension adds support for password expiration.
|
||||
It is designed to have expiration on users passwords. An email is sent when the password is expiring in 30 days, then 14 days, then 7 days.
|
||||
It is strongly inspired by https://abridge2devnull.com/posts/2014/09/29/dovecot-user-password-expiration-notifications-updated-4122015/, and adapted to fit with Postfix Admin & Roundcube's password plugin
|
||||
Expiration unit is day
|
||||
Expiration value for domain is set through Postfix Admin GUI
|
||||
|
||||
*Installation
|
||||
|
||||
Perform the following changes:
|
||||
|
||||
**Changes in MySQL/MariaDB mailbox table (as defined in $CONF['database_tables'] from config.inc.php):
|
||||
|
||||
You are invited to backup your DB first, and ensure the table name is correct.
|
||||
|
||||
Execute the attached SQL script (password_expiration.sql) that will add the required columns. The expiration value for existing users will be set to 90 days. If you want a different value, edit line 2 in the script and replace 90 by the required value.
|
||||
|
||||
**Changes in Postfix Admin :
|
||||
|
||||
To enable password expiration, add the following to your config.inc.php file:
|
||||
$CONF['password_expiration'] = 'YES';
|
||||
|
||||
All my tests are performed using $CONF['encrypt'] = 'md5crypt';
|
||||
|
||||
**If you are using Roundcube's password plugin, you should also adapt the $config['password_query'] value.
|
||||
|
||||
I recommend to use:
|
||||
|
||||
$config['password_query'] = 'UPDATE mailbox SET password=%c, modified = now(), password_expiry = now() + interval 90 day';
|
||||
|
||||
of cource you may adapt to the expected expiration value
|
||||
|
||||
All my tests are performed using $config['password_algorithm'] = 'md5-crypt';
|
||||
|
||||
**Changes in Dovecot (adapt if you use another LDA)
|
||||
|
||||
Edit dovecot-mysql.conf file, and replace the user_query (and only this one) by this query:
|
||||
|
||||
password_query = SELECT username as user, password, concat('/var/vmail/', maildir) as userdb_var, concat('maildir:/var/vmail/', maildir) as userdb_mail, 20001 as userdb_uid, 20001 as userdb_gid, m.domain FROM mailbox m, domain d where d.domain = m.domain and m.username = '%u' AND m.active = '1' AND (m.password_expiry > now() or d.password_expiry = 0)
|
||||
|
||||
Of course you may require to adapt the uid, gid, maildir and table to your setup
|
||||
|
||||
**Changes in system
|
||||
|
||||
You need to have a script running on a daily basis to check password expiration and send emails 30, 14 and 7 days before password expiration (script attached: check_mailpass_expiration.sh).
|
||||
Edit the script to adapt the variables to your setup.
|
||||
This script is using postfixadmin.my.cnf to read credentials. Edit this file to enter a DB user that is allowed to access (read-write) your database. This file should be protected from any user (chmod 400).
|
@ -0,0 +1,93 @@
|
||||
This file is not exhaustive.
|
||||
|
||||
Please feel free to add yourself and a summary of changes to this file at the bottom if creating a pull request.
|
||||
|
||||
|
||||
Postfixadmin was originally written by Mischa Peters <mischa at high5 dot net>
|
||||
|
||||
Copyright (c) 2002 - 2005 High5!
|
||||
Licensed under GPL for more info check GPL-LICENSE.TXT
|
||||
|
||||
|
||||
|
||||
Additional authors:
|
||||
|
||||
2004/07/13 David Osborn <ossdev at daocon.com>
|
||||
strict, processes domain level aliases, more
|
||||
subroutines, send reply from original to address
|
||||
|
||||
2004/11/09 David Osborn <ossdev at daocon.com>
|
||||
Added syslog support
|
||||
Slightly better logging which includes messageid
|
||||
Avoid infinite loops with domain aliases
|
||||
|
||||
2005-01-19 Troels Arvin <troels at arvin.dk>
|
||||
PostgreSQL-version.
|
||||
Normalized DB schema from one vacation table ("vacation")
|
||||
to two ("vacation", "vacation_notification"). Uses
|
||||
referential integrity CASCADE action to simplify cleanup
|
||||
when a user is no longer on vacation.
|
||||
Inserting variables into queries stricly by prepare()
|
||||
to try to avoid SQL injection.
|
||||
International characters are now handled well.
|
||||
|
||||
2005-01-21 Troels Arvin <troels at arvin.dk>
|
||||
Uses the Email::Valid package to avoid sending notices
|
||||
to obviously invalid addresses.
|
||||
|
||||
2007-08-15 David Goodwin <david at palepurple.co.uk>
|
||||
Use the Perl Mail::Sendmail module for sending mail
|
||||
Check for headers that start with blank lines (patch from forum)
|
||||
|
||||
2007-08-20 Martin Ambroz <amsys at trustica.cz>
|
||||
Added initial Unicode support
|
||||
|
||||
2008-05-09 Fabio Bonelli <fabiobonelli at libero.it>
|
||||
Properly handle failed queries to vacation_notification.
|
||||
Fixed log reporting.
|
||||
|
||||
2008-07-29 Patch from Luxten to add repeat notification after timeout. See:
|
||||
https://sourceforge.net/tracker/index.php?func=detail&aid=2031631&group_id=191583&atid=937966
|
||||
|
||||
2008-08-01 Luigi Iotti <luigi at iotti dot biz>
|
||||
Use envelope sender/recipient instead of using
|
||||
From: and To: header fields;
|
||||
Support to good vacation behavior as in
|
||||
http://www.irbs.net/internet/postfix/0707/0954.html
|
||||
(needs to be tested);
|
||||
|
||||
2008-08-04 David Goodwin <david at palepurple dot co dot uk>
|
||||
Use Log4Perl
|
||||
Added better testing (and -t option)
|
||||
|
||||
2009-06-29 Stevan Bajic <stevan at bajic.ch>
|
||||
Add Mail::Sender for SMTP auth + more flexibility
|
||||
|
||||
2009-07-07 Stevan Bajic <stevan at bajic.ch>
|
||||
Add better alias lookups
|
||||
Check for more heades from Anti-Virus/Anti-Spam solutions
|
||||
|
||||
2009-08-10 Sebastian <reg9009 at yahoo dot de>
|
||||
Adjust SQL query for vacation timeframe. It is now possible to set from/until date for vacation message.
|
||||
|
||||
2012-04-1 Nikolaos Topp <info at ichier.de>
|
||||
Add configuration parameter $smtp_client in order to get mails through
|
||||
postfix helo-checks, using check_helo_access whitelist without permitting 'localhost' default style stuff
|
||||
|
||||
2012-04-19 Jan Kruis <jan at crossreference dot nl>
|
||||
change SQL query for vacation into function.
|
||||
Add sub get_interval()
|
||||
Gives the user the option to set the interval time ( 0 = one reply, 1 = autoreply, > 1 = Delay reply )
|
||||
See https://sourceforge.net/tracker/?func=detail&aid=3508083&group_id=191583&atid=937966
|
||||
|
||||
2012-06-18 Christoph Lechleitner <christoph.lechleitner@iteg.at>
|
||||
Add capability to include the subject of the original mail in the subject of the vacation message.
|
||||
A good vacation subject could be: 'Re: $SUBJECT'
|
||||
Also corrected log entry about "Already informed ..." to show the $orig_from, not $email
|
||||
|
||||
2017-07-14 Thomas Kempf <tkempf@hueper.de>
|
||||
Replacing deprecated Mail::Sender by Email::Sender
|
||||
Add configuration parameter $no_vacation_pattern in order to exlude specific alias-recipients from
|
||||
sending vacation mails, even if one or multiple of the recipients the alias points to has vacation
|
||||
currently active.
|
||||
|
@ -1,22 +0,0 @@
|
||||
<?php
|
||||
//
|
||||
// Postfix Admin
|
||||
// by Mischa Peters <mischa at high5 dot net>
|
||||
// Copyright (c) 2002 - 2005 High5!
|
||||
// Licensed under GPL for more info check GPL-LICENSE.TXT
|
||||
//
|
||||
// File: index.php
|
||||
//
|
||||
// Template File: -none-
|
||||
//
|
||||
// Template Variables:
|
||||
//
|
||||
// -none-
|
||||
//
|
||||
// Form POST \ GET Variables:
|
||||
//
|
||||
// -none-
|
||||
//
|
||||
header ("Location: ../login.php");
|
||||
exit;
|
||||
?>
|
@ -1,140 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Postfix Admin
|
||||
*
|
||||
* LICENSE
|
||||
* This source file is subject to the GPL license that is bundled with
|
||||
* this package in the file LICENSE.TXT.
|
||||
*
|
||||
* Further details on the project are available at http://postfixadmin.sf.net
|
||||
*
|
||||
* @version $Id$
|
||||
* @license GNU GPL v2 or later.
|
||||
*
|
||||
* File: backup.php
|
||||
* Used to save all settings - but only works for MySQL databases.
|
||||
* Template File: -none-
|
||||
*
|
||||
* Template Variables: -none-
|
||||
*
|
||||
* Form POST \ GET Variables: -none-
|
||||
*/
|
||||
|
||||
require_once('common.php');
|
||||
|
||||
authentication_require_role('global-admin');
|
||||
|
||||
(($CONF['backup'] == 'NO') ? header("Location: main.php") && exit : '1');
|
||||
|
||||
// TODO: make backup supported for postgres
|
||||
if (db_pgsql()) {
|
||||
flash_error('Sorry: Backup is currently not supported for your DBMS ('.$CONF['database_type'].').');
|
||||
$smarty->assign ('smarty_template', 'message');
|
||||
$smarty->display ('index.tpl');
|
||||
die;
|
||||
}
|
||||
|
||||
if (safeget('download') == "") {
|
||||
$smarty->assign ('smarty_template', 'backupwarning');
|
||||
$smarty->display ('index.tpl');
|
||||
die;
|
||||
}
|
||||
|
||||
# Still here? Then let's create the database dump...
|
||||
|
||||
/*
|
||||
SELECT attnum,attname,typname,atttypmod-4,attnotnull,atthasdef,adsrc
|
||||
AS def FROM pg_attribute,pg_class,pg_type,pg_attrdef
|
||||
WHERE pg_class.oid=attrelid AND pg_type.oid=atttypid
|
||||
AND attnum>0 AND pg_class.oid=adrelid AND adnum=attnum AND atthasdef='t' AND lower(relname)='admin'
|
||||
UNION SELECT attnum,attname,typname,atttypmod-4,attnotnull,atthasdef,''
|
||||
AS def FROM pg_attribute,pg_class,pg_type
|
||||
WHERE pg_class.oid=attrelid
|
||||
AND pg_type.oid=atttypid
|
||||
AND attnum>0
|
||||
AND atthasdef='f'
|
||||
AND lower(relname)='admin'
|
||||
$db = $_GET['db'];
|
||||
$cmd = "pg_dump -c -D -f /tix/miner/miner.sql -F p -N -U postgres $db";
|
||||
$res = `$cmd`;
|
||||
// Alternate: $res = shell_exec($cmd);
|
||||
echo $res;
|
||||
*/
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == "GET")
|
||||
{
|
||||
umask (077);
|
||||
$path = (ini_get('upload_tmp_dir') != '') ? ini_get('upload_tmp_dir') : '/tmp';
|
||||
date_default_timezone_set(@date_default_timezone_get()); # Suppress date.timezone warnings
|
||||
$filename = "postfixadmin-" . date ("Ymd") . "-" . getmypid() . ".sql";
|
||||
$backup = $path . DIRECTORY_SEPARATOR . $filename;
|
||||
|
||||
$header = "#\n# Postfix Admin $version\n# Date: " . date ("D M j G:i:s T Y") . "\n#\n";
|
||||
|
||||
if (!$fh = fopen ($backup, 'w'))
|
||||
{
|
||||
flash_error("<div class=\"error_msg\">Cannot open file ($backup)</div>");
|
||||
$smarty->assign ('smarty_template', 'message');
|
||||
$smarty->display ('index.tpl');
|
||||
}
|
||||
else
|
||||
{
|
||||
fwrite ($fh, $header);
|
||||
|
||||
$tables = array(
|
||||
'admin',
|
||||
'alias',
|
||||
'alias_domain',
|
||||
'config',
|
||||
'domain',
|
||||
'domain_admins',
|
||||
'fetchmail',
|
||||
'log',
|
||||
'mailbox',
|
||||
'quota',
|
||||
'quota2',
|
||||
'vacation',
|
||||
'vacation_notification'
|
||||
);
|
||||
|
||||
for ($i = 0 ; $i < sizeof ($tables) ; ++$i)
|
||||
{
|
||||
$result = db_query ("SHOW CREATE TABLE " . table_by_key($tables[$i]));
|
||||
if ($result['rows'] > 0)
|
||||
{
|
||||
while ($row = db_array ($result['result']))
|
||||
{
|
||||
fwrite ($fh, "$row[1];\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ($i = 0 ; $i < sizeof ($tables) ; ++$i)
|
||||
{
|
||||
$result = db_query ("SELECT * FROM " . table_by_key($tables[$i]));
|
||||
if ($result['rows'] > 0)
|
||||
{
|
||||
while ($row = db_assoc ($result['result']))
|
||||
{
|
||||
$fields = array_keys($row);
|
||||
$values = array_values($row);
|
||||
$values = array_map('escape_string', $values);
|
||||
|
||||
fwrite ($fh, "INSERT INTO ". $tables[$i] . " (". implode (',',$fields) . ") VALUES ('" . implode ('\',\'',$values) . "');\n");
|
||||
$fields = "";
|
||||
$values = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
header ("Content-Type: text/plain");
|
||||
header ("Content-Disposition: attachment; filename=\"$filename\"");
|
||||
header ("Content-Transfer-Encoding: binary");
|
||||
header ("Content-Length: " . filesize("$backup"));
|
||||
header ("Content-Description: Postfix Admin");
|
||||
$download_backup = fopen ("$backup", "r");
|
||||
unlink ("$backup");
|
||||
fpassthru ($download_backup);
|
||||
}
|
||||
/* vim: set expandtab softtabstop=3 tabstop=3 shiftwidth=3: */
|
||||
?>
|
@ -1,124 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Postfix Admin
|
||||
*
|
||||
* LICENSE
|
||||
* This source file is subject to the GPL license that is bundled with
|
||||
* this package in the file LICENSE.TXT.
|
||||
*
|
||||
* Further details on the project are available at http://postfixadmin.sf.net
|
||||
*
|
||||
* @version $Id$
|
||||
* @license GNU GPL v2 or later.
|
||||
*
|
||||
* File: broadcast-message.php
|
||||
* Used to send a message to _ALL_ users with mailboxes on this server.
|
||||
*
|
||||
* Template File: broadcast-message.tpl
|
||||
*
|
||||
* Template Variables: -none-
|
||||
*
|
||||
* Form POST \ GET Variables:
|
||||
*
|
||||
* name
|
||||
* subject
|
||||
* message
|
||||
*/
|
||||
|
||||
require_once('common.php');
|
||||
|
||||
if (Config::bool('sendmail_all_admins')) {
|
||||
authentication_require_role('admin');
|
||||
} else {
|
||||
authentication_require_role('global-admin');
|
||||
}
|
||||
|
||||
if ($CONF['sendmail'] != 'YES') {
|
||||
header("Location: main.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
$error = 0;
|
||||
|
||||
$smtp_from_email = smtp_get_admin_email();
|
||||
$allowed_domains = list_domains_for_admin(authentication_get_username());
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == "POST")
|
||||
{
|
||||
if (safepost('token') != $_SESSION['PFA_token']) die('Invalid token!');
|
||||
|
||||
if (empty($_POST['subject']) || empty($_POST['message']) || empty($_POST['name']))
|
||||
{
|
||||
$error = 1;
|
||||
flash_error($PALANG['pBroadcast_error_empty']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$wanted_domains = array_intersect($allowed_domains, $_POST['domains']);
|
||||
|
||||
$table_mailbox = table_by_key('mailbox');
|
||||
$table_alias = table_by_key('alias');
|
||||
|
||||
$recipients = [];
|
||||
|
||||
$q = "SELECT username from $table_mailbox WHERE active='" . db_get_boolean(true) . "' AND ".db_in_clause("domain", $wanted_domains);
|
||||
if (intval(safepost('mailboxes_only')) == 0) {
|
||||
$q .= " UNION SELECT goto FROM $table_alias WHERE active='" . db_get_boolean(true) . "' AND ".db_in_clause("domain", $wanted_domains)."AND goto NOT IN ($q)";
|
||||
}
|
||||
$result = db_query($q);
|
||||
if($result['rows'] > 0) {
|
||||
while($row = db_array($result['result'])) {
|
||||
$recipients[] = $row[0];
|
||||
}
|
||||
}
|
||||
|
||||
$recipients = array_unique($recipients);
|
||||
|
||||
if(count($recipients)>0) {
|
||||
mb_internal_encoding("UTF-8");
|
||||
$b_name = mb_encode_mimeheader( $_POST['name'], 'UTF-8', 'Q');
|
||||
$b_subject = mb_encode_mimeheader( $_POST['subject'], 'UTF-8', 'Q');
|
||||
$b_message = base64_encode($_POST['message']);
|
||||
|
||||
$i = 0;
|
||||
foreach ($recipients as $rcpt) {
|
||||
$fTo = $rcpt;
|
||||
$fHeaders = 'To: ' . $fTo . "\n";
|
||||
$fHeaders .= 'From: ' . $b_name . ' <' . $smtp_from_email . ">\n";
|
||||
$fHeaders .= 'Subject: ' . $b_subject . "\n";
|
||||
$fHeaders .= 'MIME-Version: 1.0' . "\n";
|
||||
$fHeaders .= 'Content-Type: text/plain; charset=UTF-8' . "\n";
|
||||
$fHeaders .= 'Content-Transfer-Encoding: base64' . "\n";
|
||||
|
||||
$fHeaders .= $b_message;
|
||||
|
||||
if (!smtp_mail ($fTo, $smtp_from_email, $fHeaders))
|
||||
{
|
||||
flash_error(Config::lang_f('pSendmail_result_error', $fTo));
|
||||
}
|
||||
else
|
||||
{
|
||||
flash_info(Config::lang_f('pSendmail_result_success', $fTo));
|
||||
}
|
||||
}
|
||||
}
|
||||
flash_info($PALANG['pBroadcast_success']);
|
||||
$smarty->assign ('smarty_template', 'message');
|
||||
$smarty->display ('index.tpl');
|
||||
// echo '<p>'.$PALANG['pBroadcast_success'].'</p>';
|
||||
}
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == "GET" || $error == 1)
|
||||
{
|
||||
$smarty->assign ('allowed_domains', $allowed_domains);
|
||||
$smarty->assign ('smtp_from_email', $smtp_from_email);
|
||||
$smarty->assign ('error', $error);
|
||||
$smarty->assign ('smarty_template', 'broadcast-message');
|
||||
$smarty->display ('index.tpl');
|
||||
|
||||
// include ("templates/broadcast-message.tpl");
|
||||
}
|
||||
|
||||
/* vim: set expandtab softtabstop=3 tabstop=3 shiftwidth=3: */
|
||||
?>
|
@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
#Adapt to your setup
|
||||
|
||||
POSTFIX_DB="postfix_test"
|
||||
MYSQL_CREDENTIALS_FILE="postfixadmin.my.cnf"
|
||||
|
||||
REPLY_ADDRESS=noreply@example.com
|
||||
|
||||
# Change this list to change notification times and when ...
|
||||
for INTERVAL in 30 14 7
|
||||
do
|
||||
LOWER=$(( $INTERVAL - 1 ))
|
||||
|
||||
QUERY="SELECT username,password_expiry FROM mailbox WHERE password_expiry > now() + interval $LOWER DAY AND password_expiry < NOW() + interval $INTERVAL DAY"
|
||||
|
||||
mysql --defaults-extra-file="$MYSQL_CREDENTIALS_FILE" "$POSTFIX_DB" -B -e "$QUERY" | while read -a RESULT ; do
|
||||
echo -e "Dear User, \n Your password will expire on ${RESULT[1]}" | mail -s "Password 30 days before expiration notication" -r $REPLY_ADDRESS ${RESULT[0]}
|
||||
done
|
||||
|
||||
done
|
@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "postfixadmin/postfixadmin",
|
||||
"description": "web based administration interface for Postfix mail servers",
|
||||
"type": "project",
|
||||
"license": "GPL-2.0",
|
||||
"scripts": {
|
||||
"build" : [
|
||||
"@check-format",
|
||||
"@lint",
|
||||
"@test-fixup",
|
||||
"@psalm",
|
||||
"@test"
|
||||
],
|
||||
"check-format": "php-cs-fixer fix --ansi --dry-run --diff",
|
||||
"format": "php-cs-fixer fix --ansi",
|
||||
"lint": "@php ./vendor/bin/parallel-lint --exclude vendor/ --exclude lib/block_random_int.php --exclude lib/array_column.php .",
|
||||
"test": "DATABASE=sqlite ./vendor/bin/phpunit --coverage-clover ./clover.xml tests/",
|
||||
"test-fixup": "mkdir -p templates_c ; test -f config.local.php || touch config.local.php",
|
||||
"psalm": "@php ./vendor/bin/psalm --show-info=false "
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-mysqli": "*",
|
||||
"ext-sqlite3": "*",
|
||||
"friendsofphp/php-cs-fixer": "*",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.0",
|
||||
"php": ">7.2.0",
|
||||
"cedx/coveralls": "^11.0",
|
||||
"phpunit/phpunit": "8.*",
|
||||
"vimeo/psalm":"^3.0",
|
||||
"shardj/zf1-future" : "^1.12"
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"config.inc.php",
|
||||
"functions.inc.php",
|
||||
"lib/smarty/libs/bootstrap.php"
|
||||
]
|
||||
},
|
||||
"support": {
|
||||
"irc": "irc://irc.freenode.org/postfixadmin",
|
||||
"issues": "https://github.com/postfixadmin/postfixadmin/issues",
|
||||
"chat": "https://gitter.im/postfixadmin/Lobby"
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
# BEGIN FOR POSTFIXADMIN
|
||||
|
||||
Alias /postfixadmin /usr/share/postfixadmin
|
||||
Alias /postfixadmin /usr/share/postfixadmin/public
|
||||
|
||||
# END FOR POSTFIXADMIN
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Alias for Postfixadmin
|
||||
alias.url += (
|
||||
"/postfixadmin" => "/usr/share/postfixadmin",
|
||||
"/postfixadmin" => "/usr/share/postfixadmin/public",
|
||||
)
|
||||
|
@ -1 +1 @@
|
||||
0001-db_credentials.patch
|
||||
config-debian.diff
|
||||
|
@ -1,4 +1,8 @@
|
||||
usr/share/postfixadmin
|
||||
usr/share/postfixadmin/css
|
||||
usr/share/postfixadmin/scripts
|
||||
usr/share/postfixadmin/public
|
||||
usr/share/postfixadmin/lib
|
||||
usr/share/doc/postfixadmin
|
||||
var/cache/postfixadmin
|
||||
usr/bin
|
||||
etc/postfixadmin
|
||||
|
@ -1,10 +1,9 @@
|
||||
*.php usr/share/postfixadmin
|
||||
css usr/share/postfixadmin
|
||||
images usr/share/postfixadmin
|
||||
public usr/share/postfixadmin
|
||||
languages usr/share/postfixadmin
|
||||
model usr/share/postfixadmin
|
||||
templates usr/share/postfixadmin
|
||||
users usr/share/postfixadmin
|
||||
smarty usr/share/postfixadmin
|
||||
configs usr/share/postfixadmin
|
||||
lib usr/share/postfixadmin
|
||||
configs usr/share/postfixadmin
|
||||
scripts usr/share/postfixadmin
|
||||
debian/lighttpd/90-postfixadmin.conf etc/lighttpd/conf-available
|
||||
|
@ -1 +1,2 @@
|
||||
etc/postfixadmin/config.inc.php usr/share/postfixadmin/config.inc.php
|
||||
var/cache/postfixadmin usr/share/postfixadmin/templates_c
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Turn on sanitisation of all data by default so it's not possible for XSS flaws to occur in PFA
|
||||
*/
|
||||
class PFASmarty {
|
||||
|
||||
/**
|
||||
* @var Smarty
|
||||
*/
|
||||
protected $template;
|
||||
|
||||
/**
|
||||
* @param string $template_theme
|
||||
*/
|
||||
public function __construct($template_theme = 'default') {
|
||||
$this->template = new Smarty();
|
||||
|
||||
//$this->template->debugging = true;
|
||||
if($template_theme == 'default') {
|
||||
$this->template->setTemplateDir(dirname(__FILE__) . '/../templates');
|
||||
}
|
||||
else {
|
||||
$this->template->setTemplateDir(dirname(__FILE__) . '/../templates/'. $template_theme);
|
||||
}
|
||||
|
||||
// if it's not present or writeable, smarty should just not cache.
|
||||
$templates_c = dirname(__FILE__) . '/../templates_c';
|
||||
if (is_dir($templates_c) && is_writeable($templates_c)) {
|
||||
$this->template->setCompileDir($templates_c);
|
||||
} else {
|
||||
# unfortunately there's no sane way to just disable compiling of templates
|
||||
clearstatcache(); // just incase someone just fixed it; on their next refresh it should work.
|
||||
error_log("ERROR: directory $templates_c doesn't exist or isn't writeable for the webserver");
|
||||
die("ERROR: the templates_c directory doesn't exist or isn't writeable for the webserver");
|
||||
}
|
||||
|
||||
$this->template->setConfigDir(dirname(__FILE__) . '/../configs');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param bool $sanitise
|
||||
*/
|
||||
public function assign($key, $value, $sanitise = true) {
|
||||
$this->template->assign("RAW_$key", $value);
|
||||
if ($sanitise == false) {
|
||||
return $this->template->assign($key, $value);
|
||||
}
|
||||
$clean = $this->sanitise($value);
|
||||
/* we won't run the key through sanitise() here... some might argue we should */
|
||||
return $this->template->assign($key, $clean);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @param string $template
|
||||
*/
|
||||
public function display($template) {
|
||||
header("Expires: Sun, 16 Mar 2003 05:00:00 GMT");
|
||||
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
|
||||
header("Cache-Control: no-store, no-cache, must-revalidate");
|
||||
header("Cache-Control: post-check=0, pre-check=0", false);
|
||||
header("Pragma: no-cache");
|
||||
header("Content-Type: text/html; charset=UTF-8");
|
||||
|
||||
$this->template->display($template);
|
||||
unset($_SESSION['flash']); # cleanup flash messages
|
||||
}
|
||||
/**
|
||||
* Recursive cleaning of data, using htmlentities - this assumes we only ever output to HTML and we're outputting in UTF-8 charset
|
||||
*
|
||||
* @param mixed $data - array or primitive type; objects not supported.
|
||||
* @return mixed $data
|
||||
* */
|
||||
public function sanitise($data) {
|
||||
if (!is_array($data)) {
|
||||
return htmlentities($data, ENT_QUOTES, 'UTF-8', false);
|
||||
}
|
||||
$clean = array();
|
||||
foreach ($data as $key => $value) {
|
||||
/* as this is a nested data structure it's more likely we'll output the key too (at least in my opinion, so we'll sanitise it too */
|
||||
$clean[$this->sanitise($key)] = $this->sanitise($value);
|
||||
}
|
||||
return $clean;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file should only be loaded if you're :
|
||||
* a. running PHP < 7.0, and
|
||||
* b. have the php_crypt password hash configured, and
|
||||
* c. have not loaded paragonie's random_compat library.
|
||||
*
|
||||
*/
|
||||
|
||||
if(function_exists('random_int')) {
|
||||
return;
|
||||
}
|
||||
|
||||
function random_int($a, $b) { // someone might not be using php_crypt or ask for password generation, in which case random_int() won't be called
|
||||
die(__FILE__ . " Postfixadmin security: Please install https://github.com/paragonie/random_compat OR enable the 'Phar' extension.");
|
||||
}
|
Binary file not shown.
@ -0,0 +1,5 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEEd+wCqJDrx5B4OldM0dQE0ZMX+lx1ZWm
|
||||
pui0SUqD4G29L3NGsz9UhJ/0HjBdbnkhIK5xviT0X5vtjacF6ajgcCArbTB+ds+p
|
||||
+h7Q084NuSuIpNb6YPfoUFgC/CL9kAoc
|
||||
-----END PUBLIC KEY-----
|
@ -0,0 +1,4 @@
|
||||
Downloaded on 2018/04/29.
|
||||
|
||||
https://github.com/paragonie/random_compat/releases/download/v2.0.12/random_compat.phar.pubkey
|
||||
https://github.com/paragonie/random_compat/releases/download/v2.0.12/random_compat.phar
|
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
if (!isset($CONF) || !isset($PALANG)) {
|
||||
die("environment not setup correctly");
|
||||
}
|
||||
|
||||
require_once(dirname(__FILE__) . '/smarty/libs/Autoloader.php');
|
||||
|
||||
require_once(dirname(__FILE__) . '/PFASmarty.php');
|
||||
|
||||
Smarty_Autoloader::register();
|
||||
|
||||
if (isset($CONF['theme']) && is_dir(dirname(__FILE__) . "/../templates/" . $CONF['theme'])) {
|
||||
$smarty = new PFASmarty($CONF['theme']);
|
||||
} else {
|
||||
$smarty = new PFASmarty();
|
||||
}
|
||||
|
||||
if (!isset($rel_path)) {
|
||||
$rel_path = '';
|
||||
} # users/* sets this to '../'
|
||||
|
||||
$CONF['theme_css'] = $rel_path . htmlentities($CONF['theme_css']);
|
||||
if (!empty($CONF['theme_custom_css'])) {
|
||||
$CONF['theme_custom_css'] = $rel_path . htmlentities($CONF['theme_custom_css']);
|
||||
}
|
||||
$CONF['theme_favicon'] = $rel_path . htmlentities($CONF['theme_favicon']);
|
||||
$CONF['theme_logo'] = $rel_path . htmlentities($CONF['theme_logo']);
|
||||
|
||||
$smarty->assign('CONF', $CONF);
|
||||
$smarty->assign('PALANG', $PALANG);
|
||||
$smarty->assign('url_domain', '');
|
||||
//*** footer.tpl
|
||||
if (!isset($version)) {
|
||||
$version = 'dev/unknown';
|
||||
}
|
||||
$smarty->assign('version', $version);
|
||||
|
||||
//*** menu.tpl
|
||||
$smarty->assign('boolconf_alias_domain', Config::bool('alias_domain'));
|
||||
$smarty->assign('authentication_has_role', array('global_admin' => authentication_has_role('global-admin'), 'admin' => authentication_has_role('admin'), 'user' => authentication_has_role('user')));
|
||||
|
||||
/* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the Smarty package.
|
||||
*
|
||||
* (c) Sebastian Bergmann <sebastian@phpunit.de>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
/**
|
||||
* Load and register Smarty Autoloader
|
||||
*/
|
||||
if (!class_exists('Smarty_Autoloader')) {
|
||||
include dirname(__FILE__) . '/Autoloader.php';
|
||||
}
|
||||
Smarty_Autoloader::register(true);
|
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsFunction
|
||||
*/
|
||||
/**
|
||||
* Smarty {counter} function plugin
|
||||
* Type: function
|
||||
* Name: counter
|
||||
* Purpose: print out a counter value
|
||||
*
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @link http://www.smarty.net/manual/en/language.function.counter.php {counter}
|
||||
* (Smarty online manual)
|
||||
*
|
||||
* @param array $params parameters
|
||||
* @param Smarty_Internal_Template $template template object
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
function smarty_function_counter($params, $template)
|
||||
{
|
||||
static $counters = array();
|
||||
$name = (isset($params[ 'name' ])) ? $params[ 'name' ] : 'default';
|
||||
if (!isset($counters[ $name ])) {
|
||||
$counters[ $name ] = array('start' => 1, 'skip' => 1, 'direction' => 'up', 'count' => 1);
|
||||
}
|
||||
$counter =& $counters[ $name ];
|
||||
if (isset($params[ 'start' ])) {
|
||||
$counter[ 'start' ] = $counter[ 'count' ] = (int)$params[ 'start' ];
|
||||
}
|
||||
if (!empty($params[ 'assign' ])) {
|
||||
$counter[ 'assign' ] = $params[ 'assign' ];
|
||||
}
|
||||
if (isset($counter[ 'assign' ])) {
|
||||
$template->assign($counter[ 'assign' ], $counter[ 'count' ]);
|
||||
}
|
||||
if (isset($params[ 'print' ])) {
|
||||
$print = (bool)$params[ 'print' ];
|
||||
} else {
|
||||
$print = empty($counter[ 'assign' ]);
|
||||
}
|
||||
if ($print) {
|
||||
$retval = $counter[ 'count' ];
|
||||
} else {
|
||||
$retval = null;
|
||||
}
|
||||
if (isset($params[ 'skip' ])) {
|
||||
$counter[ 'skip' ] = $params[ 'skip' ];
|
||||
}
|
||||
if (isset($params[ 'direction' ])) {
|
||||
$counter[ 'direction' ] = $params[ 'direction' ];
|
||||
}
|
||||
if ($counter[ 'direction' ] === 'down') {
|
||||
$counter[ 'count' ] -= $counter[ 'skip' ];
|
||||
} else {
|
||||
$counter[ 'count' ] += $counter[ 'skip' ];
|
||||
}
|
||||
return $retval;
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsFunction
|
||||
*/
|
||||
/**
|
||||
* Smarty {cycle} function plugin
|
||||
* Type: function
|
||||
* Name: cycle
|
||||
* Date: May 3, 2002
|
||||
* Purpose: cycle through given values
|
||||
* Params:
|
||||
*
|
||||
* - name - name of cycle (optional)
|
||||
* - values - comma separated list of values to cycle, or an array of values to cycle
|
||||
* (this can be left out for subsequent calls)
|
||||
* - reset - boolean - resets given var to true
|
||||
* - print - boolean - print var or not. default is true
|
||||
* - advance - boolean - whether or not to advance the cycle
|
||||
* - delimiter - the value delimiter, default is ","
|
||||
* - assign - boolean, assigns to template var instead of printed.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* {cycle values="#eeeeee,#d0d0d0d"}
|
||||
* {cycle name=row values="one,two,three" reset=true}
|
||||
* {cycle name=row}
|
||||
*
|
||||
* @link http://www.smarty.net/manual/en/language.function.cycle.php {cycle}
|
||||
* (Smarty online manual)
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @author credit to Mark Priatel <mpriatel@rogers.com>
|
||||
* @author credit to Gerard <gerard@interfold.com>
|
||||
* @author credit to Jason Sweat <jsweat_php@yahoo.com>
|
||||
* @version 1.3
|
||||
*
|
||||
* @param array $params parameters
|
||||
* @param Smarty_Internal_Template $template template object
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
function smarty_function_cycle($params, $template)
|
||||
{
|
||||
static $cycle_vars;
|
||||
$name = (empty($params[ 'name' ])) ? 'default' : $params[ 'name' ];
|
||||
$print = (isset($params[ 'print' ])) ? (bool)$params[ 'print' ] : true;
|
||||
$advance = (isset($params[ 'advance' ])) ? (bool)$params[ 'advance' ] : true;
|
||||
$reset = (isset($params[ 'reset' ])) ? (bool)$params[ 'reset' ] : false;
|
||||
if (!isset($params[ 'values' ])) {
|
||||
if (!isset($cycle_vars[ $name ][ 'values' ])) {
|
||||
trigger_error('cycle: missing \'values\' parameter');
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (isset($cycle_vars[ $name ][ 'values' ]) && $cycle_vars[ $name ][ 'values' ] !== $params[ 'values' ]) {
|
||||
$cycle_vars[ $name ][ 'index' ] = 0;
|
||||
}
|
||||
$cycle_vars[ $name ][ 'values' ] = $params[ 'values' ];
|
||||
}
|
||||
if (isset($params[ 'delimiter' ])) {
|
||||
$cycle_vars[ $name ][ 'delimiter' ] = $params[ 'delimiter' ];
|
||||
} elseif (!isset($cycle_vars[ $name ][ 'delimiter' ])) {
|
||||
$cycle_vars[ $name ][ 'delimiter' ] = ',';
|
||||
}
|
||||
if (is_array($cycle_vars[ $name ][ 'values' ])) {
|
||||
$cycle_array = $cycle_vars[ $name ][ 'values' ];
|
||||
} else {
|
||||
$cycle_array = explode($cycle_vars[ $name ][ 'delimiter' ], $cycle_vars[ $name ][ 'values' ]);
|
||||
}
|
||||
if (!isset($cycle_vars[ $name ][ 'index' ]) || $reset) {
|
||||
$cycle_vars[ $name ][ 'index' ] = 0;
|
||||
}
|
||||
if (isset($params[ 'assign' ])) {
|
||||
$print = false;
|
||||
$template->assign($params[ 'assign' ], $cycle_array[ $cycle_vars[ $name ][ 'index' ] ]);
|
||||
}
|
||||
if ($print) {
|
||||
$retval = $cycle_array[ $cycle_vars[ $name ][ 'index' ] ];
|
||||
} else {
|
||||
$retval = null;
|
||||
}
|
||||
if ($advance) {
|
||||
if ($cycle_vars[ $name ][ 'index' ] >= count($cycle_array) - 1) {
|
||||
$cycle_vars[ $name ][ 'index' ] = 0;
|
||||
} else {
|
||||
$cycle_vars[ $name ][ 'index' ]++;
|
||||
}
|
||||
}
|
||||
return $retval;
|
||||
}
|
@ -0,0 +1,286 @@
|
||||
<?php
|
||||
/**
|
||||
* Smarty plugin
|
||||
*
|
||||
* @package Smarty
|
||||
* @subpackage PluginsFunction
|
||||
*/
|
||||
/**
|
||||
* Smarty {html_checkboxes} function plugin
|
||||
* File: function.html_checkboxes.php
|
||||
* Type: function
|
||||
* Name: html_checkboxes
|
||||
* Date: 24.Feb.2003
|
||||
* Purpose: Prints out a list of checkbox input types
|
||||
* Examples:
|
||||
*
|
||||
* {html_checkboxes values=$ids output=$names}
|
||||
* {html_checkboxes values=$ids name='box' separator='<br>' output=$names}
|
||||
* {html_checkboxes values=$ids checked=$checked separator='<br>' output=$names}
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* - name (optional) - string default "checkbox"
|
||||
* - values (required) - array
|
||||
* - options (optional) - associative array
|
||||
* - checked (optional) - array default not set
|
||||
* - separator (optional) - ie <br> or
|
||||
* - output (optional) - the output next to each checkbox
|
||||
* - assign (optional) - assign the output as an array to this variable
|
||||
* - escape (optional) - escape the content (not value), defaults to true
|
||||
*
|
||||
* @link http://www.smarty.net/manual/en/language.function.html.checkboxes.php {html_checkboxes}
|
||||
* (Smarty online manual)
|
||||
* @author Christopher Kvarme <christopher.kvarme@flashjab.com>
|
||||
* @author credits to Monte Ohrt <monte at ohrt dot com>
|
||||
* @version 1.0
|
||||
*
|
||||
* @param array $params parameters
|
||||
* @param Smarty_Internal_Template $template template object
|
||||
*
|
||||
* @return string
|
||||
* @uses smarty_function_escape_special_chars()
|
||||
* @throws \SmartyException
|
||||
*/
|
||||
function smarty_function_html_checkboxes($params, Smarty_Internal_Template $template)
|
||||
{
|
||||
$template->_checkPlugins(
|
||||
array(
|
||||
array(
|
||||
'function' => 'smarty_function_escape_special_chars',
|
||||
'file' => SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php'
|
||||
)
|
||||
)
|
||||
);
|
||||
$name = 'checkbox';
|
||||
$values = null;
|
||||
$options = null;
|
||||
$selected = array();
|
||||
$separator = '';
|
||||
$escape = true;
|
||||
$labels = true;
|
||||
$label_ids = false;
|
||||
$output = null;
|
||||
$extra = '';
|
||||
foreach ($params as $_key => $_val) {
|
||||
switch ($_key) {
|
||||
case 'name':
|
||||
case 'separator':
|
||||
$$_key = (string)$_val;
|
||||
break;
|
||||
case 'escape':
|
||||
case 'labels':
|
||||
case 'label_ids':
|
||||
$$_key = (bool)$_val;
|
||||
break;
|
||||
case 'options':
|
||||
$$_key = (array)$_val;
|
||||
break;
|
||||
case 'values':
|
||||
case 'output':
|
||||
$$_key = array_values((array)$_val);
|
||||
break;
|
||||
case 'checked':
|
||||
case 'selected':
|
||||
if (is_array($_val)) {
|
||||
$selected = array();
|
||||
foreach ($_val as $_sel) {
|
||||
if (is_object($_sel)) {
|
||||
if (method_exists($_sel, '__toString')) {
|
||||
$_sel = smarty_function_escape_special_chars((string)$_sel->__toString());
|
||||
} else {
|
||||
trigger_error(
|
||||
'html_checkboxes: selected attribute contains an object of class \'' .
|
||||
get_class($_sel) . '\' without __toString() method',
|
||||
E_USER_NOTICE
|
||||
);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
$_sel = smarty_function_escape_special_chars((string)$_sel);
|
||||
}
|
||||
$selected[ $_sel ] = true;
|
||||
}
|
||||
} elseif (is_object($_val)) {
|
||||
if (method_exists($_val, '__toString')) {
|
||||
$selected = smarty_function_escape_special_chars((string)$_val->__toString());
|
||||
} else {
|
||||
trigger_error(
|
||||
'html_checkboxes: selected attribute is an object of class \'' . get_class($_val) .
|
||||
'\' without __toString() method',
|
||||
E_USER_NOTICE
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$selected = smarty_function_escape_special_chars((string)$_val);
|
||||
}
|
||||
break;
|
||||
case 'checkboxes':
|
||||
trigger_error(
|
||||
'html_checkboxes: the use of the "checkboxes" attribute is deprecated, use "options" instead',
|
||||
E_USER_WARNING
|
||||
);
|
||||
$options = (array)$_val;
|
||||
break;
|
||||
case 'assign':
|
||||
break;
|
||||
case 'strict':
|
||||
break;
|
||||
case 'disabled':
|
||||
case 'readonly':
|
||||
if (!empty($params[ 'strict' ])) {
|
||||
if (!is_scalar($_val)) {
|
||||
trigger_error(
|
||||
"html_options: {$_key} attribute must be a scalar, only boolean true or string '{$_key}' will actually add the attribute",
|
||||
E_USER_NOTICE
|
||||
);
|
||||
}
|
||||
if ($_val === true || $_val === $_key) {
|
||||
$extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_key) . '"';
|
||||
}
|
||||
break;
|
||||
}
|
||||
// omit break; to fall through!
|
||||
// no break
|
||||
default:
|
||||
if (!is_array($_val)) {
|
||||
$extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_val) . '"';
|
||||
} else {
|
||||
trigger_error("html_checkboxes: extra attribute '{$_key}' cannot be an array", E_USER_NOTICE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isset($options) && !isset($values)) {
|
||||
return '';
|
||||
} /* raise error here? */
|
||||
$_html_result = array();
|
||||
if (isset($options)) {
|
||||
foreach ($options as $_key => $_val) {
|
||||
$_html_result[] =
|
||||
smarty_function_html_checkboxes_output(
|
||||
$name,
|
||||
$_key,
|
||||
$_val,
|
||||
$selected,
|
||||
$extra,
|
||||
$separator,
|
||||
$labels,
|
||||
$label_ids,
|
||||
$escape
|
||||
);
|
||||
}
|
||||
} else {
|
||||
foreach ($values as $_i => $_key) {
|
||||
$_val = isset($output[ $_i ]) ? $output[ $_i ] : '';
|
||||
$_html_result[] =
|
||||
smarty_function_html_checkboxes_output(
|
||||
$name,
|
||||
$_key,
|
||||
$_val,
|
||||
$selected,
|
||||
$extra,
|
||||
$separator,
|
||||
$labels,
|
||||
$label_ids,
|
||||
$escape
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!empty($params[ 'assign' ])) {
|
||||
$template->assign($params[ 'assign' ], $_html_result);
|
||||
} else {
|
||||
return implode("\n", $_html_result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $value
|
||||
* @param $output
|
||||
* @param $selected
|
||||
* @param $extra
|
||||
* @param $separator
|
||||
* @param $labels
|
||||
* @param $label_ids
|
||||
* @param bool $escape
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function smarty_function_html_checkboxes_output(
|
||||
$name,
|
||||
$value,
|
||||
$output,
|
||||
$selected,
|
||||
$extra,
|
||||
$separator,
|
||||
$labels,
|
||||
$label_ids,
|
||||
$escape = true
|
||||
) {
|
||||
$_output = '';
|
||||
if (is_object($value)) {
|
||||
if (method_exists($value, '__toString')) {
|
||||
$value = (string)$value->__toString();
|
||||
} else {
|
||||
trigger_error(
|
||||
'html_options: value is an object of class \'' . get_class($value) .
|
||||
'\' without __toString() method',
|
||||
E_USER_NOTICE
|
||||
);
|
||||
return '';
|
||||
}
|
||||
} else {
|
||||
$value = (string)$value;
|
||||
}
|
||||
if (is_object($output)) {
|
||||
if (method_exists($output, '__toString')) {
|
||||
$output = (string)$output->__toString();
|
||||
} else {
|
||||
trigger_error(
|
||||
'html_options: output is an object of class \'' . get_class($output) .
|
||||
'\' without __toString() method',
|
||||
E_USER_NOTICE
|
||||
);
|
||||
return '';
|
||||
}
|
||||
} else {
|
||||
$output = (string)$output;
|
||||
}
|
||||
if ($labels) {
|
||||
if ($label_ids) {
|
||||
$_id = smarty_function_escape_special_chars(
|
||||
preg_replace(
|
||||
'![^\w\-\.]!' . Smarty::$_UTF8_MODIFIER,
|
||||
'_',
|
||||
$name . '_' . $value
|
||||
)
|
||||
);
|
||||
$_output .= '<label for="' . $_id . '">';
|
||||
} else {
|
||||
$_output .= '<label>';
|
||||
}
|
||||
}
|
||||
$name = smarty_function_escape_special_chars($name);
|
||||
$value = smarty_function_escape_special_chars($value);
|
||||
if ($escape) {
|
||||
$output = smarty_function_escape_special_chars($output);
|
||||
}
|
||||
$_output .= '<input type="checkbox" name="' . $name . '[]" value="' . $value . '"';
|
||||
if ($labels && $label_ids) {
|
||||
$_output .= ' id="' . $_id . '"';
|
||||
}
|
||||
if (is_array($selected)) {
|
||||
if (isset($selected[ $value ])) {
|
||||
$_output .= ' checked="checked"';
|
||||
}
|
||||
} elseif ($value === $selected) {
|
||||
$_output .= ' checked="checked"';
|
||||
}
|
||||
$_output .= $extra . ' />' . $output;
|
||||
if ($labels) {
|
||||
$_output .= '</label>';
|
||||
}
|
||||
$_output .= $separator;
|
||||
return $_output;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue