|  | @@ -26,7 +26,8 @@ CONTENT_TYPE_TEXT_HTML = 'text/html'
 | 
	
		
			
			| 26 | 26 |  IMAP_SEEN_FLAG = SEEN
 | 
	
		
			
			| 27 | 27 |  IMAP_CHECKED_FLAG = FLAGGED
 | 
	
		
			
			| 28 | 28 |  MAIL_FETCHER_FILELOCK_TIMEOUT = 10
 | 
	
		
			
			| 29 |  | -
 | 
	
		
			
			|  | 29 | +MAIL_FETCHER_CONNECTION_TIMEOUT = 60*9
 | 
	
		
			
			|  | 30 | +IDLE_MODE = True
 | 
	
		
			
			| 30 | 31 |  
 | 
	
		
			
			| 31 | 32 |  class MessageContainer(object):
 | 
	
		
			
			| 32 | 33 |      def __init__(self, message: Message, uid: int) -> None:
 | 
	
	
		
			
			|  | @@ -196,16 +197,25 @@ class MailFetcher(object):
 | 
	
		
			
			| 196 | 197 |          while self._is_active:
 | 
	
		
			
			| 197 | 198 |              try:
 | 
	
		
			
			| 198 | 199 |                  imapc = IMAPClient(self.host, ssl=self.use_ssl)
 | 
	
		
			
			| 199 |  | -                logger.debug(self, 'sleep for {}'.format(self.delay))
 | 
	
		
			
			| 200 |  | -                time.sleep(self.delay)
 | 
	
		
			
			| 201 | 200 |                  imapc.login(self.user, self.password)
 | 
	
		
			
			| 202 |  | -                with self.lock.acquire(
 | 
	
		
			
			| 203 |  | -                        timeout=MAIL_FETCHER_FILELOCK_TIMEOUT
 | 
	
		
			
			| 204 |  | -                ):
 | 
	
		
			
			| 205 |  | -                    messages = self._fetch(imapc)
 | 
	
		
			
			| 206 |  | -                    cleaned_mails = [DecodedMail(m.message, m.uid)
 | 
	
		
			
			| 207 |  | -                                     for m in messages]
 | 
	
		
			
			| 208 |  | -                    self._notify_tracim(cleaned_mails, imapc)
 | 
	
		
			
			|  | 201 | +                # select mailbox
 | 
	
		
			
			|  | 202 | +                logger.debug(self, 'Select folder {}'.format(
 | 
	
		
			
			|  | 203 | +                    self.folder,
 | 
	
		
			
			|  | 204 | +                ))
 | 
	
		
			
			|  | 205 | +                deadline = time.time() + MAIL_FETCHER_CONNECTION_TIMEOUT
 | 
	
		
			
			|  | 206 | +                while time.time() < deadline:
 | 
	
		
			
			|  | 207 | +                    self._check_mail(imapc)
 | 
	
		
			
			|  | 208 | +
 | 
	
		
			
			|  | 209 | +                    if IDLE_MODE and imapc.has_capability('IDLE'):
 | 
	
		
			
			|  | 210 | +                        logger.debug(self, 'wail for event(IDLE)')
 | 
	
		
			
			|  | 211 | +                        imapc.idle()
 | 
	
		
			
			|  | 212 | +                        imapc.idle_check(
 | 
	
		
			
			|  | 213 | +                            timeout=MAIL_FETCHER_CONNECTION_TIMEOUT
 | 
	
		
			
			|  | 214 | +                        )
 | 
	
		
			
			|  | 215 | +                        imapc.idle_done()
 | 
	
		
			
			|  | 216 | +                    else:
 | 
	
		
			
			|  | 217 | +                        logger.debug(self, 'sleep for {}'.format(self.delay))
 | 
	
		
			
			|  | 218 | +                        time.sleep(self.delay)
 | 
	
		
			
			| 209 | 219 |              except filelock.Timeout as e:
 | 
	
		
			
			| 210 | 220 |                  log = 'Mail Fetcher Lock Timeout {}'
 | 
	
		
			
			| 211 | 221 |                  logger.warning(self, log.format(e.__str__()))
 | 
	
	
		
			
			|  | @@ -215,31 +225,36 @@ class MailFetcher(object):
 | 
	
		
			
			| 215 | 225 |              finally:
 | 
	
		
			
			| 216 | 226 |                  imapc.logout()
 | 
	
		
			
			| 217 | 227 |  
 | 
	
		
			
			|  | 228 | +    def _check_mail(self, imapc: IMAPClient) -> None:
 | 
	
		
			
			|  | 229 | +        with self.lock.acquire(
 | 
	
		
			
			|  | 230 | +                timeout=MAIL_FETCHER_FILELOCK_TIMEOUT
 | 
	
		
			
			|  | 231 | +        ):
 | 
	
		
			
			|  | 232 | +            messages = self._fetch(imapc)
 | 
	
		
			
			|  | 233 | +            cleaned_mails = [DecodedMail(m.message, m.uid)
 | 
	
		
			
			|  | 234 | +                             for m in messages]
 | 
	
		
			
			|  | 235 | +            self._notify_tracim(cleaned_mails, imapc)
 | 
	
		
			
			|  | 236 | +
 | 
	
		
			
			| 218 | 237 |      def stop(self) -> None:
 | 
	
		
			
			| 219 | 238 |          self._is_active = False
 | 
	
		
			
			| 220 | 239 |  
 | 
	
		
			
			| 221 |  | -    def _fetch(self, imapclient: IMAPClient) -> typing.List[MessageContainer]:
 | 
	
		
			
			|  | 240 | +    def _fetch(self, imapc: IMAPClient) -> typing.List[MessageContainer]:
 | 
	
		
			
			| 222 | 241 |          """
 | 
	
		
			
			| 223 | 242 |          Get news message from mailbox
 | 
	
		
			
			| 224 | 243 |          :return: list of new mails
 | 
	
		
			
			| 225 | 244 |          """
 | 
	
		
			
			| 226 | 245 |          messages = []
 | 
	
		
			
			| 227 |  | -        # select mailbox
 | 
	
		
			
			| 228 |  | -        logger.debug(self, 'Fetch messages from folder {}'.format(
 | 
	
		
			
			| 229 |  | -            self.folder,
 | 
	
		
			
			| 230 |  | -        ))
 | 
	
		
			
			| 231 | 246 |  
 | 
	
		
			
			| 232 |  | -        imapclient.select_folder(self.folder)
 | 
	
		
			
			|  | 247 | +        imapc.select_folder(self.folder)
 | 
	
		
			
			| 233 | 248 |          logger.debug(self, 'Fetch unseen messages')
 | 
	
		
			
			| 234 |  | -        uids = imapclient.search(['UNSEEN'])
 | 
	
		
			
			|  | 249 | +        uids = imapc.search(['UNSEEN'])
 | 
	
		
			
			| 235 | 250 |          logger.debug(self, 'Found {} unseen mails'.format(
 | 
	
		
			
			| 236 | 251 |              len(uids),
 | 
	
		
			
			| 237 | 252 |          ))
 | 
	
		
			
			| 238 |  | -        imapclient.add_flags(uids, IMAP_SEEN_FLAG)
 | 
	
		
			
			|  | 253 | +        imapc.add_flags(uids, IMAP_SEEN_FLAG)
 | 
	
		
			
			| 239 | 254 |          logger.debug(self, 'Temporary Flag {} mails as seen'.format(
 | 
	
		
			
			| 240 | 255 |              len(uids),
 | 
	
		
			
			| 241 | 256 |          ))
 | 
	
		
			
			| 242 |  | -        for msgid, data in imapclient.fetch(uids, ['BODY.PEEK[]']).items():
 | 
	
		
			
			|  | 257 | +        for msgid, data in imapc.fetch(uids, ['BODY.PEEK[]']).items():
 | 
	
		
			
			| 243 | 258 |              # INFO - G.M - 2017-12-08 - Fetch BODY.PEEK[]
 | 
	
		
			
			| 244 | 259 |              # Retrieve all mail(body and header) but don't set mail
 | 
	
		
			
			| 245 | 260 |              # as seen because of PEEK
 |