@@ -203,7 +203,7 @@ def dolist(listname):
203203 except TimeOutError:
204204 print(C_('WARNING: could not acquire lock for list: '
205205 '%(listname)s'), file=sys.stderr)
206- return 1
206+ return (1, None)
207207
208208 # Sanity check the invariant that every BYBOUNCE disabled member must have
209209 # bounce information. Some earlier betas broke this. BAW: we're
@@ -378,9 +378,26 @@ script.
378378 # Mailman 2.1
379379 #
380380 move_language_templates(mlist)
381+
382+ # Check for old password formats inline
383+ from Mailman.Utils import is_old_password_format
384+ needs_upgrade = False
385+ if mlist.password and is_old_password_format(mlist.password):
386+ needs_upgrade = True
387+ if mlist.mod_password and is_old_password_format(mlist.mod_password):
388+ needs_upgrade = True
389+ if mlist.post_password and is_old_password_format(mlist.post_password):
390+ needs_upgrade = True
391+
392+ upgrade_info = None
393+ if needs_upgrade:
394+ # Store list info for notification
395+ listaddr = mlist.GetListEmail()
396+ upgrade_info = (mlist, listaddr)
397+
381398 # Avoid eating filehandles with the list lockfiles
382399 mlist.Unlock()
383- return 0
400+ return (0, upgrade_info)
384401
385402
386403
@@ -722,8 +739,10 @@ def check_and_notify_password_upgrades(dry_run=False):
722739 needs_upgrade = True
723740
724741 if needs_upgrade:
725- # Store both the listname and mlist so we can display the correct name
726- lists_needing_upgrade.append((listname, mlist))
742+ # Store the listname, mlist, and email address to ensure correct display
743+ # Extract email address now to avoid any variable scoping issues later
744+ listaddr = mlist.GetListEmail()
745+ lists_needing_upgrade.append((listname, mlist, listaddr))
727746
728747 # Check global passwords
729748 global_passwords_old = []
@@ -746,16 +765,20 @@ def check_and_notify_password_upgrades(dry_run=False):
746765 if dry_run:
747766 print(C_('DRY-RUN: Would send password upgrade notifications to %(count)d list(s).') % {
748767 'count': len(lists_needing_upgrade)})
749- for listname, mlist in lists_needing_upgrade:
750- # Use the list email address as the display name to ensure uniqueness
751- listaddr = mlist.GetListEmail()
752- # Extract listname part from email for display (everything before @)
753- display_name = listaddr.split('@')[0] if '@' in listaddr else listname
768+ for listname, mlist, listaddr in lists_needing_upgrade:
769+ # Extract the listname part from the email address (everything before @)
770+ # This ensures we display the correct list name that matches the email
771+ if '@' in listaddr:
772+ # Split on @ and take the first part (the listname)
773+ display_name = listaddr.split('@', 1)[0]
774+ else:
775+ # Fallback if email format is unexpected
776+ display_name = mlist.internal_name()
754777 print(C_(' - Would notify owners of %(listname)s (%(listaddr)s)') % {
755778 'listname': display_name,
756779 'listaddr': listaddr})
757780 else:
758- for listname, mlist in lists_needing_upgrade:
781+ for listname, mlist, listaddr in lists_needing_upgrade:
759782 send_password_upgrade_notification(mlist)
760783
761784 # Note about global passwords
@@ -869,9 +892,26 @@ If your archives are big, this could take a minute or two..."""))
869892 os.path.walk("%s/public_html/archives" % mm_cfg.PREFIX,
870893 archive_path_fixer, "")
871894 print('done')
895+ # Track lists needing password upgrade
896+ lists_needing_upgrade = []
897+ seen_internal_names = set() # Track by internal name to avoid duplicates
898+
872899 for listname in listnames:
873900 print(C_('Updating mailing list: %(listname)s'))
874- errors = errors + dolist(listname)
901+ result = dolist(listname)
902+ if isinstance(result, tuple):
903+ list_errors, upgrade_info = result
904+ errors = errors + list_errors
905+ if upgrade_info:
906+ mlist, listaddr = upgrade_info
907+ # Deduplicate by internal name
908+ internal_name = mlist.internal_name()
909+ if internal_name not in seen_internal_names:
910+ seen_internal_names.add(internal_name)
911+ lists_needing_upgrade.append((listname, mlist, listaddr))
912+ else:
913+ # Backward compatibility: if dolist returns just an int
914+ errors = errors + result
875915 print
876916 print('Updating Usenet watermarks')
877917 wmfile = os.path.join(mm_cfg.DATA_DIR, 'gate_watermarks')
@@ -911,8 +951,54 @@ If your archives are big, this could take a minute or two..."""))
911951 # files from separate .msg (pickled Message objects) and .db (marshalled
912952 # dictionaries) to a shared .pck file containing two pickles.
913953 update_qfiles()
954+
914955 # Check for old password formats and notify list admins
915- check_and_notify_password_upgrades(dry_run=dry_run)
956+ # Check global passwords
957+ from Mailman.Utils import is_old_password_format
958+ global_passwords_old = []
959+ site_pw = Utils.get_global_password(siteadmin=True)
960+ if site_pw and is_old_password_format(site_pw):
961+ global_passwords_old.append(('site admin', True))
962+ creator_pw = Utils.get_global_password(siteadmin=False)
963+ if creator_pw and is_old_password_format(creator_pw):
964+ global_passwords_old.append(('list creator', False))
965+
966+ # Send notifications if needed
967+ if lists_needing_upgrade or global_passwords_old:
968+ print(C_('Found %(count)d lists with old password formats that need upgrading.') % {
969+ 'count': len(lists_needing_upgrade)})
970+ if global_passwords_old:
971+ print(C_('Also found %(count)d global password(s) with old format.') % {
972+ 'count': len(global_passwords_old)})
973+
974+ # Send emails to list owners (unless dry-run)
975+ if dry_run:
976+ print(C_('DRY-RUN: Would send password upgrade notifications to %(count)d list(s).') % {
977+ 'count': len(lists_needing_upgrade)})
978+ for listname, mlist, listaddr in lists_needing_upgrade:
979+ # Extract the listname part from the email address (everything before @)
980+ # This ensures we display the correct list name that matches the email
981+ if '@' in listaddr:
982+ # Split on @ and take the first part (the listname)
983+ display_name = listaddr.split('@', 1)[0]
984+ else:
985+ # Fallback if email format is unexpected
986+ display_name = mlist.internal_name()
987+ print(C_(' - Would notify owners of %(listname)s (%(listaddr)s)') % {
988+ 'listname': display_name,
989+ 'listaddr': listaddr})
990+ else:
991+ for listname, mlist, listaddr in lists_needing_upgrade:
992+ send_password_upgrade_notification(mlist)
993+
994+ # Note about global passwords
995+ if global_passwords_old:
996+ print(C_('Note: Global passwords will be automatically upgraded when used.'))
997+ for pw_type, siteadmin in global_passwords_old:
998+ print(C_(' - %(pw_type)s password needs upgrade (will upgrade on next use)') % {
999+ 'pw_type': pw_type})
1000+ else:
1001+ print('All passwords are already in the new format.')
9161002 # This warning was necessary for the upgrade from 1.0b9 to 1.0b10.
9171003 # There's no good way of figuring this out for releases prior to 2.0beta2
9181004 # :(
0 commit comments