You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

140 lines
5.8 KiB

  1. # -*- coding: utf-8 -*-
  2. # © 2015-2016 Matthieu Dietrich (Camptocamp SA)
  3. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
  4. import logging
  5. import datetime
  6. from openerp import api, fields, models
  7. from dateutil.relativedelta import relativedelta
  8. from openerp.addons.server_environment import serv_config
  9. _logger = logging.getLogger(__name__)
  10. class FetchmailServer(models.Model):
  11. """Incoming POP/IMAP mail server account"""
  12. _inherit = 'fetchmail.server'
  13. cleanup_days = fields.Integer(
  14. compute='_get_cleanup_conf',
  15. string='Expiration days',
  16. help="Number of days before marking an e-mail as read")
  17. cleanup_folder = fields.Char(
  18. compute='_get_cleanup_conf',
  19. string='Expiration folder',
  20. help="Folder where an e-mail marked as read will be moved.")
  21. purge_days = fields.Integer(
  22. compute='_get_cleanup_conf',
  23. string='Deletion days',
  24. help="Number of days before removing an e-mail")
  25. @api.multi
  26. def _get_cleanup_conf(self):
  27. """
  28. Return configuration
  29. """
  30. for fetchmail in self:
  31. global_section_name = 'incoming_mail'
  32. # default vals
  33. config_vals = {'cleanup_days': False,
  34. 'purge_days': False,
  35. 'cleanup_folder': False}
  36. if serv_config.has_section(global_section_name):
  37. config_vals.update(serv_config.items(global_section_name))
  38. custom_section_name = '.'.join((global_section_name,
  39. fetchmail.name))
  40. if serv_config.has_section(custom_section_name):
  41. config_vals.update(serv_config.items(custom_section_name))
  42. # convert string values to integer
  43. if config_vals['cleanup_days']:
  44. config_vals['cleanup_days'] = int(config_vals['cleanup_days'])
  45. if config_vals['purge_days']:
  46. config_vals['purge_days'] = int(config_vals['purge_days'])
  47. for field in ['cleanup_days', 'purge_days', 'cleanup_folder']:
  48. fetchmail[field] = config_vals[field]
  49. def _cleanup_fetchmail_server(self, server, imap_server):
  50. count, failed = 0, 0
  51. expiration_date = datetime.date.today()
  52. expiration_date -= relativedelta(days=server.cleanup_days)
  53. search_text = expiration_date.strftime('(UNSEEN BEFORE %d-%b-%Y)')
  54. imap_server.select()
  55. result, data = imap_server.search(None, search_text)
  56. for num in data[0].split():
  57. try:
  58. # Mark message as read
  59. imap_server.store(num, '+FLAGS', '\\Seen')
  60. if server.cleanup_folder:
  61. # To move a message, you have to COPY
  62. # then DELETE the message
  63. result = imap_server.copy(num, server.cleanup_folder)
  64. if result[0] == 'OK':
  65. imap_server.store(num, '+FLAGS', '\\Deleted')
  66. except Exception:
  67. _logger.exception('Failed to cleanup mail from %s server %s.',
  68. server.type, server.name)
  69. failed += 1
  70. count += 1
  71. _logger.info("Marked %d email(s) as read on %s server %s; "
  72. "%d succeeded, %d failed.", count, server.type,
  73. server.name, (count - failed), failed)
  74. def _purge_fetchmail_server(self, server, imap_server):
  75. # Purging e-mails older than the purge date, if available
  76. count, failed = 0, 0
  77. purge_date = datetime.date.today()
  78. purge_date -= relativedelta(days=server.purge_days)
  79. search_text = purge_date.strftime('(BEFORE %d-%b-%Y)')
  80. imap_server.select()
  81. result, data = imap_server.search(None, search_text)
  82. for num in data[0].split():
  83. try:
  84. # Delete message
  85. imap_server.store(num, '+FLAGS', '\\Deleted')
  86. except Exception:
  87. _logger.exception('Failed to remove mail from %s server %s.',
  88. server.type, server.name)
  89. failed += 1
  90. count += 1
  91. _logger.info("Removed %d email(s) on %s server %s; "
  92. "%d succeeded, %d failed.", count, server.type,
  93. server.name, (count - failed), failed)
  94. @api.multi
  95. def fetch_mail(self):
  96. """ Called before the fetch, in order to clean up
  97. right before retrieving emails. """
  98. context = self.env.context.copy()
  99. context['fetchmail_cron_running'] = True
  100. for server in self:
  101. _logger.info('start cleaning up emails on %s server %s',
  102. server.type, server.name)
  103. context.update({'fetchmail_server_id': server.id,
  104. 'server_type': server.type})
  105. imap_server = False
  106. if server.type == 'imap':
  107. try:
  108. imap_server = server.connect()
  109. if server.cleanup_days > 0:
  110. self._cleanup_fetchmail_server(server, imap_server)
  111. if server.purge_days > 0:
  112. self._purge_fetchmail_server(server, imap_server)
  113. # Do the final cleanup: delete all messages
  114. # flagged as deleted
  115. imap_server.expunge()
  116. except Exception:
  117. _logger.exception("General failure when trying to cleanup "
  118. "mail from %s server %s.",
  119. server.type, server.name)
  120. finally:
  121. if imap_server:
  122. imap_server.close()
  123. imap_server.logout()
  124. return super(FetchmailServer, self).fetch_mail()