001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019
020 package org.apache.geronimo.javamail.store.nntp;
021
022 import javax.mail.Flags;
023 import javax.mail.Folder;
024 import javax.mail.IllegalWriteException;
025 import javax.mail.Message;
026 import javax.mail.MessagingException;
027 import javax.mail.MethodNotSupportedException;
028 import javax.mail.Session;
029 import javax.mail.event.ConnectionEvent;
030
031 import org.apache.geronimo.javamail.transport.nntp.NNTPConnection;
032
033 /**
034 * The base NNTP implementation of the javax.mail.Folder This is a base class
035 * for both the Root NNTP server and each NNTP group folder.
036 *
037 * @see javax.mail.Folder
038 *
039 * @version $Rev: 437941 $
040 */
041 public class NNTPFolder extends Folder {
042
043 // our active connection.
044 protected NNTPConnection connection;
045
046 // our attached session
047 protected Session session;
048
049 // the name of this folder (either the name of the server for the root or
050 // the news group name).
051 protected String name;
052
053 // the "full" name of the folder. For the root folder, this is the name
054 // returned by the connection
055 // welcome string. Otherwise, this is the same as the name.
056 protected String fullName;
057
058 // the parent folder. For the root folder, this is null. For a group folder,
059 // this is the root.
060 protected Folder parent;
061
062 // the folder open state
063 protected boolean folderOpen = false;
064
065 // the folder message count. For the root folder, this is always 0.
066 protected int messageCount = 0;
067
068 // the persistent flags we save in the store (basically just the SEEN flag).
069 protected Flags permanentFlags;
070
071 /**
072 * Super class constructor the base NNTPFolder class.
073 *
074 * @param store
075 * The javamail store this folder is attached to.
076 */
077 protected NNTPFolder(NNTPStore store) {
078 super(store);
079 // get the active connection from the store...all commands are sent
080 // there
081 this.connection = store.getConnection();
082 this.session = store.getSession();
083
084 // set up our permanent flags bit.
085 permanentFlags = new Flags();
086 permanentFlags.add(Flags.Flag.SEEN);
087 }
088
089 /**
090 * Retrieve the folder name.
091 *
092 * @return The folder's name.
093 */
094 public String getName() {
095 return name;
096 }
097
098 /**
099 * Retrieve the folder's full name (including hierarchy information). NNTP
100 * folders are flat, so the full name is generally the same as the name.
101 *
102 * @return The full name value.
103 */
104 public String getFullName() {
105 return fullName;
106 }
107
108 /**
109 * Returns the parent folder for this folder. Returns null if this is the
110 * root folder.
111 */
112 public Folder getParent() throws MessagingException {
113 return parent;
114 }
115
116 /**
117 * Indicated whether the folder "exists" or not. Existance in this context
118 * indicates that the group still exists on the server.
119 *
120 * @return
121 * @exception MessagingException
122 */
123 public boolean exists() throws MessagingException {
124 // by default, return true. This is really only the case for the root.
125 // The group folder will
126 // need to override this.
127 return true;
128 }
129
130 /**
131 * List the subfolders. For group folders, this is a meaningless so we throw
132 * a MethodNotSupportedException.
133 *
134 * @param pattern
135 * The folder pattern string.
136 *
137 * @return Never returns.
138 * @exception MessagingException
139 */
140 public Folder[] list(String pattern) throws MessagingException {
141 throw new MethodNotSupportedException("NNTP group folders cannot contain sub folders");
142 }
143
144 /**
145 * Retrieve the list of subscribed folders that match the given pattern
146 * string.
147 *
148 * @param pattern
149 * The pattern string used for the matching
150 *
151 * @return An array of matching folders from the subscribed list.
152 */
153 public Folder[] listSubscribed(String pattern) throws MessagingException {
154 throw new MethodNotSupportedException("NNTP group folders cannot contain sub folders");
155 }
156
157 /**
158 * No sub folders, hence there is no notion of a seperator. We return a null
159 * character (consistent with what Sun returns for POP3 folders).
160 */
161 public char getSeparator() throws MessagingException {
162 return '\0';
163 }
164
165 /**
166 * Return whether this folder can hold just messages or also subfolders.
167 * Only the root folder can hold other folders, so it will need to override.
168 *
169 * @return Either Folder.HOLDS_MESSAGES or Folder.HOLDS_FOLDERS.
170 * @exception MessagingException
171 */
172 public int getType() throws MessagingException {
173 return HOLDS_MESSAGES;
174 }
175
176 /**
177 * Create a new folder. NNTP folders are read only, so this is a nop.
178 *
179 * @param type
180 * The type of folder.
181 *
182 * @return Not support, throws an exception.
183 * @exception MessagingException
184 */
185 public boolean create(int type) throws MessagingException {
186 throw new MethodNotSupportedException("Sub folders cannot be created in NNTP");
187 }
188
189 /**
190 * Check for new messages. We always return false for the root folder. The
191 * group folders will need to override.
192 *
193 * @return Always returns false.
194 * @exception MessagingException
195 */
196 public boolean hasNewMessages() throws MessagingException {
197 return false;
198 }
199
200 /**
201 * Get a named subfolder from this folder. This only has meaning from the
202 * root NNTP folder.
203 *
204 * @param name
205 * The requested name.
206 *
207 * @return If the folder exists, returns a Folder object representing the
208 * named folder.
209 * @exception MessagingException
210 */
211 public Folder getFolder(String name) throws MessagingException {
212 throw new MethodNotSupportedException("NNTP Group folders do not support sub folders");
213 }
214
215 /**
216 * Delete a folder. This is not supported for NNTP.
217 *
218 * @param recurse
219 * The recusion flag.
220 *
221 * @return Never returns.
222 * @exception MessagingException
223 */
224 public boolean delete(boolean recurse) throws MessagingException {
225 throw new MethodNotSupportedException("Deleting of NNTP folders is not supported");
226 }
227
228 /**
229 * Rename a folder. Not supported for NNTP folders.
230 *
231 * @param f
232 * The new folder specifying the rename location.
233 *
234 * @return
235 * @exception MessagingException
236 */
237 public boolean renameTo(Folder f) throws MessagingException {
238 throw new MethodNotSupportedException("Renaming of NNTP folders is not supported.");
239 }
240
241 /**
242 * @see javax.mail.Folder#open(int)
243 */
244 public void open(int mode) throws MessagingException {
245
246 // we don't support READ_WRITE mode, so don't allow opening in that
247 // mode.
248 if (mode == READ_WRITE) {
249 throw new IllegalWriteException("Newsgroup folders cannot be opened read/write");
250 }
251
252 // an only be performed on a closed folder
253 checkClosed();
254
255 this.mode = mode;
256
257 // perform folder type-specific open actions.
258 openFolder();
259
260 folderOpen = true;
261
262 notifyConnectionListeners(ConnectionEvent.OPENED);
263 }
264
265 /**
266 * Perform folder type-specific open actions. The default action is to do
267 * nothing.
268 *
269 * @exception MessagingException
270 */
271 protected void openFolder() throws MessagingException {
272 }
273
274 /**
275 * Peform folder type-specific close actions. The default action is to do
276 * nothing.
277 *
278 * @exception MessagingException
279 */
280 protected void closeFolder() throws MessagingException {
281 }
282
283 /**
284 * Close the folder. Cleans up resources, potentially expunges messages
285 * marked for deletion, and sends an event notification.
286 *
287 * @param expunge
288 * The expunge flag, which is ignored for NNTP folders.
289 *
290 * @exception MessagingException
291 */
292 public void close(boolean expunge) throws MessagingException {
293 // Can only be performed on an open folder
294 checkOpen();
295
296 // give the subclasses an opportunity to do some cleanup
297 closeFolder();
298
299 folderOpen = false;
300 notifyConnectionListeners(ConnectionEvent.CLOSED);
301 }
302
303 /**
304 * Tests the open status of the folder.
305 *
306 * @return true if the folder is open, false otherwise.
307 */
308 public boolean isOpen() {
309 return folderOpen;
310 }
311
312 /**
313 * Get the permanentFlags
314 *
315 * @return The set of permanent flags we support (only SEEN).
316 */
317 public Flags getPermanentFlags() {
318 // we need a copy of our master set.
319 return new Flags(permanentFlags);
320 }
321
322 /**
323 * Get the count of messages in this folder.
324 *
325 * @return The message count.
326 * @exception MessagingException
327 */
328 public int getMessageCount() throws MessagingException {
329 return messageCount;
330 }
331
332 /**
333 * Checks wether the message is in cache, if not will create a new message
334 * object and return it.
335 *
336 * @see javax.mail.Folder#getMessage(int)
337 */
338 public Message getMessage(int msgNum) throws MessagingException {
339 // for the base, we just throw an exception.
340 throw new MethodNotSupportedException("Root NNTP folder does not contain messages");
341 }
342
343 /**
344 * Append messages to a folder. NNTP folders are read only, so this is not
345 * supported.
346 *
347 * @param msgs
348 * The list of messages to append.
349 *
350 * @exception MessagingException
351 */
352 public void appendMessages(Message[] msgs) throws MessagingException {
353 throw new MethodNotSupportedException("Root NNTP folder does not contain messages");
354
355 }
356
357 /**
358 * Expunge messages marked for deletion and return a list of the Messages.
359 * Not supported for NNTP.
360 *
361 * @return Never returns.
362 * @exception MessagingException
363 */
364 public Message[] expunge() throws MessagingException {
365 throw new MethodNotSupportedException("Root NNTP folder does not contain messages");
366 }
367
368 /**
369 * Below is a list of convenience methods that avoid repeated checking for a
370 * value and throwing an exception
371 */
372
373 /** Ensure the folder is open */
374 protected void checkOpen() throws IllegalStateException {
375 if (!folderOpen) {
376 throw new IllegalStateException("Folder is not Open");
377 }
378 }
379
380 /** Ensure the folder is not open */
381 protected void checkClosed() throws IllegalStateException {
382 if (folderOpen) {
383 throw new IllegalStateException("Folder is Open");
384 }
385 }
386
387 /**
388 * @see javax.mail.Folder#notifyMessageChangedListeners(int,
389 * javax.mail.Message)
390 *
391 * this method is protected and cannot be used outside of Folder, therefore
392 * had to explicitly expose it via a method in NNTPFolder, so that
393 * NNTPMessage has access to it
394 *
395 * Bad design on the part of the Java Mail API.
396 */
397 public void notifyMessageChangedListeners(int type, Message m) {
398 super.notifyMessageChangedListeners(type, m);
399 }
400
401 /**
402 * Retrieve the subscribed status for a folder. This default implementation
403 * just returns false (which is true for the root folder).
404 *
405 * @return Always returns true.
406 */
407 public boolean isSubscribed() {
408 return false;
409 }
410
411 /**
412 * Set the subscribed status for a folder.
413 *
414 * @param flag
415 * The new subscribed status.
416 *
417 * @exception MessagingException
418 */
419 public void setSubscribed(boolean flag) throws MessagingException {
420 throw new MessagingException("Root NNTP folder cannot be subscribed to");
421 }
422
423 /**
424 * Test if a given article number is marked as SEEN.
425 *
426 * @param article
427 * The target article number.
428 *
429 * @return The articles current seen status.
430 */
431 public boolean isSeen(int article) {
432 return false;
433 }
434
435 /**
436 * Set the SEEN status for an article.
437 *
438 * @param article
439 * The target article.
440 * @param flag
441 * The new seen setting.
442 *
443 * @exception MessagingException
444 */
445 public void setSeen(int article, boolean flag) throws MessagingException {
446 throw new MessagingException("Root NNTP folder does not contain articles");
447 }
448
449 }