1 # Copyright (C) 2006-2008 by the Free Software Foundation, Inc.
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
21 from storm
.locals import *
22 from zope
.interface
import implements
24 from mailman
.Utils
import fqdn_listname
, makedirs
, split_listname
25 from mailman
.configuration
import config
26 from mailman
.database
import roster
27 from mailman
.database
.model
import Model
28 from mailman
.database
.types
import Enum
29 from mailman
.interfaces
import IMailingList
, Personalization
37 class MailingList(Model
):
38 implements(IMailingList
)
40 id = Int(primary
=True)
45 # Attributes not directly modifiable via the web u/i
46 created_at
= DateTime()
47 web_page_url
= Unicode()
48 admin_member_chunksize
= Int()
49 hold_and_cmd_autoresponses
= Pickle()
50 # Attributes which are directly modifiable via the web u/i. The more
51 # complicated attributes are currently stored as pickles, though that
52 # will change as the schema and implementation is developed.
53 next_request_id
= Int()
54 next_digest_number
= Int()
55 admin_responses
= Pickle()
56 postings_responses
= Pickle()
57 request_responses
= Pickle()
58 digest_last_sent_at
= Float()
59 one_last_digest
= Pickle()
61 last_post_time
= DateTime()
62 # Attributes which are directly modifiable via the web u/i. The more
63 # complicated attributes are currently stored as pickles, though that
64 # will change as the schema and implementation is developed.
65 accept_these_nonmembers
= Pickle()
66 acceptable_aliases
= Pickle()
67 admin_immed_notify
= Bool()
68 admin_notify_mchanges
= Bool()
69 administrivia
= Bool()
71 anonymous_list
= Bool()
73 archive_private
= Bool()
74 archive_volume_frequency
= Int()
75 autorespond_admin
= Bool()
76 autorespond_postings
= Bool()
77 autorespond_requests
= Int()
78 autoresponse_admin_text
= Unicode()
79 autoresponse_graceperiod
= TimeDelta()
80 autoresponse_postings_text
= Unicode()
81 autoresponse_request_text
= Unicode()
83 bounce_info_stale_after
= TimeDelta()
84 bounce_matching_headers
= Unicode()
85 bounce_notify_owner_on_disable
= Bool()
86 bounce_notify_owner_on_removal
= Bool()
87 bounce_processing
= Bool()
88 bounce_score_threshold
= Int()
89 bounce_unrecognized_goes_to_list_owner
= Bool()
90 bounce_you_are_disabled_warnings
= Int()
91 bounce_you_are_disabled_warnings_interval
= TimeDelta()
92 collapse_alternatives
= Bool()
93 convert_html_to_plaintext
= Bool()
94 default_member_moderation
= Bool()
95 description
= Unicode()
96 digest_footer
= Unicode()
97 digest_header
= Unicode()
98 digest_is_default
= Bool()
99 digest_send_periodic
= Bool()
100 digest_size_threshold
= Int()
101 digest_volume_frequency
= Int()
103 discard_these_nonmembers
= Pickle()
105 encode_ascii_prefixes
= Bool()
106 filter_action
= Int()
107 filter_content
= Bool()
108 filter_filename_extensions
= Pickle()
109 filter_mime_types
= Pickle()
110 first_strip_reply_to
= Bool()
111 forward_auto_discards
= Bool()
112 gateway_to_mail
= Bool()
113 gateway_to_news
= Bool()
114 generic_nonmember_action
= Int()
115 goodbye_msg
= Unicode()
116 header_matches
= Pickle()
117 hold_these_nonmembers
= Pickle()
118 include_list_post_header
= Bool()
119 include_rfc2369_headers
= Bool()
121 linked_newsgroup
= Unicode()
122 max_days_to_hold
= Int()
123 max_message_size
= Int()
124 max_num_recipients
= Int()
125 member_moderation_action
= Enum()
126 member_moderation_notice
= Unicode()
127 mime_is_default_digest
= Bool()
128 moderator_password
= Unicode()
129 msg_footer
= Unicode()
130 msg_header
= Unicode()
131 new_member_options
= Int()
132 news_moderation
= Enum()
133 news_prefix_subject_too
= Bool()
134 nntp_host
= Unicode()
135 nondigestable
= Bool()
136 nonmember_rejection_notice
= Unicode()
137 obscure_addresses
= Bool()
138 pass_filename_extensions
= Pickle()
139 pass_mime_types
= Pickle()
143 preferred_language
= Unicode()
144 private_roster
= Bool()
145 real_name
= Unicode()
146 reject_these_nonmembers
= Pickle()
147 reply_goes_to_list
= Enum()
148 reply_to_address
= Unicode()
149 require_explicit_destination
= Bool()
150 respond_to_post_requests
= Bool()
151 scrub_nondigest
= Bool()
152 send_goodbye_msg
= Bool()
153 send_reminders
= Bool()
154 send_welcome_msg
= Bool()
155 start_chain
= Unicode()
156 subject_prefix
= Unicode()
157 subscribe_auto_approval
= Pickle()
158 subscribe_policy
= Int()
160 topics_bodylines_limit
= Int()
161 topics_enabled
= Bool()
162 unsubscribe_policy
= Int()
163 welcome_msg
= Unicode()
165 def __init__(self
, fqdn_listname
):
166 super(MailingList
, self
).__init
__()
167 listname
, hostname
= split_listname(fqdn_listname
)
168 self
.list_name
= listname
169 self
.host_name
= hostname
170 # For the pending database
171 self
.next_request_id
= 1
173 # Max autoresponses per day. A mapping between addresses and a
174 # 2-tuple of the date of the last autoresponse and the number of
175 # autoresponses sent on that date.
176 self
.hold_and_cmd_autoresponses
= {}
177 self
.personalization
= Personalization
.none
178 self
.real_name
= string
.capwords(
179 SPACE
.join(listname
.split(UNDERSCORE
)))
180 makedirs(self
.data_path
)
184 self
.owners
= roster
.OwnerRoster(self
)
185 self
.moderators
= roster
.ModeratorRoster(self
)
186 self
.administrators
= roster
.AdministratorRoster(self
)
187 self
.members
= roster
.MemberRoster(self
)
188 self
.regular_members
= roster
.RegularMemberRoster(self
)
189 self
.digest_members
= roster
.DigestMemberRoster(self
)
190 self
.subscribers
= roster
.Subscribers(self
)
193 def fqdn_listname(self
):
194 """See `IMailingList`."""
195 return fqdn_listname(self
.list_name
, self
.host_name
)
199 """See `IMailingList`."""
200 return config
.domains
[self
.host_name
]
202 def script_url(self
, target
, context
=None):
203 """See `IMailingList`."""
204 # XXX Handle the case for when context is not None; those would be
206 return self
.web_page_url
+ target
+ '/' + self
.fqdn_listname
210 """See `IMailingList`."""
211 return os
.path
.join(config
.LIST_DATA_DIR
, self
.fqdn_listname
)
213 # IMailingListAddresses
216 def posting_address(self
):
217 return self
.fqdn_listname
220 def no_reply_address(self
):
221 return '%s@%s' % (config
.NO_REPLY_ADDRESS
, self
.host_name
)
224 def owner_address(self
):
225 return '%s-owner@%s' % (self
.list_name
, self
.host_name
)
228 def request_address(self
):
229 return '%s-request@%s' % (self
.list_name
, self
.host_name
)
232 def bounces_address(self
):
233 return '%s-bounces@%s' % (self
.list_name
, self
.host_name
)
236 def join_address(self
):
237 return '%s-join@%s' % (self
.list_name
, self
.host_name
)
240 def leave_address(self
):
241 return '%s-leave@%s' % (self
.list_name
, self
.host_name
)
244 def subscribe_address(self
):
245 return '%s-subscribe@%s' % (self
.list_name
, self
.host_name
)
248 def unsubscribe_address(self
):
249 return '%s-unsubscribe@%s' % (self
.list_name
, self
.host_name
)
251 def confirm_address(self
, cookie
):
252 template
= string
.Template(config
.VERP_CONFIRM_FORMAT
)
253 local_part
= template
.safe_substitute(
254 address
= '%s-confirm' % self
.list_name
,
256 return '%s@%s' % (local_part
, self
.host_name
)
259 return '<mailing list "%s" at %#x>' % (self
.fqdn_listname
, id(self
))