private void fetchAndRetainMessages() throws Exception { String[] uids = connection.getMessageUids(); Set<String> existingUids = PopMessage.getMatchingUids(dataSource, uids); int count = uids.length - existingUids.size(); LOG.info("Found %d new message(s) on remote server", count); if (count == 0) { return; // No new messages } IOExceptionHandler.getInstance().resetSyncCounter(mbox); boolean checkForSelfPopping = true; for (int msgno = uids.length; msgno > 0; --msgno) { String uid = uids[msgno - 1]; if (!existingUids.contains(uid)) { if (checkForSelfPopping) { // Only check new messages else could match one we previously synced. if (poppingSelf(uid)) { throw ServiceException.INVALID_REQUEST( "User attempted to import messages from his own mailbox", null); } checkForSelfPopping = false; // Only need to check one message } LOG.debug("Fetching message with uid %s", uid); IOExceptionHandler.getInstance().trackSyncItem(mbox, msgno); // Don't allow filtering to a mountpoint when retaining the // message. We don't have a local id, so we can't keep track // of it in the data_source_item table. try { fetchAndAddMessage(msgno, connection.getMessageSize(msgno), uid, false); } catch (Exception e) { if (IOExceptionHandler.getInstance().isRecoverable(mbox, msgno, "pop sync fail", e)) { // skip it; will be retried on every subsequent sync continue; } throw e; } } } IOExceptionHandler.getInstance().checkpointIOExceptionRate(mbox); }
private void fetchAndAddMessage(int msgno, int size, String uid, boolean allowFilterToMountpoint) throws ServiceException, IOException { ContentInputStream cis = null; MessageContent mc = null; checkIsEnabled(); try { cis = connection.getMessage(msgno); mc = MessageContent.read(cis, size); ParsedMessage pm = mc.getParsedMessage(null, indexAttachments); if (pm == null) { LOG.warn("Empty message body for UID %d. Must be ignored.", uid); return; } Message msg = null; // bug 47796: Set received date to sent date if available otherwise use current time try { Date sentDate = pm.getMimeMessage().getSentDate(); if (sentDate == null) { LOG.warn( "null sent date; probably due to parse error. Date header value: [%s]", pm.getMimeMessage().getHeader("Date", null)); } pm.setReceivedDate(sentDate != null ? sentDate.getTime() : System.currentTimeMillis()); } catch (MessagingException e) { LOG.warn( "unable to get sent date from parsed message due to exception, must use current time", e); pm.setReceivedDate(System.currentTimeMillis()); } DeliveryContext dc = mc.getDeliveryContext(); if (isOffline()) { msg = addMessage(null, pm, size, dataSource.getFolderId(), Flag.BITMASK_UNREAD, dc); } else { Integer localId = getFirstLocalId( RuleManager.applyRulesToIncomingMessage( null, mbox, pm, size, dataSource.getEmailAddress(), dc, dataSource.getFolderId(), true, allowFilterToMountpoint)); if (localId != null) { msg = mbox.getMessageById(null, localId); } } if (msg != null && uid != null) { PopMessage msgTracker = new PopMessage(dataSource, msg.getId(), uid); msgTracker.add(); } } catch (CommandFailedException e) { LOG.warn("Error fetching message number %d: %s", msgno, e.getMessage()); } finally { if (cis != null) { try { cis.close(); } catch (ParseException pe) { LOG.error( "ParseException while closing ContentInputStream. Assuming cis is effectively closed", pe); } } if (mc != null) { mc.cleanup(); } } }