[Mailman-i18n] Example marking file

Juan Carlos Rey Anaya jcrey@uma.es
Fri, 10 Nov 2000 20:59:20 +0100


This is a multi-part message in MIME format.
--------------BFB93F3D3F601EC069B326B6
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: quoted-printable

I send you a piece of file with marking already done, in order
contributors can note how to do markings.

I have tried (where possible) to take apart HTML code.
Cheers

PD:
There may be errors, I have done it in a hurry.
-- =

                          ___
                         / F \
                        [[[]]]]
                        ( O O )
   #----------------0000--(_)--0000---------------#
   |    Juan Carlos Rey Anaya (jcrey@uma.es)      |
   |      Servicio Central de inform=E1tica         |
   |       Universidad de M=E1laga - Espa=F1a         |
   #----------------------------------------------#
   #      Solo se que cada vez se menos :-|       #
   #----------------------------------------------#
--------------BFB93F3D3F601EC069B326B6
Content-Type: text/plain; charset=iso-8859-1;
 name="admin.py"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline;
 filename="admin.py"

        if category not in map(lambda x: x[0], CATEGORIES):
            category =3D 'general'

        # is the request for variable details?
        varhelp =3D None
        if cgidata.has_key('VARHELP'):
            varhelp =3D cgidata['VARHELP'].value
        elif cgidata.has_key('request_login') and \
             os.environ.get('QUERY_STRING'):
            # POST methods, even if their actions have a query string, do=
n't
            # get put into FieldStorage's keys :-(
            qs =3D cgi.parse_qs(os.environ['QUERY_STRING']).get('VARHELP'=
)
            if qs and type(qs) =3D=3D types.ListType:
                varhelp =3D qs[0]
        if varhelp:
            FormatOptionHelp(doc, varhelp, mlist)
            print doc.Format(bgcolor=3D"#ffffff")
            return

        if cgidata.has_key('bounce_matching_headers'):
            pairs =3D mlist.parse_matching_header_opt()

        if len(cgidata.keys()):
            ChangeOptions(mlist, category, cgidata, doc)
            mlist.CheckValues()

        # Sanity checks
        if not mlist.digestable and not mlist.nondigestable:
            AddErrorMessage(doc, _('''You have turned off delivery of
            both digest and non-digest messages.  This is an incompatible=

            state of affairs.  You must turn on either digest delivery or=

            non-digest delivery or your mailing list will basically be
            unusable.'''))
	if not mlist.digestable and len(mlist.GetDigestMembers()):
	    AddErrorMessage(doc, _('''You have digest members,
            but digests are turned off. Those people will not receive
            mail.'''))
	if not mlist.nondigestable and len(mlist.GetMembers()):
	    AddErrorMessage(doc, _('''You have regular list members
            but non-digestified mail is turned off.  They will receive ma=
il
            until you fix this problem.'''))

	FormatConfiguration(doc, mlist, category, category_suffix, cgidata)
	print doc.Format(bgcolor=3D"#ffffff")
    finally:
        mlist.Save()
        mlist.Unlock()


=0C
# Form Production:
def FormatAdminOverview(error=3DNone):
    "Present a general welcome and itemize the (public) lists."
    doc =3D Document()
    legend =3D _("%s mailing lists - Admin Links") % mm_cfg.DEFAULT_HOST_=
NAME
    doc.SetTitle(legend)

    table =3D Table(border=3D0, width=3D"100%")
    table.AddRow([Center(Header(2, legend))])
    table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 0,
                      colspan=3D2, bgcolor=3D"#99ccff")

    advertised =3D []
    names =3D Utils.list_names()
    names.sort()
    for n in names:
	l =3D MailList.MailList(n, lock=3D0)
        if l.advertised:
            advertised.append(l)

    if error:
	greeting =3D FontAttr(error, color=3D"ff5060", size=3D"+1")
    else:
	greeting =3D _("Welcome!")

    if not advertised:
        welcome_items =3D (greeting,
			 _("<p>"
	 		   " There currently are no publicly-advertised "),
			 Link(mm_cfg.MAILMAN_URL, "mailman"),
			 _(" mailing lists on %s.") % mm_cfg.DEFAULT_HOST_NAME,
			 )
    else:
        welcome_items =3D (
	    greeting,
            _("<p>"
              " Below is the collection of publicly-advertised "),
            Link(mm_cfg.MAILMAN_URL, "mailman"),
            _(" mailing lists on %s.") % mm_cfg.DEFAULT_HOST_NAME,
            (_(' Click on a list name to visit the configuration pages'
               ' for that list.')
             )
            )

    welcome_items =3D (welcome_items +
                     (_(" To visit the administrators configuration page =
for"
                        " an unadvertised list, open a URL similar to thi=
s")
                      +
                      (_(" one, but with a '/' and the %slist name append=
ed.<p>")
                       % ((error and _("right ")) or ""))
                      +
                      _(" General list information can be found at "),
                      Link(Utils.ScriptURL('listinfo'),
                           _('the mailing list overview page')),
                      "."
                      _("<p>(Send questions and comments to "),
                     Link("mailto:%s" % mm_cfg.MAILMAN_OWNER,
                          mm_cfg.MAILMAN_OWNER),
                     ".)<p>"
                      )
                     )

    table.AddRow([apply(Container, welcome_items)])
    table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 0, colspan=3D2)=


    if advertised:
        table.AddRow(['&nbsp;', '&nbsp;'])
        table.AddRow([Bold(_("List")), Bold(_("Description"))])
        for l in advertised:
            table.AddRow(
                [Link(l.GetScriptURL('admin'), Bold(l.real_name)),
                 l.description or Italic(_('[no description available]'))=
,
                 ])

    doc.AddItem(table)
    doc.AddItem('<hr>')
    doc.AddItem(MailmanLogo())
    print doc.Format(bgcolor=3D"#ffffff")


=0C
def FormatConfiguration(doc, mlist, category, category_suffix, cgi_data):=

    """Produce the overall doc, *except* any processing error messages.""=
"
    for k, v in CATEGORIES:
        if k =3D=3D category:
            label =3D v

    doc.SetTitle('%s Administration (%s)' % (mlist.real_name, label))
    doc.AddItem(Center(Header(2, _('%s mailing list administration<br>%s =
Section')
                              % (mlist.real_name, label))))
    doc.AddItem('<hr>')

    linktable =3D Table(valign=3D"top")
    linktable.AddRow([Center(Bold(_("Configuration Categories"))),
                      Center(Bold(_("Other Administrative Activities")))]=
)

    adminurl =3D mlist.GetScriptURL('admin')

    otherlinks =3D UnorderedList()
    otherlinks.AddItem(Link(mlist.GetScriptURL('admindb'), =

                            _('Tend to pending administrative requests'))=
)
    otherlinks.AddItem(Link(mlist.GetScriptURL('listinfo'),
                            _('Go to the general list information page'))=
)
    otherlinks.AddItem(Link(mlist.GetScriptURL('edithtml'),
                            _('Edit the HTML for the public list pages'))=
)
    otherlinks.AddItem(Link(mlist.GetBaseArchiveURL(), 'Go to list archiv=
es'))
    otherlinks.AddItem(Link('%s/logout' % adminurl,
                            # TBD: What I really want is a blank line :/
                            '<FONT SIZE=3D"+2"><b>Logout</b></FONT>'))

    categorylinks =3D UnorderedList()
    for k, v in CATEGORIES:
        if k =3D=3D category:
            categorylinks.AddItem("<em>%s</em>" % v)
        else:
            categorylinks.AddItem(Link("%s/%s" % (adminurl, k), v))

    linktable.AddRow([categorylinks, otherlinks])
    linktable.AddRowInfo(max(linktable.GetCurrentRowIndex(), 0),
                         valign=3D"top")

    doc.AddItem(linktable)
    doc.AddItem('<hr>')
    if category_suffix:
        encoding =3D None
        if category_suffix =3D=3D 'autoreply':
            # these have file uploads
            encoding =3D 'multipart/form-data'
        form =3D Form('%s/%s' % (adminurl, category_suffix), encoding=3De=
ncoding)
    else:
        form =3D Form(adminurl)
    doc.AddItem(form)

    if category =3D=3D 'general':
        andpassmsg =3D _("  (You can change your password there, too.)")
    else:
        andpassmsg =3D ""
    form.AddItem(_("Make your changes below, and then submit them"
                   " using the button at the bottom.%s<p>")
                 % andpassmsg)

    form.AddItem(FormatOptionsSection(category, mlist, cgi_data))

    if category =3D=3D 'general':
        form.AddItem(Center(FormatPasswordStuff()))

    form.AddItem("<p>")
    form.AddItem(Center(FormatSubmit()))
    form.AddItem(mlist.GetMailmanFooter())


=0C
def FormatOptionsSection(category, mlist, cgi_data):
    """Produce the category-specific options table."""
    if category =3D=3D 'members':
        # Special case for members section.
        return FormatMembershipOptions(mlist, cgi_data)

    options =3D GetConfigOptions(mlist, category)

    big_table =3D Table(cellspacing=3D3, cellpadding=3D4)

    # Get and portray the text label for the category.
    for k, v in CATEGORIES:
        if k =3D=3D category:
            label =3D v
    big_table.AddRow([Center(Header(2, label))])
    big_table.AddCellInfo(max(big_table.GetCurrentRowIndex(), 0), 0,
                          colspan=3D2, bgcolor=3D"#99ccff")

    def ColHeader(big_table =3D big_table):
        big_table.AddRow([Center(Bold(_('Description'))), Center(Bold(_('=
Value')))])
        big_table.AddCellInfo(max(big_table.GetCurrentRowIndex(), 0), 0,
                              width=3D"15%")
        big_table.AddCellInfo(max(big_table.GetCurrentRowIndex(), 0), 1,
                              width=3D"85%")
    did_col_header =3D 0

    for item in options:
        if type(item) =3D=3D types.StringType:
	    # The very first banner option (string in an options list) is
	    # treated as a general description, while any others are
	    # treated as section headers - centered and italicized...
	    if did_col_header:
		item =3D "<center><i>" + item + "</i></center>"
            big_table.AddRow([item])
	    big_table.AddCellInfo(max(big_table.GetCurrentRowIndex(), 0),
				  0, colspan=3D2)
            if not did_col_header:
                # Do col header after very first string descr, if any...
                ColHeader()
                did_col_header =3D 1
        else:
            if not did_col_header:
                # ... but do col header before anything else.
                ColHeader()
                did_col_header =3D 1
	    AddOptionsTableItem(big_table, item, category, mlist)
    big_table.AddRow(['<br>'])
    big_table.AddCellInfo(big_table.GetCurrentRowIndex(), 0, colspan=3D2)=

    return big_table


=0C
def AddOptionsTableItem(table, item, category, mlist, detailsp=3D1):
    """Add a row to an options table with the item description and value.=
"""
    try:
	got =3D GetItemCharacteristics(item)
	varname, kind, params, dependancies, descr, elaboration =3D got
    except ValueError, msg:
        syslog('error', 'admin: %s' % msg)
        return Italic(_("<malformed option>"))
    descr =3D GetItemGuiDescr(mlist, category, varname, descr, detailsp)
    val =3D GetItemGuiValue(mlist, kind, varname, params)
    table.AddRow([descr, val])
    table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 1,
		      bgcolor=3D"#cccccc")
    table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 0,
		      bgcolor=3D"#cccccc")


=0C
def FormatOptionHelp(doc, varref, mlist):
    item =3D None
    reflist =3D string.split(varref, '/')
    if len(reflist) =3D=3D 2:
        category, varname =3D reflist
        options =3D GetConfigOptions(mlist, category)
        for i in options:
            if i and i[0] =3D=3D varname:
                item =3D i
                break
    if not item:
        bad =3D _('Option %s/%s not found: %s') % (
            category, varname, os.environ.get('PATH_INFO'))
        AddErrorMessage(doc, bad)
        return
    got =3D GetItemCharacteristics(item)
    try:
        varname, kind, params, dependancies, descr, elaboration =3D got
        if elaboration is None:
            elaboration =3D ''
    except ValueError, msg:
        varname, kind, params, dependancies, descr =3D got
        elaboration =3D descr
    header =3D Table(width=3D"100%")
    legend =3D (_('%s Mailing list Configuration Help<br><em>%s</em> Opti=
on')
	      % (mlist.real_name, varname))
    header.AddRow([Center(Header(3, legend))])
    header.AddCellInfo(max(header.GetCurrentRowIndex(), 0), 0,
                       colspan=3D2, bgcolor=3D"#99ccff")
    doc.SetTitle(_("Mailman %s List Option Help") % varname)
    doc.AddItem(header)
    doc.AddItem("<b>%s</b> (%s): %s<p>" % (varname, category, descr))
    doc.AddItem("%s<p>" % elaboration)

    form =3D Form("%s/%s" % (mlist.GetScriptURL('admin'), category))
    valtab =3D Table(cellspacing=3D3, cellpadding=3D4)
    AddOptionsTableItem(valtab, item, category, mlist, detailsp=3D0)
    form.AddItem(valtab)
    form.AddItem('<p>')
    form.AddItem(Center(FormatSubmit()))
    doc.AddItem(Center(form))
    doc.AddItem(_("""<em><strong>Warning:</strong> changing this option h=
ere
    could cause other screens to be out-of-sync.  Be sure to reload any o=
ther
    pages that are displaying this option for this mailing list.  You can=

    also """))
    doc.AddItem(Link('%s/%s' % (mlist.GetScriptURL('admin'), category),
                     _('return to the %s options page.') % category ))
    doc.AddItem('</em>')
    doc.AddItem(mlist.GetMailmanFooter())


=0C
def GetItemCharacteristics(table_entry):
    """Break out the components of an item description from its table ent=
ry:
      0 option-var name
      1 type
      2 entry size
      3 ?dependancies?
      4 Brief description
      5 Optional description elaboration"""    =

    if len(table_entry) =3D=3D 5:
        elaboration =3D None
        varname, kind, params, dependancies, descr =3D table_entry
    elif len(table_entry) =3D=3D 6:
        varname, kind, params, dependancies, descr, elaboration =3D table=
_entry
    else:
	raise ValueError, (_("Badly formed options entry:\n  %s")
			   % table_entry)
    return (varname, kind, params, dependancies, descr, elaboration)


=0C
def GetItemGuiValue(mlist, kind, varname, params):
    """Return a representation of an item's settings."""
    if kind =3D=3D mm_cfg.Radio or kind =3D=3D mm_cfg.Toggle:
        #
        # if we are sending returning the option for subscribe
        # policy and this site doesn't allow open subscribes,
        # then we have to alter the value of mlist.subscribe_policy
        # as passed to RadioButtonArray in order to compensate
        # for the fact that there is one fewer option. correspondingly,
        # we alter the value back in the change options function -scott
        #
        # TBD: this is an ugly ugly hack.
        if varname[0] =3D=3D '_':
            checked =3D 0
        else:
            checked =3D getattr(mlist, varname)
        if varname =3D=3D 'subscribe_policy' and not mm_cfg.ALLOW_OPEN_SU=
BSCRIBE:
            checked =3D checked - 1
        return RadioButtonArray(varname, params, checked)
    elif (kind =3D=3D mm_cfg.String or kind =3D=3D mm_cfg.Email or
	  kind =3D=3D mm_cfg.Host or kind =3D=3D mm_cfg.Number):
	return TextBox(varname, getattr(mlist, varname), params)
    elif kind =3D=3D mm_cfg.Text:
	if params:
	    r, c =3D params
	else:
	    r, c =3D None, None
	val =3D getattr(mlist, varname)
	if not val:
	    val =3D ''
	return TextArea(varname, val, r, c)
    elif kind =3D=3D mm_cfg.EmailList:
	if params:
	    r, c =3D params
	else:
	    r, c =3D None, None
	res =3D string.join(getattr(mlist, varname), '\n')
	return TextArea(varname, res, r, c, wrap=3D'off')
    elif kind =3D=3D mm_cfg.FileUpload:
        # like a text area, but also with uploading
        if params:
            r, c =3D params
        else:
            r, c =3D None, None
        val =3D getattr(mlist, varname)
        if not val:
            val =3D ''
        container =3D Container()
        container.AddItem(_('<em>Enter the text below, or...</em><br>'))
        container.AddItem(TextArea(varname, val, r, c))
        container.AddItem(_('<br><em>...specify a file to upload</em><br>=
'))
        container.AddItem(FileUpload(varname+'_upload', r, c))
        return container

=0C
def GetItemGuiDescr(mlist, category, varname, descr, detailsp):
    """Return the item's description, with link to details.

    Details are not included if this is a VARHELP page, because that /is/=
 the
    details page!
    """
    if detailsp:
        text =3D Container('<div ALIGN=3D"right">' + descr + ' ',
                     Link(mlist.GetScriptURL('admin')
                              + '/?VARHELP=3D' + category + '/' + varname=
,
                          '(Details)'),
                     '</div>').Format()
    else:
        text =3D '<div ALIGN=3D"right">' + descr + '</div>'
    if varname[0] =3D=3D '_':
        text =3D text + _('''<div ALIGN=3D"right"><br><em><strong>Note:</=
strong>
        setting this value performs an immediate action but does not modi=
fy
        permanent state.</em></div>''')
    return text


=0C
def FormatMembershipOptions(mlist, cgi_data):
    container =3D Container()
    header =3D Table(width=3D"100%")
    header.AddRow([Center(Header(2, _("Membership Management")))])
    header.AddCellInfo(max(header.GetCurrentRowIndex(), 0), 0,
                       colspan=3D2, bgcolor=3D"#99ccff")
    container.AddItem(header)
    user_table =3D Table(width=3D"90%", border=3D'2')
    user_table.AddRow([Center(Header(4, _("Membership List")))])
    user_table.AddCellInfo(user_table.GetCurrentRowIndex(),
                           user_table.GetCurrentCellIndex(),
                           bgcolor=3D"#cccccc", colspan=3D8)
    user_table.AddRow(
        [Center(Italic(_("(%s members total, max. %s at a time displayed)=
") %
                       (len(mlist.members)
                        + len(mlist.digest_members),
                        mlist.admin_member_chunksize)))])
    user_table.AddCellInfo(user_table.GetCurrentRowIndex(),
                           user_table.GetCurrentCellIndex(),
                           bgcolor=3D"#cccccc", colspan=3D8)

    user_table.AddRow(map(Center, [_('member address'), _('subscr'),
                                   _('hide'), _('nomail'), _('ack'), _('n=
ot metoo'),
                                   _('digest'), _('plain')]))
    rowindex =3D user_table.GetCurrentRowIndex()
    for i in range(8):
        user_table.AddCellInfo(rowindex, i, bgcolor=3D'#cccccc')
    all =3D mlist.GetMembers() + mlist.GetDigestMembers()
    if len(all) > mlist.admin_member_chunksize:
        chunks =3D Utils.chunkify(all, mlist.admin_member_chunksize)
        if not cgi_data.has_key("chunk"):
            chunk =3D 0
        else:
            chunk =3D string.atoi(cgi_data["chunk"].value)
        all =3D chunks[chunk]
        footer =3D (_("<p><em>To View other sections, "
                    "click on the appropriate range listed below</em>"))
        chunk_indices =3D range(len(chunks))
        chunk_indices.remove(chunk)
        buttons =3D []
        for ci in chunk_indices:
            start, end =3D chunks[ci][0], chunks[ci][-1]
	    url =3D mlist.GetScriptURL('admin')
            buttons.append("<a href=3D%s/members?chunk=3D%d>" + _("from %=
s to %s") + "</a>"
                           % (url, ci, start, end))
        buttons =3D apply(UnorderedList, tuple(buttons))
        footer =3D footer + buttons.Format() + "<p>"
    else:
        all.sort()
        footer =3D "<p>"
    for member in all:
        mtext =3D '<a href=3D"%s">%s</a>' % (
            mlist.GetOptionsURL(member, obscure=3D1),
            mlist.GetUserSubscribedAddress(member))
        cells =3D [mtext + "<input type=3Dhidden name=3Duser value=3D%s>"=
 % (member),
                 Center(CheckBox(member + "_subscribed", "on", 1).Format(=
))]
        for opt in ("hide", "nomail", "ack", "notmetoo"):
            if mlist.GetUserOption(member,MailCommandHandler.option_info[=
opt]):
                value =3D "on"
                checked =3D 1
            else:
                value =3D "off"
                checked =3D 0
            box =3D CheckBox("%s_%s" % (member, opt), value, checked)
            cells.append(Center(box.Format()))
        if mlist.members.has_key(member):
            cells.append(Center(CheckBox(member + "_digest",
                                         "off", 0).Format()))
        else:
            cells.append(Center(CheckBox(member + "_digest",
                                         "on", 1).Format()))
        if mlist.GetUserOption(member,MailCommandHandler.option_info['pla=
in']):
            value =3D 'on'
            checked =3D 1
        else:
            value =3D 'off'
            checked =3D 0
        cells.append(Center(CheckBox('%s_plain' % member, value, checked)=
))
        user_table.AddRow(cells)
    container.AddItem(Center(user_table))
    legend =3D UnorderedList()
    legend.AddItem(_('<b>subscr</b> -- Is the member subscribed?'))
    legend.AddItem(_("<b>hide</b> -- Is the member's address "
                     "concealed on the list of subscribers?"))
    legend.AddItem(_('<b>nomail</b> -- Is delivery to the member disabled=
?'))
    legend.AddItem(_('<b>ack</b> -- '
                     'Does the member get acknowledgements of their posts=
?'))
    legend.AddItem(_('<b>not metoo</b> -- '
                     'Does the member avoid copies of their own posts?'))=

    legend.AddItem(_('<b>digest</b> -- '
                     'Does the member get messages in digests? '
                     '(otherwise, individual messages)'))
    legend.AddItem(
        _('<b>plain</b> -- '
          'If getting digests, does the member get plain text digests? '
          '(otherwise, MIME)'))
    container.AddItem(legend.Format())
    container.AddItem(footer)
    t =3D Table(width=3D"90%")
    t.AddRow([Center(Header(4, _("Mass Subscribe Members")))])
    t.AddCellInfo(t.GetCurrentRowIndex(),
                  t.GetCurrentCellIndex(),
                  bgcolor=3D"#cccccc", colspan=3D8)
    if mlist.send_welcome_msg:
        nochecked =3D 0
        yeschecked =3D 1
    else:
        nochecked =3D 1
        yeschecked =3D 0
    t.AddRow([("<b>1.</b>" + _("Send Welcome message to this batch? ")
               + RadioButton("send_welcome_msg_to_this_batch", 0,
                             nochecked).Format()
               + _(" no ")
               + RadioButton("send_welcome_msg_to_this_batch", 1,
                             yeschecked).Format()
               + _(" yes "))])
    t.AddRow(["<b>2.</b>" + _("Enter one address per line:") + "<p>"])
    container.AddItem(Center(t))
    container.AddItem(Center(TextArea(name=3D'subscribees',
                                      rows=3D10,cols=3D60,wrap=3DNone)))
    return container


=0C
def FormatPasswordStuff():
    change_pw_table =3D Table(bgcolor=3D"#99cccc", border=3D0,
                            cellspacing=3D0, cellpadding=3D2,
                            valign=3D"top")
    change_pw_table.AddRow(
        [Bold(Center(_('To Change The Administrator Password')))])
    change_pw_table.AddCellInfo(0, 0, align=3D"left", colspan=3D2)
    old =3D Table(bgcolor=3D"#99cccc", border=3D1,
                cellspacing=3D0, cellpadding=3D2, valign=3D"top")
    old.AddRow(['<div ALIGN=3D"right">' + _(" Enter current password:") +=
 '</div>',
                PasswordBox('adminpw')])
    new =3D Table(bgcolor=3D"#99cccc", border=3D1,
                cellspacing=3D0, cellpadding=3D2, valign=3D"top")
    new.AddRow(['<div ALIGN=3D"right">' + _(" Enter new password:") + '</=
div>',
                PasswordBox('newpw')])
    new.AddRow(['<div ALIGN=3D"right">' + _("Confirm new password:") + '<=
/div>',
                PasswordBox('confirmpw')])
    change_pw_table.AddRow([old, new])
    change_pw_table.AddCellInfo(1, 0, align=3D"left", valign=3D"top")
    #change_pw_table.AddCellInfo(1, 1, align=3D"left", valign=3D"top")
    return change_pw_table


=0C
def FormatSubmit():
    submit =3D Table(bgcolor=3D"#99ccff",
                   border=3D0, cellspacing=3D0, cellpadding=3D2)
    submit.AddRow([Bold(SubmitButton('submit', _('Submit Your Changes')))=
])
    submit.AddCellInfo(submit.GetCurrentRowIndex(), 0, align=3D"middle")
    return submit


=0C
# XXX klm - looks like turn_on_moderation is orphaned.
#turn_on_moderation =3D 0

# Options processing
def GetValidValue(mlist, prop, my_type, val, dependant):
    if my_type =3D=3D mm_cfg.Radio or my_type =3D=3D mm_cfg.Toggle:
	if type(val) <> types.IntType:
            try:
                val =3D int(val)
            except ValueError:
		pass
		# Don't know what to do here...
	    return val
    elif my_type =3D=3D mm_cfg.String or my_type =3D=3D mm_cfg.Text:
	return val
    elif my_type =3D=3D mm_cfg.Email:
	try:
            Utils.ValidateEmail(val)
            return val
        except Errors.EmailAddressError:
            # TBD: should have a way of displaying the results of the
            # operation.
            pass
	# Revert to the old value.
	return getattr(mlist, prop)
    elif my_type =3D=3D mm_cfg.EmailList:
	def SafeValidAddr(addr):
	    try:
                Utils.ValidateEmail(addr)
                return 1
            except Errors.EmailAddressError:
                return 0

	val =3D filter(SafeValidAddr,
		     map(string.strip, string.split(val, '\n')))
##	if dependant and len(val):
##	    # Wait till we've set everything to turn it on,
##	    # as we don't want to clobber our special case.
##	    # XXX klm - looks like turn_on_moderation is orphaned?
##	    turn_on_moderation =3D 1
	return val
    elif my_type =3D=3D mm_cfg.Host:
	return val
##
##      This code is sendmail dependant, so we'll just live w/o =

##      the error checking for now.
##
## 	# Shouldn't have to read in the whole file.
## 	file =3D open('/etc/sendmail.cf', 'r')
## 	lines =3D string.split(file.read(), '\n')
## 	file.close()
## 	def ConfirmCWEntry(item):
## 	    return item[0:2] =3D=3D 'Cw'
## 	lines =3D filter(ConfirmCWEntry, lines)
## 	if not len(lines):
## 	    # Revert to the old value.
## 	    return getattr(list, prop)
## 	for line in lines:
## 	    if string.lower(string.strip(line[2:])) =3D=3D string.lower(val):=

## 		return val
## 	return getattr(list, prop)
    elif my_type =3D=3D mm_cfg.Number:
        num =3D -1
        try:
            num =3D int(val)
        except ValueError:
            # TBD: a float???
            try:
                num =3D float(val)
            except ValueError:
                pass
        if num < 0:
            return getattr(mlist, prop)
        return num
    else:
	# Should never get here...
	return val


=0C
def ChangeOptions(mlist, category, cgi_info, document):
    confirmed =3D 0
    if cgi_info.has_key('newpw'):
	if cgi_info.has_key('confirmpw'):
            if cgi_info.has_key('adminpw') and cgi_info['adminpw'].value:=

                try:
                    mlist.ConfirmAdminPassword(cgi_info['adminpw'].value)=

                    confirmed =3D 1
                except Errors.MMBadPasswordError:
                    AddErrorMessage(document,
                                    _('Incorrect administrator password')=
,
                                    tag=3D'Error: ')
            if confirmed:
                new =3D string.strip(cgi_info['newpw'].value)
                confirm =3D string.strip(cgi_info['confirmpw'].value)
                if new =3D=3D '' and confirm =3D=3D '':
                    AddErrorMessage(document,
                                    _('Empty admin passwords are not allo=
wed'),
                                    tag=3D'Error: ')
                elif new =3D=3D confirm:
                    mlist.password =3D crypt(new, Utils.GetRandomSeed())
                    # Re-authenticate (to set new cookie)
                    mlist.WebAuthenticate(password=3Dnew, cookie=3D'admin=
')
                else:
                    AddErrorMessage(document, _('Passwords did not match'=
),
                                    tag=3D'Error: ')
	else:
            AddErrorMessage(document,
                            _('You must type in your new password twice')=
,
                            tag=3D'Error: ')
    #
    # for some reason, the login page mangles important values for the li=
st
    # such as .real_name so we only process these changes if the category=

    # is not "members" and the request is not from the login page
    # -scott 19980515
    #
    if category !=3D 'members' and \
            not cgi_info.has_key("request_login") and \
            len(cgi_info.keys()) > 1:
        # then
        if cgi_info.has_key("subscribe_policy"):
            if not mm_cfg.ALLOW_OPEN_SUBSCRIBE:
                #
                # we have to add one to the value because the
                # page didn't present an open list as an option
                #
                page_setting =3D string.atoi(cgi_info["subscribe_policy"]=
=2Evalue)
                cgi_info["subscribe_policy"].value =3D str(page_setting +=
 1)
        opt_list =3D GetConfigOptions(mlist, category)
        for item in opt_list:
            if type(item) <> types.TupleType or len(item) < 5:
                continue
            property, kind, args, deps, desc =3D item[0:5]
            if cgi_info.has_key(property+'_upload') and \
                   cgi_info[property+'_upload'].value:
                val =3D cgi_info[property+'_upload'].value
            elif not cgi_info.has_key(property):
                continue
            else:
                val =3D cgi_info[property].value
            value =3D GetValidValue(mlist, property, kind, val, deps)
            #
            # This is an ugly, ugly hack
            if property[0] =3D=3D '_':
                # TBD: When turning on usenet->mail gating we want to
                # automatically catch up the newsgroup otherwise the mail=
ing
                # list will suddently get flooded.  There should be a muc=
h
                # better way to do this (or for the admin to specify they=
 want
                # this).
                if property =3D=3D '_mass_catchup' and value:
                    mlist.usenet_watermark =3D None
            elif getattr(mlist, property) <> value:
                # TBD: Ensure that mlist.real_name differs only in letter=

                # case.  Otherwise a security hole can potentially be ope=
ned
                # when using an external archiver.  This seems ad-hoc and=

                # could use a more general security policy.
                if property =3D=3D 'real_name' and \
                   string.lower(value) <> string.lower(mlist._internal_na=
me):
                    # then don't install this value.
                    document.AddItem(_("""<p><b>real_name</b> attribute n=
ot
                    changed!  It must differ from the list's name by case=

                    only.<p>"""))
                    continue
                setattr(mlist, property, value)
    #
    # mass subscription processing for members category
    #
    if cgi_info.has_key('subscribees'):
	name_text =3D cgi_info['subscribees'].value
        name_text =3D string.replace(name_text, '\r', '')
	names =3D filter(None, map(string.strip, string.split(name_text, '\n')))=

        send_welcome_msg =3D string.atoi(
            cgi_info["send_welcome_msg_to_this_batch"].value)
        digest =3D 0
        if not mlist.digestable:
            digest =3D 0
        if not mlist.nondigestable:
            digest =3D 1
        subscribe_errors =3D []
        subscribe_success =3D []
        result =3D mlist.ApprovedAddMembers(names, None,
                                        digest, send_welcome_msg)
        for name in result.keys():
            if result[name] is None:
                subscribe_success.append(name)
            else:
                # `name' was not subscribed, find out why.  On failures,
                # result[name] is set from sys.exc_info()[:2]
                e, v =3D result[name]
                if e is Errors.MMAlreadyAMember:
                    subscribe_errors.append((name, _('Already a member'))=
)
                elif e is Errors.MMBadEmailError:
                    if name =3D=3D '':
                        name =3D '&lt;blank line&gt;'
                    subscribe_errors.append(
                        (name, _("Bad/Invalid email address")))
                elif e is Errors.MMHostileAddress:
                    subscribe_errors.append(
                        (name, _("Hostile Address (illegal characters)"))=
)
        if subscribe_success:
            document.AddItem(Header(5, _("Successfully Subscribed:")))
            document.AddItem(apply(UnorderedList, tuple((subscribe_succes=
s))))
            document.AddItem("<p>")
            # ApprovedAddMembers will already have saved the list for us.=

        if subscribe_errors:
            document.AddItem(Header(5, _("Error Subscribing:")))
            items =3D map(lambda x: "%s -- %s" % (x[0], x[1]), subscribe_=
errors)
            document.AddItem(apply(UnorderedList, tuple((items))))
            document.AddItem("<p>")
    #
    # do the user options for members category
    #
    if cgi_info.has_key('user'):
        user =3D cgi_info["user"]
        if type(user) is type([]):
            users =3D []
            for ui in range(len(user)):
                users.append(user[ui].value)
        else:
            users =3D [user.value]
        errors =3D []
        for user in users:
            if not cgi_info.has_key('%s_subscribed' % (user)):
                try:
                    mlist.DeleteMember(user)
                except Errors.MMNoSuchUserError:
                    errors.append((user, _('Not subscribed')))
                continue
            value =3D cgi_info.has_key('%s_digest' % user)
            try:
                mlist.SetUserDigest(user, value, force=3D1)
            except (Errors.MMNotAMemberError,
                    Errors.MMAlreadyDigested,
                    Errors.MMAlreadyUndigested):
                pass
            for opt in ("hide", "nomail", "ack", "notmetoo", "plain"):
                opt_code =3D MailCommandHandler.option_info[opt]
                if cgi_info.has_key("%s_%s" % (user, opt)):
                    mlist.SetUserOption(user, opt_code, 1, save_list=3D0)=

                else:
                    mlist.SetUserOption(user, opt_code, 0, save_list=3D0)=

        if errors:
            document.AddItem(Header(5, _("Error Unsubscribing:")))
            items =3D map(lambda x: "%s -- %s" % (x[0], x[1]), errors)
            document.AddItem(apply(UnorderedList, tuple((items))))
            document.AddItem("<p>")


=0C
def AddErrorMessage(doc, errmsg, tag=3D'Warning: ', *args):
    doc.AddItem(Header(3, Bold(FontAttr(
        tag, color=3D"#ff0000", size=3D"+2")).Format() +
                       Italic(errmsg % args).Format()))


=0C
def GetConfigOptions(mlist, category):
    return mlist.GetConfigInfo()[category]

--------------BFB93F3D3F601EC069B326B6--