def _setValue(self, mlist, property, val, doc): # Do value conversion from web representation to internal # representation. try: if property == 'bounce_processing': val = int(val) elif property == 'bounce_score_threshold': val = float(val) elif property == 'bounce_info_stale_after': val = days(int(val)) elif property == 'bounce_you_are_disabled_warnings': val = int(val) elif property == 'bounce_you_are_disabled_warnings_interval': val = days(int(val)) elif property == 'bounce_notify_owner_on_disable': val = int(val) elif property == 'bounce_notify_owner_on_removal': val = int(val) except ValueError: doc.addError( _("""Bad value for <a href="?VARHELP=bounce/%(property)s" >%(property)s</a>: %(val)s"""), tag = _('Error: ')) return GUIBase._setValue(self, mlist, property, val, doc)
def _setValue(self, mlist, property, val, doc): # Do value conversion from web representation to internal # representation. try: if property == 'bounce_processing': val = int(val) elif property == 'bounce_score_threshold': val = float(val) elif property == 'bounce_info_stale_after': val = days(int(val)) elif property == 'bounce_you_are_disabled_warnings': val = int(val) elif property == 'bounce_you_are_disabled_warnings_interval': val = days(int(val)) elif property == 'bounce_notify_owner_on_disable': val = int(val) elif property == 'bounce_notify_owner_on_removal': val = int(val) except ValueError: doc.addError( _("""Bad value for <a href="?VARHELP=bounce/%(property)s" >%(property)s</a>: %(val)s"""), tag=_('Error: ')) return GUIBase._setValue(self, mlist, property, val, doc)
def process(res, args): mlist = res.mlist if len(args) <> 1: res.results.append(_('Usage:')) res.results.append(gethelp(mlist)) return STOP cookie = args[0] try: results = mlist.ProcessConfirmation(cookie, res.msg) except Errors.MMBadConfirmation, e: # Express in approximate days days = int(mm_cfg.PENDING_REQUEST_LIFE / mm_cfg.days(1) + 0.5) res.results.append(_("""\ Invalid confirmation string. Note that confirmation strings expire approximately %(days)s days after the initial subscription request. If your confirmation has expired, please try to re-submit your original request or message."""))
def process(res, args): mlist = res.mlist if len(args) <> 1: res.results.append(_('Usage:')) res.results.append(gethelp(mlist)) return STOP cookie = args[0] try: results = mlist.ProcessConfirmation(cookie, res.msg) except Errors.MMBadConfirmation, e: # Express in approximate days days = int(mm_cfg.PENDING_REQUEST_LIFE / mm_cfg.days(1) + 0.5) res.results.append( _("""\ Invalid confirmation string. Note that confirmation strings expire approximately %(days)s days after the initial subscription request. If your confirmation has expired, please try to re-submit your original request or message."""))
return if not cookie and len(parts) == 2: cookie = parts[1] if len(parts) > 2: bad_confirmation(doc) doc.AddItem(mlist.GetMailmanFooter()) print doc.Format() return if not cookie: ask_for_cookie(mlist, doc) return days = int(mm_cfg.PENDING_REQUEST_LIFE / mm_cfg.days(1) + 0.5) confirmurl = mlist.GetScriptURL('confirm', absolute=1) # Avoid cross-site scripting attacks safecookie = Utils.websafe(cookie) badconfirmstr = _('''<b>Invalid confirmation string:</b> %(safecookie)s. <p>Note that confirmation strings expire approximately %(days)s days after the initial subscription request. If your confirmation has expired, please try to re-submit your subscription. Otherwise, <a href="%(confirmurl)s">re-enter</a> your confirmation string.''') content = mlist.pend_confirm(cookie, expunge=False) if content is None: bad_confirmation(doc, badconfirmstr)
def options_page(mlist, doc, user, cpuser, userlang, message=''): # The bulk of the document will come from the options.html template, which # includes it's own html armor (head tags, etc.). Suppress the head that # Document() derived pages get automatically. doc.suppress_head = 1 if mlist.obscure_addresses: presentable_user = Utils.ObscureEmail(user, for_text=1) if cpuser is not None: cpuser = Utils.ObscureEmail(cpuser, for_text=1) else: presentable_user = user fullname = Utils.uncanonstr(mlist.getMemberName(user), userlang) if fullname: presentable_user += ', %s' % Utils.websafe(fullname) # Do replacements replacements = mlist.GetStandardReplacements(userlang) replacements['<mm-results>'] = Bold(FontSize('+1', message)).Format() replacements['<mm-digest-radio-button>'] = mlist.FormatOptionButton( mm_cfg.Digests, 1, user) replacements['<mm-undigest-radio-button>'] = mlist.FormatOptionButton( mm_cfg.Digests, 0, user) replacements['<mm-plain-digests-button>'] = mlist.FormatOptionButton( mm_cfg.DisableMime, 1, user) replacements['<mm-mime-digests-button>'] = mlist.FormatOptionButton( mm_cfg.DisableMime, 0, user) replacements['<mm-global-mime-button>'] = (CheckBox('mime-globally', 1, checked=0).Format()) replacements['<mm-delivery-enable-button>'] = mlist.FormatOptionButton( mm_cfg.DisableDelivery, 0, user) replacements['<mm-delivery-disable-button>'] = mlist.FormatOptionButton( mm_cfg.DisableDelivery, 1, user) replacements['<mm-disabled-notice>'] = mlist.FormatDisabledNotice(user) replacements['<mm-dont-ack-posts-button>'] = mlist.FormatOptionButton( mm_cfg.AcknowledgePosts, 0, user) replacements['<mm-ack-posts-button>'] = mlist.FormatOptionButton( mm_cfg.AcknowledgePosts, 1, user) replacements['<mm-receive-own-mail-button>'] = mlist.FormatOptionButton( mm_cfg.DontReceiveOwnPosts, 0, user) replacements['<mm-dont-receive-own-mail-button>'] = ( mlist.FormatOptionButton(mm_cfg.DontReceiveOwnPosts, 1, user)) replacements['<mm-dont-get-password-reminder-button>'] = ( mlist.FormatOptionButton(mm_cfg.SuppressPasswordReminder, 1, user)) replacements['<mm-get-password-reminder-button>'] = ( mlist.FormatOptionButton(mm_cfg.SuppressPasswordReminder, 0, user)) replacements['<mm-public-subscription-button>'] = ( mlist.FormatOptionButton(mm_cfg.ConcealSubscription, 0, user)) replacements['<mm-hide-subscription-button>'] = mlist.FormatOptionButton( mm_cfg.ConcealSubscription, 1, user) replacements['<mm-dont-receive-duplicates-button>'] = ( mlist.FormatOptionButton(mm_cfg.DontReceiveDuplicates, 1, user)) replacements['<mm-receive-duplicates-button>'] = (mlist.FormatOptionButton( mm_cfg.DontReceiveDuplicates, 0, user)) replacements['<mm-unsubscribe-button>'] = ( mlist.FormatButton('unsub', _('Unsubscribe')) + '<br>' + CheckBox('unsubconfirm', 1, checked=0).Format() + _('<em>Yes, I really want to unsubscribe</em>')) replacements['<mm-new-pass-box>'] = mlist.FormatSecureBox('newpw') replacements['<mm-confirm-pass-box>'] = mlist.FormatSecureBox('confpw') replacements['<mm-change-pass-button>'] = (mlist.FormatButton( 'changepw', _("Change My Password"))) replacements['<mm-other-subscriptions-submit>'] = (mlist.FormatButton( 'othersubs', _('List my other subscriptions'))) replacements['<mm-form-start>'] = (mlist.FormatFormStart( 'options', user, mlist=mlist, contexts=AUTH_CONTEXTS, user=user)) replacements['<mm-user>'] = user replacements['<mm-presentable-user>'] = presentable_user replacements['<mm-email-my-pw>'] = mlist.FormatButton( 'emailpw', (_('Email My Password To Me'))) replacements['<mm-umbrella-notice>'] = (mlist.FormatUmbrellaNotice( user, _("password"))) replacements['<mm-logout-button>'] = (mlist.FormatButton( 'logout', _('Log out'))) replacements['<mm-options-submit-button>'] = mlist.FormatButton( 'options-submit', _('Submit My Changes')) replacements['<mm-global-pw-changes-button>'] = (CheckBox( 'pw-globally', 1, checked=0).Format()) replacements['<mm-global-deliver-button>'] = (CheckBox('deliver-globally', 1, checked=0).Format()) replacements['<mm-global-remind-button>'] = (CheckBox('remind-globally', 1, checked=0).Format()) replacements['<mm-global-nodupes-button>'] = (CheckBox('nodupes-globally', 1, checked=0).Format()) days = int(mm_cfg.PENDING_REQUEST_LIFE / mm_cfg.days(1)) if days > 1: units = _('days') else: units = _('day') replacements['<mm-pending-days>'] = _('%(days)d %(units)s') replacements['<mm-new-address-box>'] = mlist.FormatBox('new-address') replacements['<mm-confirm-address-box>'] = mlist.FormatBox( 'confirm-address') replacements['<mm-change-address-button>'] = mlist.FormatButton( 'change-of-address', _('Change My Address and Name')) replacements['<mm-global-change-of-address>'] = CheckBox( 'changeaddr-globally', 1, checked=0).Format() replacements['<mm-fullname-box>'] = mlist.FormatBox('fullname', value=fullname) # Create the topics radios. BAW: what if the list admin deletes a topic, # but the user still wants to get that topic message? usertopics = mlist.getMemberTopics(user) if mlist.topics: table = Table(border="0") for name, pattern, description, emptyflag in mlist.topics: if emptyflag: continue quotedname = urllib.parse.quote_plus(name) details = Link( mlist.GetScriptURL('options') + '/%s/?VARHELP=%s' % (user, quotedname), ' (Details)') if name in usertopics: checked = 1 else: checked = 0 table.AddRow([ CheckBox('usertopic', quotedname, checked=checked), name + details.Format() ]) topicsfield = table.Format() else: topicsfield = _('<em>No topics defined</em>') replacements['<mm-topics>'] = topicsfield replacements['<mm-suppress-nonmatching-topics>'] = ( mlist.FormatOptionButton(mm_cfg.ReceiveNonmatchingTopics, 0, user)) replacements['<mm-receive-nonmatching-topics>'] = ( mlist.FormatOptionButton(mm_cfg.ReceiveNonmatchingTopics, 1, user)) if cpuser is not None: replacements['<mm-case-preserved-user>'] = _(''' You are subscribed to this list with the case-preserved address <em>%(cpuser)s</em>.''') else: replacements['<mm-case-preserved-user>'] = '' page_text = mlist.ParseTags('options.html', replacements, userlang) if not (mlist.digestable or mlist.getMemberOption(user, mm_cfg.Digests)): page_text = DIGRE.sub('', page_text) doc.AddItem(page_text)
from Mailman import mm_cfg from Mailman import Utils from Mailman import Message from Mailman import MemberAdaptor from Mailman import Pending from Mailman.Errors import MMUnknownListError from Mailman.Logging.Syslog import syslog from Mailman import i18n EMPTYSTRING = "" # This constant is supposed to represent the day containing the first midnight # after the epoch. We'll add (0,)*6 to this tuple to get a value appropriate # for time.mktime(). ZEROHOUR_PLUSONEDAY = time.localtime(mm_cfg.days(1))[:3] def _(s): return s REASONS = { MemberAdaptor.BYBOUNCE: _("due to excessive bounces"), MemberAdaptor.BYUSER: _("by yourself"), MemberAdaptor.BYADMIN: _("by the list administrator"), MemberAdaptor.UNKNOWN: _("for unknown reasons"), } _ = i18n._
def reenable_prompt(mlist, doc, cookie, list, member): title = _('Re-enable mailing list membership') doc.SetTitle(title) form = Form(mlist.GetScriptURL('confirm', 1)) table = Table(border=0, width='100%') table.AddRow([Center(Bold(FontAttr(title, size='+1')))]) table.AddCellInfo(table.GetCurrentRowIndex(), 0, colspan=2, bgcolor=mm_cfg.WEB_HEADER_COLOR) lang = mlist.getMemberLanguage(member) i18n.set_language(lang) doc.set_language(lang) realname = mlist.real_name info = mlist.getBounceInfo(member) if not info: listinfourl = mlist.GetScriptURL('listinfo', absolute=1) # They've already be unsubscribed table.AddRow([ _("""We're sorry, but you have already been unsubscribed from this mailing list. To re-subscribe, please visit the <a href="%(listinfourl)s">list information page</a>.""") ]) return date = time.strftime('%A, %B %d, %Y', time.localtime(time.mktime(info.date + (0, ) * 6))) daysleft = int(info.noticesleft * mlist.bounce_you_are_disabled_warnings_interval / mm_cfg.days(1)) # BAW: for consistency this should be changed to 'fullname' or the above # 'fullname's should be changed to 'username'. Don't want to muck with # the i18n catalogs though. username = mlist.getMemberName(member) if username is None: username = _('<em>not available</em>') else: username = Utils.websafe(Utils.uncanonstr(username, lang)) table.AddRow([ _("""Your membership in the %(realname)s mailing list is currently disabled due to excessive bounces. Your confirmation is required in order to re-enable delivery to your address. We have the following information on file: <ul><li><b>Member address:</b> %(member)s <li><b>Member name:</b> %(username)s <li><b>Last bounce received on:</b> %(date)s <li><b>Approximate number of days before you are permanently removed from this list:</b> %(daysleft)s </ul> Hit the <em>Re-enable membership</em> button to resume receiving postings from the mailing list. Or hit the <em>Cancel</em> button to defer re-enabling your membership. """) ]) table.AddCellInfo(table.GetCurrentRowIndex(), 0, colspan=2) table.AddRow([Hidden('cookie', cookie)]) table.AddCellInfo(table.GetCurrentRowIndex(), 0, colspan=2) table.AddRow([ SubmitButton('submit', _('Re-enable membership')), SubmitButton('cancel', _('Cancel')) ]) form.AddItem(table) doc.AddItem(form)
def options_page(mlist, doc, user, cpuser, userlang, message=''): # The bulk of the document will come from the options.html template, which # includes it's own html armor (head tags, etc.). Suppress the head that # Document() derived pages get automatically. doc.suppress_head = 1 if mlist.obscure_addresses: presentable_user = Utils.ObscureEmail(user, for_text=1) if cpuser is not None: cpuser = Utils.ObscureEmail(cpuser, for_text=1) else: presentable_user = user fullname = Utils.uncanonstr(mlist.getMemberName(user), userlang) if fullname: presentable_user += ', %s' % Utils.websafe(fullname) # Do replacements replacements = mlist.GetStandardReplacements(userlang) replacements['<mm-results>'] = Bold(FontSize('+1', message)).Format() replacements['<mm-digest-radio-button>'] = mlist.FormatOptionButton( mm_cfg.Digests, 1, user) replacements['<mm-undigest-radio-button>'] = mlist.FormatOptionButton( mm_cfg.Digests, 0, user) replacements['<mm-plain-digests-button>'] = mlist.FormatOptionButton( mm_cfg.DisableMime, 1, user) replacements['<mm-mime-digests-button>'] = mlist.FormatOptionButton( mm_cfg.DisableMime, 0, user) replacements['<mm-global-mime-button>'] = ( CheckBox('mime-globally', 1, checked=0).Format()) replacements['<mm-delivery-enable-button>'] = mlist.FormatOptionButton( mm_cfg.DisableDelivery, 0, user) replacements['<mm-delivery-disable-button>'] = mlist.FormatOptionButton( mm_cfg.DisableDelivery, 1, user) replacements['<mm-disabled-notice>'] = mlist.FormatDisabledNotice(user) replacements['<mm-dont-ack-posts-button>'] = mlist.FormatOptionButton( mm_cfg.AcknowledgePosts, 0, user) replacements['<mm-ack-posts-button>'] = mlist.FormatOptionButton( mm_cfg.AcknowledgePosts, 1, user) replacements['<mm-receive-own-mail-button>'] = mlist.FormatOptionButton( mm_cfg.DontReceiveOwnPosts, 0, user) replacements['<mm-dont-receive-own-mail-button>'] = ( mlist.FormatOptionButton(mm_cfg.DontReceiveOwnPosts, 1, user)) replacements['<mm-dont-get-password-reminder-button>'] = ( mlist.FormatOptionButton(mm_cfg.SuppressPasswordReminder, 1, user)) replacements['<mm-get-password-reminder-button>'] = ( mlist.FormatOptionButton(mm_cfg.SuppressPasswordReminder, 0, user)) replacements['<mm-public-subscription-button>'] = ( mlist.FormatOptionButton(mm_cfg.ConcealSubscription, 0, user)) replacements['<mm-hide-subscription-button>'] = mlist.FormatOptionButton( mm_cfg.ConcealSubscription, 1, user) replacements['<mm-dont-receive-duplicates-button>'] = ( mlist.FormatOptionButton(mm_cfg.DontReceiveDuplicates, 1, user)) replacements['<mm-receive-duplicates-button>'] = ( mlist.FormatOptionButton(mm_cfg.DontReceiveDuplicates, 0, user)) replacements['<mm-unsubscribe-button>'] = ( mlist.FormatButton('unsub', _('Unsubscribe')) + '<br>' + CheckBox('unsubconfirm', 1, checked=0).Format() + _('<em>Yes, I really want to unsubscribe</em>')) replacements['<mm-new-pass-box>'] = mlist.FormatSecureBox('newpw') replacements['<mm-confirm-pass-box>'] = mlist.FormatSecureBox('confpw') replacements['<mm-change-pass-button>'] = ( mlist.FormatButton('changepw', _("Change My Password"))) replacements['<mm-other-subscriptions-submit>'] = ( mlist.FormatButton('othersubs', _('List my other subscriptions'))) replacements['<mm-form-start>'] = ( mlist.FormatFormStart('options', user)) replacements['<mm-user>'] = user replacements['<mm-presentable-user>'] = presentable_user replacements['<mm-email-my-pw>'] = mlist.FormatButton( 'emailpw', (_('Email My Password To Me'))) replacements['<mm-umbrella-notice>'] = ( mlist.FormatUmbrellaNotice(user, _("password"))) replacements['<mm-logout-button>'] = ( mlist.FormatButton('logout', _('Log out'))) replacements['<mm-options-submit-button>'] = mlist.FormatButton( 'options-submit', _('Submit My Changes')) replacements['<mm-global-pw-changes-button>'] = ( CheckBox('pw-globally', 1, checked=0).Format()) replacements['<mm-global-deliver-button>'] = ( CheckBox('deliver-globally', 1, checked=0).Format()) replacements['<mm-global-remind-button>'] = ( CheckBox('remind-globally', 1, checked=0).Format()) replacements['<mm-global-nodupes-button>'] = ( CheckBox('nodupes-globally', 1, checked=0).Format()) days = int(mm_cfg.PENDING_REQUEST_LIFE / mm_cfg.days(1)) if days > 1: units = _('days') else: units = _('day') replacements['<mm-pending-days>'] = _('%(days)d %(units)s') replacements['<mm-new-address-box>'] = mlist.FormatBox('new-address') replacements['<mm-confirm-address-box>'] = mlist.FormatBox( 'confirm-address') replacements['<mm-change-address-button>'] = mlist.FormatButton( 'change-of-address', _('Change My Address and Name')) replacements['<mm-global-change-of-address>'] = CheckBox( 'changeaddr-globally', 1, checked=0).Format() replacements['<mm-fullname-box>'] = mlist.FormatBox( 'fullname', value=fullname) gpgkey = mlist.getGPGKey(user) if gpgkey==None: gpgkey="" replacements['<mm-gpgkey-box>'] = ( '<textarea name="gpgkey" rows=10 cols=80>%s</textarea>' % gpgkey) replacements['<mm-global-gpgkey-changes-button>'] = ( CheckBox('gpgkey-globally', 1, checked=0).Format()) replacements['<mm-change-gpgkey-button>'] = ( mlist.FormatButton('submitgpgkey', _('Submit GPG key'))) smimekey = mlist.getSMIMEKey(user) if not smimekey: smimekey="" replacements['<mm-smimekey-box>'] = ( '<textarea name="smimekey" rows=10 cols=80>%s</textarea>' % smimekey) replacements['<mm-global-smimekey-changes-button>'] = ( CheckBox('smimekey-globally', 1, checked=0).Format()) replacements['<mm-change-smimekey-button>'] = ( mlist.FormatButton('submitsmimekey', _('Submit S/MIME key'))) # Create the topics radios. BAW: what if the list admin deletes a topic, # but the user still wants to get that topic message? usertopics = mlist.getMemberTopics(user) if mlist.topics: table = Table(border="0") for name, pattern, description, emptyflag in mlist.topics: if emptyflag: continue quotedname = urllib.quote_plus(name) details = Link(mlist.GetScriptURL('options') + '/%s/?VARHELP=%s' % (user, quotedname), ' (Details)') if name in usertopics: checked = 1 else: checked = 0 table.AddRow([CheckBox('usertopic', quotedname, checked=checked), name + details.Format()]) topicsfield = table.Format() else: topicsfield = _('<em>No topics defined</em>') replacements['<mm-topics>'] = topicsfield replacements['<mm-suppress-nonmatching-topics>'] = ( mlist.FormatOptionButton(mm_cfg.ReceiveNonmatchingTopics, 0, user)) replacements['<mm-receive-nonmatching-topics>'] = ( mlist.FormatOptionButton(mm_cfg.ReceiveNonmatchingTopics, 1, user)) if cpuser is not None: replacements['<mm-case-preserved-user>'] = _(''' You are subscribed to this list with the case-preserved address <em>%(cpuser)s</em>.''') else: replacements['<mm-case-preserved-user>'] = '' doc.AddItem(mlist.ParseTags('options.html', replacements, userlang))
def options_page(mlist, doc, user, cpuser, userlang, message=""): # The bulk of the document will come from the options.html template, which # includes it's own html armor (head tags, etc.). Suppress the head that # Document() derived pages get automatically. doc.suppress_head = 1 if mlist.obscure_addresses: presentable_user = Utils.ObscureEmail(user, for_text=1) if cpuser is not None: cpuser = Utils.ObscureEmail(cpuser, for_text=1) else: presentable_user = user fullname = Utils.uncanonstr(mlist.getMemberName(user), userlang) if fullname: presentable_user += ", %s" % Utils.websafe(fullname) # Do replacements replacements = mlist.GetStandardReplacements(userlang) replacements["<mm-results>"] = Bold(FontSize("+1", message)).Format() replacements["<mm-digest-radio-button>"] = mlist.FormatOptionButton(mm_cfg.Digests, 1, user) replacements["<mm-undigest-radio-button>"] = mlist.FormatOptionButton(mm_cfg.Digests, 0, user) replacements["<mm-plain-digests-button>"] = mlist.FormatOptionButton(mm_cfg.DisableMime, 1, user) replacements["<mm-mime-digests-button>"] = mlist.FormatOptionButton(mm_cfg.DisableMime, 0, user) replacements["<mm-global-mime-button>"] = CheckBox("mime-globally", 1, checked=0).Format() replacements["<mm-delivery-enable-button>"] = mlist.FormatOptionButton(mm_cfg.DisableDelivery, 0, user) replacements["<mm-delivery-disable-button>"] = mlist.FormatOptionButton(mm_cfg.DisableDelivery, 1, user) replacements["<mm-disabled-notice>"] = mlist.FormatDisabledNotice(user) replacements["<mm-dont-ack-posts-button>"] = mlist.FormatOptionButton(mm_cfg.AcknowledgePosts, 0, user) replacements["<mm-ack-posts-button>"] = mlist.FormatOptionButton(mm_cfg.AcknowledgePosts, 1, user) replacements["<mm-receive-own-mail-button>"] = mlist.FormatOptionButton(mm_cfg.DontReceiveOwnPosts, 0, user) replacements["<mm-dont-receive-own-mail-button>"] = mlist.FormatOptionButton(mm_cfg.DontReceiveOwnPosts, 1, user) replacements["<mm-dont-get-password-reminder-button>"] = mlist.FormatOptionButton( mm_cfg.SuppressPasswordReminder, 1, user ) replacements["<mm-get-password-reminder-button>"] = mlist.FormatOptionButton( mm_cfg.SuppressPasswordReminder, 0, user ) replacements["<mm-public-subscription-button>"] = mlist.FormatOptionButton(mm_cfg.ConcealSubscription, 0, user) replacements["<mm-hide-subscription-button>"] = mlist.FormatOptionButton(mm_cfg.ConcealSubscription, 1, user) replacements["<mm-dont-receive-duplicates-button>"] = mlist.FormatOptionButton( mm_cfg.DontReceiveDuplicates, 1, user ) replacements["<mm-receive-duplicates-button>"] = mlist.FormatOptionButton(mm_cfg.DontReceiveDuplicates, 0, user) replacements["<mm-unsubscribe-button>"] = ( mlist.FormatButton("unsub", _("Unsubscribe")) + "<br>" + CheckBox("unsubconfirm", 1, checked=0).Format() + _("<em>Yes, I really want to unsubscribe</em>") ) replacements["<mm-new-pass-box>"] = mlist.FormatSecureBox("newpw") replacements["<mm-confirm-pass-box>"] = mlist.FormatSecureBox("confpw") replacements["<mm-change-pass-button>"] = mlist.FormatButton("changepw", _("Change My Password")) replacements["<mm-other-subscriptions-submit>"] = mlist.FormatButton("othersubs", _("List my other subscriptions")) replacements["<mm-form-start>"] = mlist.FormatFormStart("options", user) replacements["<mm-user>"] = user replacements["<mm-presentable-user>"] = presentable_user replacements["<mm-email-my-pw>"] = mlist.FormatButton("emailpw", (_("Email My Password To Me"))) replacements["<mm-umbrella-notice>"] = mlist.FormatUmbrellaNotice(user, _("password")) replacements["<mm-logout-button>"] = mlist.FormatButton("logout", _("Log out")) replacements["<mm-options-submit-button>"] = mlist.FormatButton("options-submit", _("Submit My Changes")) replacements["<mm-global-pw-changes-button>"] = CheckBox("pw-globally", 1, checked=0).Format() replacements["<mm-global-deliver-button>"] = CheckBox("deliver-globally", 1, checked=0).Format() replacements["<mm-global-remind-button>"] = CheckBox("remind-globally", 1, checked=0).Format() replacements["<mm-global-nodupes-button>"] = CheckBox("nodupes-globally", 1, checked=0).Format() days = int(mm_cfg.PENDING_REQUEST_LIFE / mm_cfg.days(1)) if days > 1: units = _("days") else: units = _("day") replacements["<mm-pending-days>"] = _("%(days)d %(units)s") replacements["<mm-new-address-box>"] = mlist.FormatBox("new-address") replacements["<mm-confirm-address-box>"] = mlist.FormatBox("confirm-address") replacements["<mm-change-address-button>"] = mlist.FormatButton( "change-of-address", _("Change My Address and Name") ) replacements["<mm-global-change-of-address>"] = CheckBox("changeaddr-globally", 1, checked=0).Format() replacements["<mm-fullname-box>"] = mlist.FormatBox("fullname", value=fullname) # Create the topics radios. BAW: what if the list admin deletes a topic, # but the user still wants to get that topic message? usertopics = mlist.getMemberTopics(user) if mlist.topics: table = Table(border="0") for name, pattern, description, emptyflag in mlist.topics: if emptyflag: continue quotedname = urllib.quote_plus(name) details = Link(mlist.GetScriptURL("options") + "/%s/?VARHELP=%s" % (user, quotedname), " (Details)") if name in usertopics: checked = 1 else: checked = 0 table.AddRow([CheckBox("usertopic", quotedname, checked=checked), name + details.Format()]) topicsfield = table.Format() else: topicsfield = _("<em>No topics defined</em>") replacements["<mm-topics>"] = topicsfield replacements["<mm-suppress-nonmatching-topics>"] = mlist.FormatOptionButton( mm_cfg.ReceiveNonmatchingTopics, 0, user ) replacements["<mm-receive-nonmatching-topics>"] = mlist.FormatOptionButton(mm_cfg.ReceiveNonmatchingTopics, 1, user) if cpuser is not None: replacements["<mm-case-preserved-user>"] = _( """ You are subscribed to this list with the case-preserved address <em>%(cpuser)s</em>.""" ) else: replacements["<mm-case-preserved-user>"] = "" doc.AddItem(mlist.ParseTags("options.html", replacements, userlang))
def main(): doc = Document() doc.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE) parts = Utils.GetPathPieces() if not parts or len(parts) < 1: bad_confirmation(doc) doc.AddItem(MailmanLogo()) print(doc.Format()) return listname = parts[0].lower() try: mlist = MailList.MailList(listname, lock=0) except Errors.MMListError as e: # Avoid cross-site scripting attacks safelistname = Utils.websafe(listname) bad_confirmation(doc, _('No such list <em>%(safelistname)s</em>')) doc.AddItem(MailmanLogo()) # Send this with a 404 status. print('Status: 404 Not Found') print(doc.Format()) syslog('error', 'confirm: No such list "%s": %s', listname, e) return # Set the language for the list i18n.set_language(mlist.preferred_language) doc.set_language(mlist.preferred_language) # Get the form data to see if this is a second-step confirmation cgidata = cgi.FieldStorage(keep_blank_values=1) try: cookie = cgidata.getfirst('cookie') except TypeError: # Someone crafted a POST with a bad Content-Type:. doc.AddItem(Header(2, _("Error"))) doc.AddItem(Bold(_('Invalid options to CGI script.'))) # Send this with a 400 status. print('Status: 400 Bad Request') print(doc.Format()) return if cookie == '': ask_for_cookie(mlist, doc, _('Confirmation string was empty.')) return if not cookie and len(parts) == 2: cookie = parts[1] if len(parts) > 2: bad_confirmation(doc) doc.AddItem(mlist.GetMailmanFooter()) print(doc.Format()) return if not cookie: ask_for_cookie(mlist, doc) return days = int(mm_cfg.PENDING_REQUEST_LIFE / mm_cfg.days(1) + 0.5) confirmurl = mlist.GetScriptURL('confirm', absolute=1) # Avoid cross-site scripting attacks safecookie = Utils.websafe(cookie) badconfirmstr = _('''<b>Invalid confirmation string:</b> %(safecookie)s. <p>Note that confirmation strings expire approximately %(days)s days after the initial request. They also expire if the request has already been handled in some way. If your confirmation has expired, please try to re-submit your request. Otherwise, <a href="%(confirmurl)s">re-enter</a> your confirmation string.''') content = mlist.pend_confirm(cookie, expunge=False) if content is None: bad_confirmation(doc, badconfirmstr) doc.AddItem(mlist.GetMailmanFooter()) print(doc.Format()) return try: if content[0] == Pending.SUBSCRIPTION: if cgidata.getfirst('cancel'): subscription_cancel(mlist, doc, cookie) elif cgidata.getfirst('submit'): subscription_confirm(mlist, doc, cookie, cgidata) else: subscription_prompt(mlist, doc, cookie, content[1]) elif content[0] == Pending.UNSUBSCRIPTION: try: if cgidata.getfirst('cancel'): unsubscription_cancel(mlist, doc, cookie) elif cgidata.getfirst('submit'): unsubscription_confirm(mlist, doc, cookie) else: unsubscription_prompt(mlist, doc, cookie, *content[1:]) except Errors.NotAMemberError: doc.addError( _("""The address requesting unsubscription is not a member of the mailing list. Perhaps you have already been unsubscribed, e.g. by the list administrator?""")) # Expunge this record from the pending database. expunge(mlist, cookie) elif content[0] == Pending.CHANGE_OF_ADDRESS: if cgidata.getfirst('cancel'): addrchange_cancel(mlist, doc, cookie) elif cgidata.getfirst('submit'): addrchange_confirm(mlist, doc, cookie) else: # Watch out for users who have unsubscribed themselves in the # meantime! try: addrchange_prompt(mlist, doc, cookie, *content[1:]) except Errors.NotAMemberError: doc.addError( _("""The address requesting to be changed has been subsequently unsubscribed. This request has been cancelled.""")) # Expunge this record from the pending database. expunge(mlist, cookie) elif content[0] == Pending.HELD_MESSAGE: if cgidata.getfirst('cancel'): heldmsg_cancel(mlist, doc, cookie) elif cgidata.getfirst('submit'): heldmsg_confirm(mlist, doc, cookie) else: heldmsg_prompt(mlist, doc, cookie, *content[1:]) elif content[0] == Pending.RE_ENABLE: if cgidata.getfirst('cancel'): reenable_cancel(mlist, doc, cookie) elif cgidata.getfirst('submit'): reenable_confirm(mlist, doc, cookie) else: reenable_prompt(mlist, doc, cookie, *content[1:]) else: bad_confirmation(doc, _('System error, bad content: %(content)s')) except Errors.MMBadConfirmation: bad_confirmation(doc, badconfirmstr) doc.AddItem(mlist.GetMailmanFooter()) print(doc.Format())
def getValue(self, mlist, kind, varname, params): if varname not in ('bounce_info_stale_after', 'bounce_you_are_disabled_warnings_interval'): return None return int(getattr(mlist, varname) / days(1))
def reenable_prompt(mlist, doc, cookie, list, member): title = _('Re-enable mailing list membership') doc.SetTitle(title) form = Form(mlist.GetScriptURL('confirm', 1)) table = Table(border=0, width='100%') table.AddRow([Center(Bold(FontAttr(title, size='+1')))]) table.AddCellInfo(table.GetCurrentRowIndex(), 0, colspan=2, bgcolor=mm_cfg.WEB_HEADER_COLOR) lang = mlist.getMemberLanguage(member) i18n.set_language(lang) doc.set_language(lang) realname = mlist.real_name info = mlist.getBounceInfo(member) if not info: listinfourl = mlist.GetScriptURL('listinfo', absolute=1) # They've already be unsubscribed table.AddRow([_("""We're sorry, but you have already been unsubscribed from this mailing list. To re-subscribe, please visit the <a href="%(listinfourl)s">list information page</a>.""")]) return date = time.strftime('%A, %B %d, %Y', time.localtime(time.mktime(info.date + (0,)*6))) daysleft = int(info.noticesleft * mlist.bounce_you_are_disabled_warnings_interval / mm_cfg.days(1)) # BAW: for consistency this should be changed to 'fullname' or the above # 'fullname's should be changed to 'username'. Don't want to muck with # the i18n catalogs though. username = mlist.getMemberName(member) if username is None: username = _('<em>not available</em>') else: username = Utils.websafe(Utils.uncanonstr(username, lang)) table.AddRow([_("""Your membership in the %(realname)s mailing list is currently disabled due to excessive bounces. Your confirmation is required in order to re-enable delivery to your address. We have the following information on file: <ul><li><b>Member address:</b> %(member)s <li><b>Member name:</b> %(username)s <li><b>Last bounce received on:</b> %(date)s <li><b>Approximate number of days before you are permanently removed from this list:</b> %(daysleft)s </ul> Hit the <em>Re-enable membership</em> button to resume receiving postings from the mailing list. Or hit the <em>Cancel</em> button to defer re-enabling your membership. """)]) table.AddCellInfo(table.GetCurrentRowIndex(), 0, colspan=2) table.AddRow([Hidden('cookie', cookie)]) table.AddCellInfo(table.GetCurrentRowIndex(), 0, colspan=2) table.AddRow([SubmitButton('submit', _('Re-enable membership')), SubmitButton('cancel', _('Cancel'))]) form.AddItem(table) doc.AddItem(form)
from Mailman import mm_cfg from Mailman import Utils from Mailman import Message from Mailman import MemberAdaptor from Mailman import Pending from Mailman.Errors import MMUnknownListError from Mailman.Logging.Syslog import syslog from Mailman import i18n EMPTYSTRING = '' # This constant is supposed to represent the day containing the first midnight # after the epoch. We'll add (0,)*6 to this tuple to get a value appropriate # for time.mktime(). ZEROHOUR_PLUSONEDAY = time.localtime(mm_cfg.days(1))[:3] def _(s): return s REASONS = { MemberAdaptor.BYBOUNCE: _('due to excessive bounces'), MemberAdaptor.BYUSER: _('by yourself'), MemberAdaptor.BYADMIN: _('by the list administrator'), MemberAdaptor.UNKNOWN: _('for unknown reasons'), } _ = i18n._
def process(res, args): mlist = res.mlist if len(args) != 1: res.results.append(_('Usage:')) res.results.append(gethelp(mlist)) return STOP cookie = args[0] try: results = mlist.ProcessConfirmation(cookie, res.msg) except Errors.MMBadConfirmation as e: # Express in approximate days days = int(mm_cfg.PENDING_REQUEST_LIFE / mm_cfg.days(1) + 0.5) res.results.append(_("""\ Invalid confirmation string. Note that confirmation strings expire approximately %(days)s days after the initial request. They also expire if the request has already been handled in some way. If your confirmation has expired, please try to re-submit your original request or message.""")) except Errors.MMNeedApproval: res.results.append(_("""\ Your request has been forwarded to the list moderator for approval.""")) except Errors.MMAlreadyAMember: # Some other subscription request for this address has # already succeeded. res.results.append(_('You are already subscribed.')) except Errors.NotAMemberError: # They've already been unsubscribed res.results.append(_("""\ You are not currently a member. Have you already unsubscribed or changed your email address?""")) except Errors.MembershipIsBanned: owneraddr = mlist.GetOwnerEmail() res.results.append(_("""\ You are currently banned from subscribing to this list. If you think this restriction is erroneous, please contact the list owners at %(owneraddr)s.""")) except Errors.HostileSubscriptionError: res.results.append(_("""\ You were not invited to this mailing list. The invitation has been discarded, and both list administrators have been alerted.""")) except Errors.MMBadPasswordError: res.results.append(_("""\ Bad approval password given. Held message is still being held.""")) else: if ((results[0] == Pending.SUBSCRIPTION and mlist.send_welcome_msg) or (results[0] == Pending.UNSUBSCRIPTION and mlist.send_goodbye_msg)): # We don't also need to send a confirmation succeeded message res.respond = 0 else: if results[0] == Pending.HELD_MESSAGE: if results[1] == mm_cfg.APPROVE: res.results.append(_('Confirmation succeeded') + ' (' + _('Approve') + ')') else: res.results.append(_('Confirmation succeeded') + ' (' + _('Discard') + ')') else: res.results.append(_('Confirmation succeeded')) # Consume any other confirmation strings with the same cookie so # the user doesn't get a misleading "unprocessed" message. # Also consume any Approve(d): line as it was processed. match = 'confirm ' + cookie unprocessed = [] for line in res.commands: try: if (line.lstrip() == match or line.lstrip().lower().startswith('approved:') or line.lstrip().lower().startswith('approve:')): continue except UnicodeError: pass unprocessed.append(line) res.commands = unprocessed # Process just one confirmation string per message return STOP