1 # Copyright (C) 1998-2015 by the Free Software Foundation, Inc.
3 # This file is part of GNU Mailman.
5 # GNU Mailman is free software: you can redistribute it and/or modify it under
6 # the terms of the GNU General Public License as published by the Free
7 # Software Foundation, either version 3 of the License, or (at your option)
10 # GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 # You should have received a copy of the GNU General Public License along with
16 # GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
22 from email
.Charset
import Charset
24 from mailman
import MailList
25 from mailman
import Utils
26 from mailman
.app
.requests
import handle_request
27 from mailman
.configuration
import config
28 from mailman
.core
.i18n
import _
29 from mailman
.email
.message
import UserNotification
30 from mailman
.initialize
import initialize
31 from mailman
.interfaces
.requests
import IListRequests
, RequestType
32 from mailman
.version
import MAILMAN_VERSION
34 # Work around known problems with some RedHat cron daemons
36 signal
.signal(signal
.SIGCHLD
, signal
.SIG_DFL
)
44 parser
= optparse
.OptionParser(version
=MAILMAN_VERSION
,
48 Check for pending admin requests and mail the list owners if necessary."""))
49 parser
.add_option('-C', '--config',
50 help=_('Alternative configuration file to use'))
51 opts
, args
= parser
.parse_args()
54 print(_('Unexpected arguments'), file=sys
.stderr
)
56 return opts
, args
, parser
60 def pending_requests(mlist
):
61 # Must return a byte string
62 lcset
= mlist
.preferred_language
.charset
65 requestsdb
= IListRequests(mlist
)
66 for request
in requestsdb
.of_type(RequestType
.subscription
):
68 pending
.append(_('Pending subscriptions:'))
70 key
, data
= requestsdb
.get_request(request
.id)
73 fullname
= data
['fullname']
74 passwd
= data
['passwd']
75 digest
= data
['digest']
78 if isinstance(fullname
, unicode):
79 fullname
= fullname
.encode(lcset
, 'replace')
80 fullname
= ' (%s)' % fullname
81 pending
.append(' %s%s %s' % (addr
, fullname
, time
.ctime(when
)))
83 for request
in requestsdb
.of_type(RequestType
.held_message
):
85 pending
.append(_('\nPending posts:'))
87 key
, data
= requestsdb
.get_request(request
.id)
89 sender
= data
['sender']
90 subject
= data
['subject']
91 reason
= data
['reason']
93 msgdata
= data
['msgdata']
94 subject
= Utils
.oneline(subject
, lcset
)
95 date
= time
.ctime(when
)
98 From: $sender on $date
102 # Coerce all items in pending to a Unicode so we can join them
104 charset
= mlist
.preferred_language
.charset
106 if isinstance(s
, unicode):
109 upending
.append(unicode(s
, charset
, 'replace'))
110 # Make sure that the text we return from here can be encoded to a byte
111 # string in the charset of the list's language. This could fail if for
112 # example, the request was pended while the list's language was French,
113 # but then it was changed to English before checkdbs ran.
114 text
= NL
.join(upending
)
115 charset
= Charset(mlist
.preferred_language
.charset
)
116 incodec
= charset
.input_codec
or 'ascii'
117 outcodec
= charset
.output_codec
or 'ascii'
118 if isinstance(text
, unicode):
119 return text
.encode(outcodec
, 'replace')
120 # Be sure this is a byte string encodeable in the list's charset
121 utext
= unicode(text
, incodec
, 'replace')
122 return utext
.encode(outcodec
, 'replace')
126 def auto_discard(mlist
):
127 # Discard old held messages
129 expire
= config
.days(mlist
.max_days_to_hold
)
130 requestsdb
= IListRequests(mlist
)
131 heldmsgs
= list(requestsdb
.of_type(RequestType
.held_message
))
132 if expire
and heldmsgs
:
133 for request
in heldmsgs
:
134 key
, data
= requestsdb
.get_request(request
.id)
135 if now
- data
['date'] > expire
:
136 handle_request(mlist
, request
.id, config
.DISCARD
)
143 # Figure out epoch seconds of midnight at the start of today (or the given
144 # 3-tuple date of (year, month, day).
145 def midnight(date
=None):
147 date
= time
.localtime()[:3]
148 # -1 for dst flag tells the library to figure it out
149 return time
.mktime(date
+ (0,)*5 + (-1,))
153 opts
, args
, parser
= parseargs()
154 initialize(opts
.config
)
156 for name
in config
.list_manager
.names
:
157 # The list must be locked in order to open the requests database
158 mlist
= MailList
.MailList(name
)
160 count
= IListRequests(mlist
).count
161 # While we're at it, let's evict yesterday's autoresponse data
162 midnight_today
= midnight()
164 for sender
in mlist
.hold_and_cmd_autoresponses
.keys():
165 date
, respcount
= mlist
.hold_and_cmd_autoresponses
[sender
]
166 if midnight(date
) < midnight_today
:
167 evictions
.append(sender
)
169 for sender
in evictions
:
170 del mlist
.hold_and_cmd_autoresponses
[sender
]
171 # This is the only place we've changed the list's database
174 # Set the default language the the list's preferred language.
175 _
.default
= mlist
.preferred_language
176 realname
= mlist
.real_name
177 discarded
= auto_discard(mlist
)
179 count
= count
- discarded
180 text
= _('Notice: $discarded old request(s) '
181 'automatically expired.\n\n')
185 text
+= Utils
.maketext(
188 'mail_host': mlist
.mail_host
,
189 'adminDB' : mlist
.GetScriptURL('admindb',
191 'real_name': realname
,
193 text
+= '\n' + pending_requests(mlist
)
194 subject
= _('$count $realname moderator '
195 'request(s) waiting')
197 subject
= _('$realname moderator request check result')
198 msg
= UserNotification(mlist
.GetOwnerEmail(),
199 mlist
.GetBouncesEmail(),
201 mlist
.preferred_language
)
202 msg
.send(mlist
, **{'tomoderators': True})
208 if __name__
== '__main__':