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 java.io.File;
023    import java.io.PrintStream;
024    import java.util.Iterator;
025    
026    import javax.mail.Folder;
027    import javax.mail.MessagingException;
028    import javax.mail.Session;
029    import javax.mail.Store;
030    import javax.mail.URLName;
031    
032    import org.apache.geronimo.javamail.store.nntp.newsrc.NNTPNewsrc;
033    import org.apache.geronimo.javamail.store.nntp.newsrc.NNTPNewsrcFile;
034    import org.apache.geronimo.javamail.store.nntp.newsrc.NNTPNewsrcGroup;
035    import org.apache.geronimo.javamail.transport.nntp.NNTPConnection;
036    import org.apache.geronimo.javamail.util.ProtocolProperties; 
037    import org.apache.geronimo.mail.util.SessionUtil;
038    
039    /**
040     * NNTP implementation of javax.mail.Store POP protocol spec is implemented in
041     * org.apache.geronimo.javamail.store.pop3.NNTPConnection
042     * 
043     * @version $Rev: 673152 $ $Date: 2008-07-01 13:37:38 -0400 (Tue, 01 Jul 2008) $
044     */
045    public class NNTPStore extends Store {
046        protected static final String NNTP_NEWSRC = "newsrc";
047    
048        protected static final String protocol = "nntp";
049    
050        protected static final int DEFAULT_NNTP_PORT = 119;
051        protected static final int DEFAULT_NNTP_SSL_PORT = 563;
052    
053        // our accessor for protocol properties and the holder of 
054        // protocol-specific information 
055        protected ProtocolProperties props; 
056        // our active connection object (shared code with the NNTPStore).
057        protected NNTPConnection connection;
058    
059        // the root folder
060        protected NNTPRootFolder root;
061        // the newsrc file where we store subscriptions and seen message markers.
062        protected NNTPNewsrc newsrc;
063        
064        /**
065         * Construct an NNTPStore item. This will load the .newsrc file associated
066         * with the server.
067         * 
068         * @param session
069         *            The owning javamail Session.
070         * @param name
071         *            The Store urlName, which can contain server target
072         *            information.
073         */
074        public NNTPStore(Session session, URLName name) {
075            this(session, name, "nntp", DEFAULT_NNTP_PORT, false);
076        }
077    
078        /**
079         * Common constructor used by the POP3Store and POP3SSLStore classes
080         * to do common initialization of defaults.
081         *
082         * @param session
083         *            The host session instance.
084         * @param name
085         *            The URLName of the target.
086         * @param protocol
087         *            The protocol type ("nntp" or "nntps"). This helps us in
088         *            retrieving protocol-specific session properties.
089         * @param defaultPort
090         *            The default port used by this protocol. For pop3, this will
091         *            be 110. The default for pop3 with ssl is 995.
092         * @param sslConnection
093         *            Indicates whether an SSL connection should be used to initial
094         *            contact the server. This is different from the STARTTLS
095         *            support, which switches the connection to SSL after the
096         *            initial startup.
097         */
098        protected NNTPStore(Session session, URLName name, String protocol, int defaultPort, boolean sslConnection) {
099            super(session, name);
100            
101            // create the protocol property holder.  This gives an abstraction over the different 
102            // flavors of the protocol. 
103            props = new ProtocolProperties(session, protocol, sslConnection, defaultPort); 
104    
105            // the connection manages connection for the transport 
106            connection = new NNTPConnection(props); 
107        }
108    
109        /**
110         * @see javax.mail.Store#getDefaultFolder()
111         * 
112         * This returns a root folder object for all of the news groups.
113         */
114        public Folder getDefaultFolder() throws MessagingException {
115            checkConnectionStatus();
116            if (root == null) {
117                return new NNTPRootFolder(this, connection.getHost(), connection.getWelcomeString());
118            }
119            return root;
120        }
121    
122        /**
123         * @see javax.mail.Store#getFolder(java.lang.String)
124         */
125        public Folder getFolder(String name) throws MessagingException {
126            return getDefaultFolder().getFolder(name);
127        }
128    
129        /**
130         * 
131         * @see javax.mail.Store#getFolder(javax.mail.URLName)
132         */
133        public Folder getFolder(URLName url) throws MessagingException {
134            return getDefaultFolder().getFolder(url.getFile());
135        }
136    
137        
138        /**
139         * Do the protocol connection for an NNTP transport. This handles server
140         * authentication, if possible. Returns false if unable to connect to the
141         * server.
142         * 
143         * @param host
144         *            The target host name.
145         * @param port
146         *            The server port number.
147         * @param user
148         *            The authentication user (if any).
149         * @param password
150         *            The server password. Might not be sent directly if more
151         *            sophisticated authentication is used.
152         * 
153         * @return true if we were able to connect to the server properly, false for
154         *         any failures.
155         * @exception MessagingException
156         */
157        protected boolean protocolConnect(String host, int port, String username, String password)
158                throws MessagingException {
159            // the connection pool handles all of the details here. But don't proceed 
160            // without a connection 
161            if (!connection.protocolConnect(host, port, username, password)) {
162                return false; 
163            }
164    
165            // see if we have a newsrc file location specified
166            String newsrcFile = props.getProperty(NNTP_NEWSRC);
167    
168            File source = null;
169    
170            // not given as a property? Then look for a file in user.home
171            if (newsrcFile != null) {
172                source = new File(newsrcFile);
173            } else {
174                // ok, look for a file in the user.home directory. If possible,
175                // we'll try for a file
176                // with the hostname appended.
177                String home = SessionUtil.getProperty("user.home");
178    
179                // try for a host-specific file first. If not found, use (and
180                // potentially create) a generic
181                // .newsrc file.
182                newsrcFile = ".newsrc-" + host;
183                source = new File(home, newsrcFile);
184                if (!source.exists()) {
185                    source = new File(home, ".newsrc");
186                }
187            }
188    
189            // now create a newsrc read and load the file.
190            newsrc = new NNTPNewsrcFile(source);
191            newsrc.load();
192    
193            // we're going to return success here, but in truth, the server may end
194            // up asking for our bonafides at any time, and we'll be expected to authenticate then.
195            return true;
196        }
197        
198    
199        /**
200         * @see javax.mail.Service#close()
201         */
202        public void close() throws MessagingException {
203            // This is done to ensure proper event notification.
204            super.close();
205            // persist the newsrc file, if possible
206            if (newsrc != null) {
207                newsrc.close();
208                newsrc = null; 
209            }
210            connection.close();
211            connection = null;
212        }
213    
214        private void checkConnectionStatus() throws MessagingException {
215            if (!this.isConnected()) {
216                throw new MessagingException("Not connected ");
217            }
218        }
219    
220        /**
221         * Retrieve the server connection created by this store.
222         * 
223         * @return The active connection object.
224         */
225        NNTPConnection getConnection() {
226            return connection;
227        }
228    
229        /**
230         * Retrieve the Session object this Store is operating under.
231         * 
232         * @return The attached Session instance.
233         */
234        Session getSession() {
235            return session;
236        }
237    
238        /**
239         * Retrieve all of the groups we nave persistent store information about.
240         * 
241         * @return The set of groups contained in the newsrc file.
242         */
243        Iterator getNewsrcGroups() {
244            return newsrc.getGroups();
245        }
246    
247        /**
248         * Retrieve the newsrc group information for a named group. If the file does
249         * not currently include this group, an unsubscribed group will be added to
250         * the file.
251         * 
252         * @param name
253         *            The name of the target group.
254         * 
255         * @return The NNTPNewsrcGroup item corresponding to this name.
256         */
257        NNTPNewsrcGroup getNewsrcGroup(String name) {
258            return newsrc.getGroup(name);
259        }
260    }