001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      https://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.net.nntp;
019
020import java.util.Calendar;
021import java.util.Objects;
022
023/**
024 * The NewGroupsOrNewsQuery class. This is used to issue NNTP NEWGROUPS and NEWNEWS queries, implemented by
025 * {@link org.apache.commons.net.nntp.NNTPClient#listNewNewsgroups listNewNewsGroups} and {@link org.apache.commons.net.nntp.NNTPClient#listNewNews listNewNews
026 * } respectively. It prevents you from having to format date, time, distribution, and newgroup arguments.
027 * <p>
028 * You might use the class as follows:
029 * </p>
030 *
031 * <pre>
032 * query = new NewsGroupsOrNewsQuery(new GregorianCalendar(97, 11, 15), false);
033 * query.addDistribution("comp");
034 * NewsgroupInfo[] newsgroups = client.listNewgroups(query);
035 * </pre>
036 *
037 * This will retrieve the list of newsgroups starting with the comp. distribution prefix created since midnight 11/15/97.
038 *
039 * @see NNTPClient
040 */
041
042public final class NewGroupsOrNewsQuery {
043    private final String date;
044    private final String time;
045    private StringBuffer distributions;
046    private StringBuffer newsgroups;
047    private final boolean isGMT;
048
049    /**
050     * Creates a new query using the given time as a reference point.
051     *
052     * @param date The date since which new groups or news have arrived.
053     * @param gmt  True if the date should be considered as GMT, false if not.
054     */
055    public NewGroupsOrNewsQuery(final Calendar date, final boolean gmt) {
056        int num;
057        String str;
058        final StringBuilder buffer;
059
060        this.distributions = null;
061        this.newsgroups = null;
062        this.isGMT = gmt;
063
064        buffer = new StringBuilder();
065
066        // Get year
067        num = date.get(Calendar.YEAR);
068        str = Integer.toString(num);
069        num = str.length();
070
071        if (num >= 2) {
072            buffer.append(str.substring(num - 2));
073        } else {
074            buffer.append("00");
075        }
076
077        // Get month
078        num = date.get(Calendar.MONTH) + 1;
079        str = Integer.toString(num);
080        num = str.length();
081
082        if (num == 1) {
083            buffer.append('0');
084            buffer.append(str);
085        } else if (num == 2) {
086            buffer.append(str);
087        } else {
088            buffer.append("01");
089        }
090
091        // Get day
092        num = date.get(Calendar.DAY_OF_MONTH);
093        str = Integer.toString(num);
094        num = str.length();
095
096        if (num == 1) {
097            buffer.append('0');
098            buffer.append(str);
099        } else if (num == 2) {
100            buffer.append(str);
101        } else {
102            buffer.append("01");
103        }
104
105        this.date = buffer.toString();
106
107        buffer.setLength(0);
108
109        // Get hour
110        num = date.get(Calendar.HOUR_OF_DAY);
111        str = Integer.toString(num);
112        num = str.length();
113
114        if (num == 1) {
115            buffer.append('0');
116            buffer.append(str);
117        } else if (num == 2) {
118            buffer.append(str);
119        } else {
120            buffer.append("00");
121        }
122
123        // Get minutes
124        num = date.get(Calendar.MINUTE);
125        str = Integer.toString(num);
126        num = str.length();
127
128        if (num == 1) {
129            buffer.append('0');
130            buffer.append(str);
131        } else if (num == 2) {
132            buffer.append(str);
133        } else {
134            buffer.append("00");
135        }
136
137        // Get seconds
138        num = date.get(Calendar.SECOND);
139        str = Integer.toString(num);
140        num = str.length();
141
142        if (num == 1) {
143            buffer.append('0');
144            buffer.append(str);
145        } else if (num == 2) {
146            buffer.append(str);
147        } else {
148            buffer.append("00");
149        }
150
151        this.time = buffer.toString();
152    }
153
154    /**
155     * Add a distribution group to the query. The distribution part of a newsgroup is the segment of the name preceding the first dot (e.g., comp, alt, rec).
156     * Only those newsgroups matching one of the distributions or, in the case of NEWNEWS, an article in a newsgroup matching one of the distributions, will be
157     * reported as a query result. Adding distributions is purely optional.
158     *
159     * @param distribution A distribution to add to the query.
160     */
161    public void addDistribution(final String distribution) {
162        if (distributions != null) {
163            distributions.append(',');
164        } else {
165            distributions = new StringBuffer();
166        }
167        distributions.append(distribution);
168    }
169
170    /**
171     * Add a newsgroup to the list of newsgroups being queried. Newsgroups added this way are only meaningful to the NEWNEWS command. Newsgroup names may
172     * include the {@code *} wildcard, as in {@code comp.lang.*} or {@code comp.lang.java.*}. Adding at least one newsgroup is mandatory for
173     * the NEWNEWS command.
174     *
175     * @param newsgroup The newsgroup to add to the list of groups to be checked for new news.
176     */
177    public void addNewsgroup(final String newsgroup) {
178        if (newsgroups != null) {
179            newsgroups.append(',');
180        } else {
181            newsgroups = new StringBuffer();
182        }
183        newsgroups.append(newsgroup);
184    }
185
186    /**
187     * Gets the NNTP query formatted date (year, month, day in the form YYMMDD).
188     *
189     * @return The NNTP query formatted date.
190     */
191    public String getDate() {
192        return date;
193    }
194
195    /**
196     * Gets the comma separated list of distributions. This may be null if there are no distributions.
197     *
198     * @return The list of distributions, which may be null if no distributions have been specified.
199     */
200    public String getDistributions() {
201        return Objects.toString(distributions, null);
202    }
203
204    /**
205     * Gets the comma separated list of newsgroups. This may be null if there are no newsgroups
206     *
207     * @return The list of newsgroups, which may be null if no newsgroups have been specified.
208     */
209    public String getNewsgroups() {
210        return Objects.toString(newsgroups, null);
211    }
212
213    /**
214     * Gets the NNTP query formatted time (hour, minutes, seconds in the form HHMMSS).
215     *
216     * @return The NNTP query formatted time.
217     */
218    public String getTime() {
219        return time;
220    }
221
222    /**
223     * Tests whether or not the query date should be treated as GMT.
224     *
225     * @return True if the query date is to be treated as GMT, false if not.
226     */
227    public boolean isGMT() {
228        return isGMT;
229    }
230
231    /**
232     * Add a newsgroup to the list of newsgroups being queried, but indicate that group should not be checked for new news. Newsgroups added this way are only
233     * meaningful to the NEWNEWS command. Newsgroup names may include the {@code *} wildcard, as in {@code comp.lang.*} or
234     * {@code comp.lang.java.*}.
235     * <p>
236     * The following would create a query that searched for new news in all comp.lang.java newsgroups except for comp.lang.java.advocacy.
237     * </p>
238     *
239     * <pre>
240     * query.addNewsgroup("comp.lang.java.*");
241     * query.omitNewsgroup("comp.lang.java.advocacy");
242     * </pre>
243     *
244     * @param newsgroup The newsgroup to add to the list of groups to be checked for new news, but which should be omitted from the search for new news.
245     */
246    public void omitNewsgroup(final String newsgroup) {
247        addNewsgroup("!" + newsgroup);
248    }
249}