1 /*
2 * Copyright (c) 2005-2006 Creative Sphere Limited.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 *
10 * Creative Sphere - initial API and implementation
11 *
12 */
13 package org.abstracthorizon.mercury.maildir.uid;
14
15 import java.io.File;
16 import java.io.IOException;
17
18 import javax.mail.MessagingException;
19 import javax.mail.internet.MimeMessage;
20
21 import org.abstracthorizon.mercury.maildir.MaildirFolderData;
22 import org.abstracthorizon.mercury.maildir.MaildirMessage;
23
24
25 /**
26 * <p>UID Maildir message representation.</p>
27 * <p>Messages file name is defined in the following way:
28 * <ul>
29 * <li>time of creation in seconds</li>
30 * <li>"." (dot)</li>
31 * <li>"V" followed with last 9 bits of folder's hash code as an integer</li>
32 * <li>"U" message's uid</li>
33 * <li>"." (dot)</li>
34 * <li>host name</li>
35 * <li>optional ":", "." or value from stores info separator attibute
36 * followed by "2," followed by flags</li>
37 * </ul>
38 * Flags are defined on the way explained in {@link org.abstracthorizon.mercury.maildir.FlagUtilities}
39 * </p>
40 * <p>Note: If file supplied in one of the constructors doesn't match this file name pattern file is then
41 * renamed to match it. Also, if file name matches that pattern but folder's hash code is different
42 * (folder's hash code represents UID validity) file is again renamed to proper one.
43 * </p>
44 *
45 * @author Daniel Sendula
46 */
47 public class UIDMaildirMessage extends MaildirMessage implements UIDMessage {
48
49 /** Messages uid object */
50 private UID uid;
51
52 /**
53 * Creates new message based on another message. It will create new file for this message in supplied folder.
54 * @param folder folder this message belongs to
55 * @param message message
56 * @param msgnum message number
57 * @throws MessagingException
58 * @throws IOException
59 */
60 protected UIDMaildirMessage(MaildirFolderData folder, MimeMessage message, int msgnum) throws MessagingException, IOException {
61 super(folder, message, msgnum);
62 }
63
64 /**
65 * This constructor creates new message from supplied file. If supplied file doesn't
66 * match appropriate format than it is renamed.
67 * @param folder folder this message belongs to
68 * @param file file
69 * @param msgnum message number
70 * @throws MessagingException
71 */
72 public UIDMaildirMessage(MaildirFolderData folder, File file, int msgnum) throws MessagingException {
73 super(folder, file, msgnum, false);
74
75 String name = file.getName();
76
77 int i = name.indexOf('.');
78 if (i > 0) {
79 int j = name.indexOf('.', i+1);
80 if (name.charAt(i+1) == 'V') {
81 int k = name.indexOf('U', i+1);
82 if ((k > 0) && (k < j)) {
83 try {
84 int folderHash = Integer.parseInt(name.substring(i+2, k));
85 long uidx = Long.parseLong(name.substring(k+1, j));
86 if ((getFolder().hashCode() & 511) == folderHash) {
87 uid = new UID(uidx);
88 }
89 } catch (NumberFormatException ignore) {
90 }
91 }
92 }
93 }
94
95 if (uid == null) {
96 File oldFile = file;
97 String filename = file.getName();
98 String flags = null;
99
100 int j = filename.lastIndexOf(FLAGS_SEPERATOR);
101 if (j >= 0) {
102 flags = filename.substring(j+2);
103 }
104
105 this.file = new File(file.getParentFile(), createFileName(flags));
106 long oldDate = oldFile.lastModified();
107 if (!oldFile.renameTo(this.file)) {
108 throw new MessagingException("Cannot rename "+oldFile.getAbsolutePath()+" to "+this.file.getAbsolutePath());
109 } else {
110 this.file.setLastModified(oldDate);
111 }
112 }
113 initialise();
114 }
115
116 /**
117 * Creates file name using supplied flags.
118 * @param flags flags
119 * @return file name for this message
120 * @throws MessagingException
121 */
122 protected String createFileName(String flags) throws MessagingException {
123 String time = Long.toString(System.currentTimeMillis());
124
125 uid = ((UIDMaildirFolderData)folder).getNextUID();
126
127 String folderHash = Integer.toString(getFolder().hashCode() & 511);
128
129 baseName = time + ".V" + folderHash + 'U' + uid.getUID() + '.' + host;
130
131 if ((flags == null) || (flags.length() == 0)) {
132 return baseName;
133 } else {
134 return baseName + infoSeparator + FLAGS_SEPERATOR + flags;
135 }
136 }
137
138 /**
139 * Returns message's UID object.
140 * @return message's UID object.
141 */
142 public UID getUID() {
143 return uid;
144 }
145
146 /**
147 * This object compares two messages based on UID value.
148 * @param o message to be compared
149 * @return <code>true</code> if both messages have same UID. <code>False</code> is returned if
150 * UIDs are different or supplied object is not UID message
151 */
152 public boolean equals(Object o) {
153 if (o instanceof UIDMaildirMessage) {
154 long u1 = uid.getUID();
155 long u2 = ((UIDMaildirMessage)o).getUID().getUID();
156 if ((u1 == u2) && (getFolder().getFullName().equals(((UIDMaildirMessage)o).getFolder().getFullName()))) {
157 return true;
158 }
159 }
160 return false;
161 }
162
163 /**
164 * This method compares two messages' uids.
165 * @param o message to be compared with
166 * @return -1, 0, 1 depending if this message has less, equal or greater UID then supplied.
167 * If supplied object is not UID message then -1 is returned.
168 */
169 public int compareTo(MaildirMessage o) {
170 if (o instanceof UIDMaildirMessage) {
171 long u1 = uid.getUID();
172 long u2 = ((UIDMaildirMessage)o).getUID().getUID();
173 if (u1 == u2) {
174 return 0;
175 } else if (u1 < u2) {
176 return -1;
177 } else {
178 return 1;
179 }
180 }
181 return -1;
182 }
183 }