Package net.suberic.pooka.cache

Source Code of net.suberic.pooka.cache.SimpleFileCache$LocalMimeMessage

package net.suberic.pooka.cache;
import javax.mail.internet.*;
import net.suberic.pooka.FolderInfo;
import net.suberic.pooka.MessageInfo;
import net.suberic.pooka.OperationCancelledException;
import java.util.HashMap;
import java.util.Vector;
import java.io.*;
import javax.mail.*;
import javax.mail.event.*;
import javax.activation.DataHandler;

/**
* A simple cache.
*
*/
public class SimpleFileCache implements MessageCache {

  // FIXME:  why isn't anything synchronized?

  public static int ADDED = 10;
  public static int REMOVED = 11;

  public static String DELIMETER = "_";
  public static String CONTENT_EXT = "msg";
  public static String HEADER_EXT = "hdr";
  public static String FLAG_EXT = "flag";

  protected long uidValidity;

  // the source FolderInfo.
  private CachingFolderInfo folderInfo;

  // the directory in which the cache is stored.
  private File cacheDir;

  // the UIDValidity
  private long newUidValidity;

  // the currently cached uid's
  private Vector cachedMessages;

  // the currently cached Flags.
  private HashMap cachedFlags;

  // the currently cached Headers.
  private HashMap cachedHeaders;

  // the place where we store changes to happen later...
  private ChangeCache changes = null;

  // the last local UID used.
  long lastLocalUID = -1;

  /**
   * Creates a new SimpleFileCache for the given FolderInfo, in the
   * directory provided.
   */
  public SimpleFileCache(CachingFolderInfo folder, String directoryName) throws IOException {
    folderInfo = folder;
    cacheDir = new File(directoryName);
    if ( ! cacheDir.exists() )
      cacheDir.mkdirs();
    else if (! cacheDir.isDirectory())
      throw new IOException("not a directory.");

    changes = new ChangeCache(cacheDir);

    loadCache();
  }

  /**
   * Returns the datahandler for the given message uid.
   */
  public DataHandler getDataHandler(long uid, long newUidValidity, boolean saveToCache) throws MessagingException {
    if (newUidValidity != uidValidity) {
      throw new StaleCacheException(uidValidity, newUidValidity);
    }

    DataHandler h = getHandlerFromCache(uid);
    if (h != null) {
      return h;
    } else {
      if (getFolderInfo().shouldBeConnected()) {
        MimeMessage m = getFolderInfo().getRealMessageById(uid);
        if (m != null) {
          h = m.getDataHandler();
          if (saveToCache)
            cacheMessage(m, uid, newUidValidity, MESSAGE);
          return h;
        } else
          throw new MessageRemovedException("No such message:  " + uid);
      } else {
        throw new NotCachedException("Message is not cached, and folder is not available.");
      }
    }
  }

  /**
   * Returns the datahandler for the given message uid.
   */
  public DataHandler getDataHandler(long uid, long newUidValidity) throws MessagingException {
    return getDataHandler(uid, newUidValidity, true);
  }

  /**
   * Returns a non-mutable Message representation of the given Message.
   */
  public MimeMessage getMessageRepresentation(long uid, long newUidValidity) throws MessagingException {
    return getMessageRepresentation(uid, newUidValidity, true);
  }

  /**
   * Returns a non-mutable Message representation of the given Message.
   */
  public MimeMessage getMessageRepresentation(long uid, long newUidValidity, boolean saveToCache) throws MessagingException {
    if (newUidValidity != uidValidity) {
      throw new StaleCacheException(uidValidity, newUidValidity);
    }

    DataHandler h = getHandlerFromCache(uid);

    File f = new File(cacheDir, uid + DELIMETER + CONTENT_EXT);
    if (f.exists()) {
      try {
        FileInputStream fis = new FileInputStream(f);
        MimeMessage mm = new MimeMessage(net.suberic.pooka.Pooka.getDefaultSession(), fis);
        return mm;
      } catch (Exception e) {
        return null;
      }
    } else {
      if (getFolderInfo().shouldBeConnected()) {
        MimeMessage m = getFolderInfo().getRealMessageById(uid);
        if (m != null) {
          if (saveToCache)
            cacheMessage(m, uid, newUidValidity, MESSAGE);

          return m;
        } else
          throw new MessageRemovedException("No such message:  " + uid);
      } else {
        throw new NotCachedException("Message is not cached, and folder is not available.");
      }
    }
  }


  /**
   * Adds the given Flags to the message with the given uid.
   *
   * This affects both the client cache as well as the message on the
   * server, if the server is available.
   */
  public void addFlag(long uid, long newUidValidity, Flags flag) throws MessagingException {
    if (newUidValidity != uidValidity) {
      throw new StaleCacheException(uidValidity, newUidValidity);
    }

    Flags f = getFlags(uid, newUidValidity);
    if (f != null) {
      f.add(flag);
    } else {
      f = flag;
    }

    if (getFolderInfo().shouldBeConnected()) {
      MimeMessage m = getFolderInfo().getRealMessageById(uid);
      if (m != null)
        m.setFlags(flag, true);

      saveFlags(uid, uidValidity, f);

    } else {
      writeToChangeLog(uid, flag, ADDED);

      saveFlags(uid, uidValidity, f);
      final long fUid = uid;
      getFolderInfo().getFolderThread().addToQueue(new net.suberic.util.thread.ActionWrapper(new javax.swing.AbstractAction() {
          public void actionPerformed(java.awt.event.ActionEvent actionEvent) {
            if (getFolderInfo() != null) {
              MessageInfo mInfo = getFolderInfo().getMessageInfoByUid(fUid);
              if (mInfo != null) {
                getFolderInfo().messageChanged(new MessageChangedEvent(SimpleFileCache.this, MessageChangedEvent.FLAGS_CHANGED, mInfo.getMessage()));
              }
            }
          }
        }, getFolderInfo().getFolderThread()), new java.awt.event.ActionEvent(SimpleFileCache.this, 1, "message-changed"));

    }

  }

  /**
   * Removes the given Flags from the message with the given uid.
   *
   * This affects both the client cache as well as the message on the
   * server, if the server is available.
   */
  public void removeFlag(long uid, long newUidValidity, Flags flag) throws MessagingException {
    if (newUidValidity != uidValidity) {
      throw new StaleCacheException(uidValidity, newUidValidity);
    }
    Flags f = getFlags(uid, newUidValidity);
    if (f != null) {
      f.remove(flag);

      if (getFolderInfo().shouldBeConnected()) {
        MimeMessage m = getFolderInfo().getRealMessageById(uid);
        if (m != null)
          m.setFlags(flag, false);
        saveFlags(uid, uidValidity, f);
      } else {
        saveFlags(uid, uidValidity, f);
        writeToChangeLog(uid, flag, REMOVED);
      }

    }
  }

  /**
   * Returns the InternetHeaders object for the given uid.
   */
  public InternetHeaders getHeaders(long uid, long newUidValidity, boolean saveToCache) throws MessagingException {
    if (newUidValidity != uidValidity) {
      throw new StaleCacheException(uidValidity, newUidValidity);
    }
    InternetHeaders h = getHeadersFromCache(uid);
    if (h != null) {
      return h;
    } else {
      if (getFolderInfo().shouldBeConnected()) {
        MimeMessage m = getFolderInfo().getRealMessageById(uid);
        if (m != null) {
          java.util.Enumeration headerLines = m.getAllHeaderLines();
          h = new InternetHeaders();
          while (headerLines.hasMoreElements()) {
            h.addHeaderLine((String) headerLines.nextElement());
          }
          if (saveToCache)
            cacheMessage(m, uid, newUidValidity, HEADERS);
          return h;
        } else
          throw new MessageRemovedException("No such message:  " + uid);
      } else {
        throw new NotCachedException("Message is not cached, and folder is not available.");
      }
    }
  }

  public InternetHeaders getHeaders(long uid, long uidValidity) throws MessagingException {
    return getHeaders(uid, uidValidity, true);
  }

  /**
   * Returns the Flags object for the given uid.
   */
  public Flags getFlags(long uid, long newUidValidity, boolean saveToCache) throws MessagingException {
    if (newUidValidity != uidValidity) {
      throw new StaleCacheException(uidValidity, newUidValidity);
    }
    Flags f = getFlagsFromCache(uid);

    if (f != null) {
      return f;
    } else {
      if (getFolderInfo().shouldBeConnected()) {
        MimeMessage m = getFolderInfo().getRealMessageById(uid);
        if (m != null) {
          f = m.getFlags();
          if (saveToCache)
            cacheMessage(m, uid, newUidValidity, FLAGS);
          return f;
        } else
          throw new MessageRemovedException("No such message:  " + uid);
      } else {
        throw new NotCachedException("Message is not cached, and folder is not available.");
      }
    }

  }

  /**
   * Returns the Flags object for the given uid.
   */
  public Flags getFlags(long uid, long uidValidity) throws MessagingException {
    return getFlags(uid, uidValidity, true);
  }

  /**
   * Adds a message to the cache.  Note that status is only used to
   * determine whether or not the entire message is cached, or just
   * the headers and flags.
   *
   * This does not affect the server, nor does it affect message
   * count on the client.
   */
  public boolean cacheMessage(MimeMessage m, long uid, long newUidValidity, int status) throws MessagingException {
    return cacheMessage(m, uid, newUidValidity, status, true);
  }

  /**
   * Adds a message to the cache.  Note that status is only used to
   * determine whether or not the entire message is cached, or just
   * the headers and flags.
   *
   * This does not affect the server, nor does it affect message
   * count on the client.
   */
  public boolean cacheMessage(MimeMessage m, long uid, long newUidValidity, int status, boolean writeMsgFile) throws MessagingException {
    if (newUidValidity != uidValidity) {
      throw new StaleCacheException(uidValidity, newUidValidity);
    }

    if (m == null)
      return false;

    try {
      if (status == CONTENT || status == MESSAGE) {
        // we have to reset the seen flag if it's not set, since getting
        // the message from the server sets the flag.

        Flags flags = m.getFlags();
        boolean resetSeen = (! flags.contains(Flags.Flag.SEEN));

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        m.writeTo(baos);

        if (resetSeen) {
          m.setFlag(Flags.Flag.SEEN, false);
        }

        File outFile = new File(cacheDir, uid + DELIMETER + CONTENT_EXT);
        if (outFile.exists())
          outFile.delete();

        FileOutputStream fos = new FileOutputStream(outFile);
        //m.writeTo(fos);
        fos.write(baos.toByteArray());

        fos.flush();
        fos.close();
      }

      if (status == MESSAGE || status == FLAGS || status == FLAGS_AND_HEADERS) {
        Flags flags = m.getFlags();
        saveFlags(uid, uidValidity, flags);
      }


      if (status == MESSAGE || status == HEADERS || status == FLAGS_AND_HEADERS) {

        StringWriter outString = new StringWriter();

        java.util.Enumeration headerLines = m.getAllHeaderLines();
        BufferedWriter bos = new BufferedWriter(outString);

        int foo = 0;
        while (headerLines.hasMoreElements()) {
          bos.write((String) headerLines.nextElement());
          bos.newLine();
        }

        bos.newLine();
        bos.flush();
        bos.close();

        File outFile = new File(cacheDir, uid + DELIMETER + HEADER_EXT);
        if (outFile.exists())
          outFile.delete();

        outFile.createNewFile();

        FileWriter fos = new FileWriter(outFile);
        bos = new BufferedWriter(fos);
        /*
          java.util.Enumeration enum = m.getAllHeaderLines();
          BufferedWriter bos = new BufferedWriter(fos);

          int foo = 0;
          while (enum.hasMoreElements()) {
          bos.write((String) enum.nextElement());
          bos.newLine();
          }
        */
        bos.write(outString.toString());
        bos.flush();
        bos.close();
        fos.close();
      }

      if (! cachedMessages.contains(new Long(uid))) {
        cachedMessages.add(new Long(uid));
        if (writeMsgFile)
          writeMsgFile();
      }
    } catch (IOException ioe) {
      throw new MessagingException(ioe.getMessage(), ioe);
    }

    return true;
  }

  /**
   * Removes a message from the cache only.  This has no effect on the
   * server.
   */
  public boolean invalidateCache(long uid, int status) {
    invalidateCache(new long[] { uid }, status);

    return true;
  }

  /**
   * Invalidates all of the messages in the uids array in the cache.
   */
  public boolean invalidateCache(long[] uids, int status) {
    for (int i = 0; i < uids.length; i++) {
      FilenameFilter filter = new CacheFilenameFilter(uids[i], status);
      File[] matchingFiles = cacheDir.listFiles(filter);
      for (int j = 0; j < matchingFiles.length; j++)
        matchingFiles[j].delete();

      Long l = new Long(uids[i]);
      if (status == MESSAGE || status == FLAGS_AND_HEADERS || status == FLAGS) {
        cachedFlags.remove(l);
      }
      if (status == MESSAGE || status == FLAGS_AND_HEADERS || status == HEADERS) {
        cachedHeaders.remove(l);
      }

      if (status == MESSAGE) {
        cachedMessages.remove(l);
        writeMsgFile();
      }
    }

    return true;
  }

  /**
   * Invalidates the entire cache.  Usually called when the uidValidity
   * is changed.
   */
  public void invalidateCache() {
    File[] matchingFiles = cacheDir.listFiles();
    if (matchingFiles != null)
      for (int j = 0; j < matchingFiles.length; j++) {
        if (matchingFiles[j].isFile())
          matchingFiles[j].delete();
      }

    cachedMessages = new Vector();
    cachedFlags = new HashMap();
    cachedHeaders = new HashMap();

    getChangeAdapter().invalidate();
  }


  /**
   * Adds the messages to the given folder.  Returns the uids for the
   * message.
   *
   * This method changes both the client cache as well as the server, if
   * the server is available.
   */
  public long[] appendMessages(MessageInfo[] msgs) throws MessagingException {
    if (getFolderInfo().shouldBeConnected()) {
      try {
        getFolderInfo().appendMessages(msgs);
      } catch (OperationCancelledException oce) {
        throw new MessagingException("Append cancelled.");
      }
    } else {
      LocalMimeMessage[] localMsgs = new LocalMimeMessage[msgs.length];
      for (int i = 0; i < localMsgs.length; i++) {
        Message m = msgs[i].getMessage();
        localMsgs[i] = new LocalMimeMessage((MimeMessage)m);
      }
      MessageCountEvent mce = new MessageCountEvent(getFolderInfo().getFolder(), MessageCountEvent.ADDED, false, localMsgs);
      getFolderInfo().messagesAdded(mce);
    }

    return new long[] {};
  }

  /**
   * Removes all messages marked as 'DELETED'  from the given folder.
   * Returns the uids of all the removed messages.
   *
   * Note that if any message fails to be removed, then the ones
   * that have succeeded should be returned in the long[].
   *
   * This method changes both the client cache as well as the server, if
   * the server is available.
   */
  public void expungeMessages() throws MessagingException {
    try {
      getChangeAdapter().expunge();
      Vector removedMessages = new Vector();
      for (int i = cachedMessages.size() -1; i >= 0; i--) {
        long uid = ((Long) cachedMessages.elementAt(i)).longValue();
        Flags f = getFlagsFromCache(uid);
        if (f.contains(Flags.Flag.DELETED)) {
          Message m = getFolderInfo().getMessageInfoByUid(uid).getMessage();
          ((CachingMimeMessage)m).setExpungedValue(true);
          removedMessages.add(m);
        }
      }

      if (removedMessages.size() > 0) {
        Message[] rmMsg = new Message[removedMessages.size()];
        for (int i = 0; i < removedMessages.size(); i++)
          rmMsg[i] = (Message) removedMessages.elementAt(i);

        MessageCountEvent mce = new MessageCountEvent(getFolderInfo().getFolder(), MessageCountEvent.REMOVED, true, rmMsg);
        getFolderInfo().messagesRemoved(mce);
      }
    } catch (IOException ioe) {
      throw new MessagingException(ioe.getMessage(), ioe);
    }
  }

  /**
   * This returns the uid's of the message which exist in updatedUids, but
   * not in the current list of messsages.
   */
  public long[] getAddedMessages(long[] uids, long newUidValidity) throws StaleCacheException {
    if (newUidValidity != uidValidity) {
      throw new StaleCacheException(uidValidity, newUidValidity);
    }
    long[] added = new long[uids.length];
    int addedCount = 0;

    for (int i = 0; i < uids.length; i++) {
      if (! cachedMessages.contains(new Long(uids[i]))) {
        added[addedCount++]=uids[i];
      }
    }

    long[] returnValue = new long[addedCount];
    if (addedCount > 0)
      System.arraycopy(added, 0, returnValue, 0, addedCount);

    return returnValue;
  }

  /**
   * This returns the uid's of the message which exist in the current
   * list of messages, but no longer exist in the updatedUids.
   */
  public long[] getRemovedMessages(long[] uids, long newUidValidity) throws StaleCacheException {
    if (newUidValidity != uidValidity) {
      throw new StaleCacheException(uidValidity, newUidValidity);
    }
    Vector remainders = new Vector(cachedMessages);

    for (int i = 0; i < uids.length; i++) {
      remainders.remove(new Long(uids[i]));
    }

    long[] returnValue = new long[remainders.size()];
    for (int i = 0; i < remainders.size(); i++)
      returnValue[i] = ((Long) remainders.elementAt(i)).longValue();

    return returnValue;
  }

  /**
   * This returns the message id's of all the currently cached messages.
   * Note that only the headers and flags of the message need to be
   * cached for a message to be considered in the cache.
   */
  public long[] getMessageUids() {
    long[] returnValue = new long[cachedMessages.size()];
    for (int i = 0; i < cachedMessages.size(); i++)
      returnValue[i] = ((Long) cachedMessages.elementAt(i)).longValue();

    return returnValue;
  }

  /**
   * Gets a DataHandler from the cache.  Returns null if no handler is
   * available in the cache.
   */
  protected DataHandler getHandlerFromCache(long uid) {
    File f = new File(cacheDir, uid + DELIMETER + CONTENT_EXT);
    if (f.exists()) {
      try {
        FileInputStream fis = new FileInputStream(f);
        MimeMessage mm = new MimeMessage(net.suberic.pooka.Pooka.getDefaultSession(), fis);
        javax.activation.DataSource source = new WrappedMimePartDataSource (mm, this, uid);
        DataHandler dh = new DataHandler(source);
        return dh;
      } catch (Exception e) {
        return null;
      }
      //return new DataHandler(new FileDataSource(f));
    } else
      return null;
  }

  /**
   * Gets the InternetHeaders from the cache.  Returns null if no headers are
   * available in the cache.
   */
  InternetHeaders getHeadersFromCache(long uid) throws MessagingException {
    InternetHeaders returnValue = (InternetHeaders) cachedHeaders.get(new Long(uid));
    if (returnValue != null) {
      return returnValue;
    } else {

      File f = new File(cacheDir, uid +DELIMETER + HEADER_EXT);
      if (f.exists())
        try {
          FileInputStream fis = new FileInputStream(f);
          returnValue = new InternetHeaders(fis);
          cachedHeaders.put(new Long(uid), returnValue);
          try {
            fis.close();
          } catch (java.io.IOException ioe) {
          }
          return returnValue;
        } catch (FileNotFoundException fnfe) {
          throw new MessagingException(fnfe.getMessage(), fnfe);
        }
      else
        return null;
    }
  }

  /**
   * Gets the Flags from the cache.  Returns null if no flagss are
   * available in the cache.
   */
  Flags getFlagsFromCache(long uid) {
    Flags returnValue = (Flags) cachedFlags.get(new Long(uid));
    if (returnValue != null) {
      return new Flags(returnValue);
    } else {
      File f = new File(cacheDir, uid + DELIMETER + FLAG_EXT);
      if (f.exists()) {
        try {
          Flags newFlags = new Flags();
          BufferedReader in = new BufferedReader(new FileReader(f));
          for (String currentLine = in.readLine(); currentLine != null; currentLine = in.readLine()) {

            if (currentLine.equalsIgnoreCase("Deleted"))
              newFlags.add(Flags.Flag.DELETED);
            else if (currentLine.equalsIgnoreCase("Answered"))
              newFlags.add(Flags.Flag.ANSWERED);
            else if (currentLine.equalsIgnoreCase("Draft"))
              newFlags.add(Flags.Flag.DRAFT);
            else if (currentLine.equalsIgnoreCase("Flagged"))
              newFlags.add(Flags.Flag.FLAGGED);
            else if (currentLine.equalsIgnoreCase("Recent"))
              newFlags.add(Flags.Flag.RECENT);
            else if (currentLine.equalsIgnoreCase("SEEN"))
              newFlags.add(Flags.Flag.SEEN);
            else
              newFlags.add(new Flags(currentLine));
          }

          cachedFlags.put(new Long(uid), newFlags);
          return newFlags;
        } catch (FileNotFoundException fnfe) {
          System.out.println("caught filenotfoundexception.");
          return null;
        } catch (IOException ioe) {
          System.out.println("caught ioexception.");
          return null;
        }
      }

      return null;
    }
  }

  /**
   * Saves the given flags to the cache.
   */
  protected void saveFlags(long uid, long newUidValidity, Flags f) throws MessagingException {
    Flags oldFlags = getFlagsFromCache(uid);
    if (oldFlags == null || ! oldFlags.equals(f)) {
      cachedFlags.put(new Long(uid), f);
      try {
        File outFile = new File(cacheDir, uid + DELIMETER + FLAG_EXT);
        if (outFile.exists())
          outFile.delete();

        FileWriter fw = new FileWriter(outFile);
        BufferedWriter bw = new BufferedWriter(fw);

        Flags.Flag[] systemFlags = f.getSystemFlags();
        for (int i = 0; i < systemFlags.length; i++) {
          if (systemFlags[i] == Flags.Flag.ANSWERED) {
            bw.write("Answered");
            bw.newLine();
          } else if (systemFlags[i] == Flags.Flag.DELETED) {
            bw.write("Deleted");
            bw.newLine();
          } else if (systemFlags[i] == Flags.Flag.DRAFT) {
            bw.write("Draft");
            bw.newLine();
          } else if (systemFlags[i] == Flags.Flag.FLAGGED) {
            bw.write("Flagged");
            bw.newLine();
          } else if (systemFlags[i] == Flags.Flag.RECENT) {
            // let's not cache the recent flag, eh?
          } else if (systemFlags[i] == Flags.Flag.SEEN) {
            bw.write("Seen");
            bw.newLine();
          }
        }

        String[] userFlags = f.getUserFlags();
        for (int i = 0; i < userFlags.length; i++) {
          bw.write(userFlags[i]);
          bw.newLine();
        }

        bw.flush();
        bw.close();
      } catch (IOException ioe) {
        throw new MessagingException (ioe.getMessage(), ioe);
      }
    }
  }

  protected void writeToChangeLog(long uid, Flags flags, int status) throws MessagingException {
    try {
      if (status == REMOVED)
        getChangeAdapter().setFlags(uid, flags, false);
      else
        getChangeAdapter().setFlags(uid, flags, true);
    } catch (IOException ioe) {
      throw new MessagingException (ioe.getMessage(), ioe);
    }
  }

  /**
   * Initializes the cache from the file system.
   */
  public void loadCache() {
    cachedMessages = new Vector();
    cachedFlags = new HashMap();
    cachedHeaders = new HashMap();

    File msgListFile = new File(cacheDir, "messageList");
    if (msgListFile.exists()) {
      try {
        BufferedReader in = new BufferedReader(new FileReader(msgListFile));
        for (String nextLine = in.readLine(); nextLine != null; nextLine = in.readLine()) {
          Long l = new Long(nextLine);
          cachedMessages.add(l);
          // this has the side effect of loading the cached flags
          // to the cachedFlags HashMap. -- i think we do that now when
          // we fetch?
          //getFlagsFromCache(l.longValue());
          //getHeadersFromCache(l.longValue());
        }
      } catch (Exception e) { }
    }

    File validityFile = new File(cacheDir, "validity");
    if (validityFile.exists()) {
      try {
        BufferedReader in = new BufferedReader(new FileReader(validityFile));
        uidValidity = Long.parseLong(in.readLine());
      } catch (Exception e) {
      }
    }

    File localMsgFile = new File(cacheDir, "lastLocal");
    if (localMsgFile.exists()) {
      try {
        BufferedReader in = new BufferedReader(new FileReader(localMsgFile));
        lastLocalUID = Long.parseLong(in.readLine());
      } catch (Exception e) {
      }
    }

  }

  public void writeMsgFile() {
    try {
      File msgListFile = new File(cacheDir, "messageList");
      if (! msgListFile.exists()) {
        msgListFile.createNewFile();
      }
      BufferedWriter out = new BufferedWriter(new FileWriter(msgListFile));
      for (int i = 0; i < cachedMessages.size(); i++) {
        out.write(((Long) cachedMessages.elementAt(i)).toString());
        out.newLine();
      }
      out.flush();
      out.close();
    } catch (Exception e) {
    }
  }

  /**
   * Writes any offline changes made back to the server.
   */
  public void writeChangesToServer(Folder f) throws MessagingException {
    try {
      getChangeAdapter().writeChanges((UIDFolder) f, getFolderInfo());
    } catch (IOException ioe) {
      throw new MessagingException(net.suberic.pooka.Pooka.getProperty("error.couldNotGetChanges", "Error:  could not get cached changes."), ioe);
    }
  }

  public CachingFolderInfo getFolderInfo() {
    return folderInfo;
  }

  /**
   * Returns the size of the given message, or -1 if the message is
   * not cached.
   */
  public int getSize(long uid) {
    File f = new File(cacheDir, uid + DELIMETER + CONTENT_EXT);
    if (! f.exists()) {
      return (int)f.length();
    } else
      return -1;

  }

  private class CacheID {
    long id;
    long lastAccessed;
    long size;

    CacheID(long newId, long newLastAccessed, long newSize) {
      id = newId;
      lastAccessed = newLastAccessed;
      size = newSize;
    }
  }

  private class CacheFilenameFilter implements FilenameFilter {
    long uid;
    int status;

    public CacheFilenameFilter(long newUid, int newStatus) {
      uid = newUid;
      status = newStatus;
    }

    public boolean accept(File dir, String name) {
      if (status == MESSAGE || status == CONTENT) {
        if (name.startsWith(uid + DELIMETER + CONTENT_EXT))
          return true;
      }

      if (status == FLAGS || status == FLAGS_AND_HEADERS || status == MESSAGE) {
        if (name.startsWith(uid + DELIMETER + FLAG_EXT))
          return true;
      }

      if (status == HEADERS || status == FLAGS_AND_HEADERS || status == MESSAGE) {
        if (name.startsWith(uid + DELIMETER + HEADER_EXT))
          return true;
      }

      return false;
    }
  }

  /**
   * This returns the number of messages in the cache.
   */
  public int getMessageCount() {
    return cachedMessages.size();
  }

  /**
   * This returns the number of unread messages in the cache.
   */
  public int getUnreadMessageCount() throws MessagingException {
    // sigh.
    int unreadCount = 0;
    for (int i = 0; i < cachedMessages.size(); i++) {
      Flags f = getFlags(((Long) cachedMessages.elementAt(i)).longValue(), uidValidity, false);
      if (! f.contains(Flags.Flag.SEEN)) {
        unreadCount++;
      }
    }

    return unreadCount;
  }

  /**
   * Returns whether a given uid exists fully in the cache or not.
   */
  public boolean isFullyCached(long uid) {
    DataHandler dh = getHandlerFromCache(uid);
    return (dh != null);
  }

  /**
   * Returns the status of the given uid.
   */
  public int getCacheStatus(long uid) throws MessagingException {
    if (isFullyCached(uid))
      return CONTENT;
    else {
      InternetHeaders ih = getHeadersFromCache(uid);
      Flags f = getFlagsFromCache(uid);
      if (ih != null && f != null)
        return FLAGS_AND_HEADERS;
      else if (ih != null)
        return HEADERS;
      else if (f != null)
        return FLAGS;
      else
        return NOT_CACHED;
    }

  }

  public long getUIDValidity() {
    return uidValidity;
  }

  public void setUIDValidity(long newValidity) {
    try {
      File f = new File(cacheDir, "validity");
      if (f.exists())
        f.delete();

      f.createNewFile();

      BufferedWriter out = new BufferedWriter(new FileWriter(f));
      out.write(Long.toString(newValidity));
      out.flush();
      out.close();
    } catch (Exception e) {
    }

    uidValidity = newValidity;
  }

  public ChangeCache getChangeAdapter() {
    return changes;
  }

  /**
   * Searches all of the cached messages and returns those which match
   * the given SearchTerm.
   */
  public MessageInfo[] search(javax.mail.search.SearchTerm term) throws
    javax.mail.MessagingException {
    Vector matches = new Vector();

    for (int i = 0; i < cachedMessages.size(); i++) {
      MessageInfo info = getFolderInfo().getMessageInfoByUid(((Long)cachedMessages.elementAt(i)).longValue());
      Message m = info.getMessage();
      if (term.match(m))
        matches.add(info);
    }

    MessageInfo[] returnValue = new MessageInfo[matches.size()];
    for (int i = 0; i < matches.size(); i++) {
      returnValue[i] = (MessageInfo) matches.elementAt(i);
    }

    return returnValue;
  }

  /**
   * A class representing a local, cache-only message.
   */
  public class LocalMimeMessage extends javax.mail.internet.MimeMessage {

    long uid;

    public LocalMimeMessage(MimeMessage m) throws MessagingException {
      super(m);
      uid = generateLocalUID();
    }

    public long getUID() {
      return uid;
    }
  }

  /**
   * Generates a local UID.
   */
  public synchronized long generateLocalUID() {
    lastLocalUID--;
    try {
      File f = new File(cacheDir, "lastLocal");
      if (f.exists())
        f.delete();

      f.createNewFile();

      BufferedWriter out = new BufferedWriter(new FileWriter(f));
      out.write(Long.toString(lastLocalUID));
      out.flush();
      out.close();
    } catch (Exception e) {
    }
    return lastLocalUID;
  }
}

TOP

Related Classes of net.suberic.pooka.cache.SimpleFileCache$LocalMimeMessage

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.