/src/mailman/runners/archive.py

https://gitlab.com/sunny94/mailman
Python | 105 lines | 60 code | 10 blank | 35 comment | 15 complexity | f013738bdfc03e9fdb96e0f28ddf816a MD5 | raw file
  1. # Copyright (C) 2000-2016 by the Free Software Foundation, Inc.
  2. #
  3. # This file is part of GNU Mailman.
  4. #
  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)
  8. # any later version.
  9. #
  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
  13. # more details.
  14. #
  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/>.
  17. """Archive runner."""
  18. import copy
  19. import logging
  20. from datetime import datetime
  21. from email.utils import mktime_tz, parsedate_tz
  22. from lazr.config import as_timedelta
  23. from mailman import public
  24. from mailman.config import config
  25. from mailman.core.runner import Runner
  26. from mailman.interfaces.archiver import ClobberDate
  27. from mailman.interfaces.mailinglist import IListArchiverSet
  28. from mailman.utilities.datetime import RFC822_DATE_FMT, now
  29. log = logging.getLogger('mailman.archiver')
  30. def _should_clobber(msg, msgdata, archiver):
  31. """Should the Date header in the original message get clobbered?"""
  32. # Calculate the Date header of the message as a datetime. What if there
  33. # are multiple Date headers, even in violation of the RFC? For now, take
  34. # the first one. If there are no Date headers, then definitely clobber.
  35. original_date = msg.get('date')
  36. if original_date is None:
  37. return True
  38. section = getattr(config.archiver, archiver, None)
  39. if section is None:
  40. log.error('No archiver config section found: {}'.format(archiver))
  41. return False
  42. try:
  43. clobber = ClobberDate[section.clobber_date]
  44. except ValueError:
  45. log.error('Invalid clobber_date for "{}": {}'.format(
  46. archiver, section.clobber_date))
  47. return False
  48. if clobber is ClobberDate.always:
  49. return True
  50. elif clobber is ClobberDate.never:
  51. return False
  52. # Maybe we'll clobber the date. Let's see if it's farther off from now
  53. # than the skew period.
  54. skew = as_timedelta(section.clobber_skew)
  55. try:
  56. time_tuple = parsedate_tz(original_date)
  57. except (ValueError, OverflowError):
  58. # The likely cause of this is that the year in the Date: field is
  59. # horribly incorrect, e.g. (from SF bug # 571634):
  60. #
  61. # Date: Tue, 18 Jun 0102 05:12:09 +0500
  62. #
  63. # Obviously clobber such dates.
  64. return True
  65. if time_tuple is None:
  66. # There was some other bogosity in the Date header.
  67. return True
  68. claimed_date = datetime.fromtimestamp(mktime_tz(time_tuple))
  69. return (abs(now() - claimed_date) > skew)
  70. @public
  71. class ArchiveRunner(Runner):
  72. """The archive runner."""
  73. def _dispose(self, mlist, msg, msgdata):
  74. received_time = msgdata.get('received_time', now(strip_tzinfo=False))
  75. archiver_set = IListArchiverSet(mlist)
  76. for archiver in archiver_set.archivers:
  77. # The archiver is disabled if either the list-specific or
  78. # site-wide archiver is disabled.
  79. if not archiver.is_enabled:
  80. continue
  81. msg_copy = copy.deepcopy(msg)
  82. if _should_clobber(msg, msgdata, archiver.name):
  83. original_date = msg_copy['date']
  84. del msg_copy['date']
  85. del msg_copy['x-original-date']
  86. msg_copy['Date'] = received_time.strftime(RFC822_DATE_FMT)
  87. if original_date:
  88. msg_copy['X-Original-Date'] = original_date
  89. # A problem in one archiver should not prevent other archivers
  90. # from running.
  91. try:
  92. archiver.system_archiver.archive_message(mlist, msg_copy)
  93. except Exception:
  94. log.exception('Exception in "{}" archiver'.format(
  95. archiver.name))