예제 #1
0
 private void connect() throws ServiceException {
   if (!connection.isClosed()) return;
   try {
     connection.connect();
     try {
       connection.login(dataSource.getDecryptedPassword());
     } catch (CommandFailedException e) {
       throw new LoginException(e.getError());
     }
   } catch (Exception e) {
     connection.close();
     throw ServiceException.FAILURE("Unable to connect to POP3 server: " + dataSource, e);
   }
 }
예제 #2
0
 @Override
 public synchronized void test() throws ServiceException {
   validateDataSource();
   try {
     connect();
     if (dataSource.leaveOnServer() && !hasUIDL()) {
       throw RemoteServiceException.POP3_UIDL_REQUIRED();
     }
     connection.quit();
   } catch (IOException e) {
     throw ServiceException.FAILURE("Unable to connect to POP3 server: " + dataSource, e);
   } finally {
     connection.close();
   }
 }
예제 #3
0
 private boolean hasUIDL() throws IOException {
   if (connection.hasCapability(Pop3Capabilities.UIDL)) {
     return true;
   }
   // Additional check for servers that don't support CAPA
   // (i.e. Hotmail) but do support UIDL.
   try {
     if (connection.getMessageCount() > 0) {
       // Only need to test UIDL on first message
       connection.getMessageUid(1);
     } else {
       connection.getMessageUids();
     }
   } catch (CommandFailedException e) {
     return false;
   }
   return true;
 }
예제 #4
0
  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);
  }
예제 #5
0
 @Override
 public synchronized void importData(List<Integer> folderIds, boolean fullSync)
     throws ServiceException {
   validateDataSource();
   connect();
   try {
     if (connection.getMessageCount() > 0) {
       if (dataSource.leaveOnServer()) {
         fetchAndRetainMessages();
       } else {
         fetchAndDeleteMessages();
       }
     }
     connection.quit();
   } catch (ServiceException e) {
     throw e;
   } catch (Exception e) {
     throw ServiceException.FAILURE("Synchronization of POP3 folder failed", e);
   } finally {
     connection.close();
   }
 }
예제 #6
0
  private void fetchAndDeleteMessages() throws Exception {
    Integer sizes[] = connection.getMessageSizes();

    LOG.info("Found %d new message(s) on remote server", sizes.length);
    IOExceptionHandler.getInstance().resetSyncCounter(mbox);
    for (int msgno = sizes.length; msgno > 0; --msgno) {
      LOG.debug("Fetching message number %d", msgno);
      IOExceptionHandler.getInstance().trackSyncItem(mbox, msgno);
      try {
        fetchAndAddMessage(msgno, sizes[msgno - 1], null, true);
      } catch (Exception e) {
        if (IOExceptionHandler.getInstance().isRecoverable(mbox, msgno, "pop sync fail", e)) {
          // don't delete msg; if we end up aborting we want it still to exist
          // skip it; will be retried on every subsequent sync
          continue;
        }
        throw e;
      }
      checkIsEnabled();
      connection.deleteMessage(msgno);
    }
    IOExceptionHandler.getInstance().checkpointIOExceptionRate(mbox);
  }
예제 #7
0
 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();
     }
   }
 }